diff --git a/make/conf/docs-modules.conf b/make/conf/docs-modules.conf index f0bce0ef0092..ad118ca9add6 100644 --- a/make/conf/docs-modules.conf +++ b/make/conf/docs-modules.conf @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ DOCS_MODULES= \ jdk.hotspot.agent \ jdk.httpserver \ jdk.jpackage \ + jdk.incubator.json \ jdk.incubator.vector \ jdk.jartool \ jdk.javadoc \ diff --git a/make/modules/java.base/lib/CoreLibraries.gmk b/make/modules/java.base/lib/CoreLibraries.gmk index db7dd2911ce1..3c4af53fa1a2 100644 --- a/make/modules/java.base/lib/CoreLibraries.gmk +++ b/make/modules/java.base/lib/CoreLibraries.gmk @@ -176,7 +176,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJLI, \ EXTRA_HEADER_DIRS := libjvm, \ OPTIMIZATION := HIGH, \ CFLAGS := $(LIBJLI_CFLAGS) $(LIBZ_CFLAGS), \ - DISABLED_WARNINGS_gcc := unused-function unused-variable, \ + DISABLED_WARNINGS_gcc := unused-function, \ DISABLED_WARNINGS_clang := deprecated-non-prototype format-nonliteral \ unused-function, \ DISABLED_WARNINGS_clang_java_md_macosx.m := unused-variable, \ diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index b31f7a0b2e84..89935680605e 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -2191,7 +2191,7 @@ void MachVEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const if (!_verified) { st->print_cr("\t load_class"); } else { - st->print_cr("\t unpack_inline_arg"); + st->print_cr("\t unpack_value_arg"); } } #endif @@ -2209,9 +2209,9 @@ void MachVEPNode::emit(C2_MacroAssembler *masm, PhaseRegAlloc* ra_) const int framesize = ra_->C->output()->frame_slots() << LogBytesPerInt; __ remove_frame(framesize, false); } - // Unpack inline type args passed as oop and then jump to + // Unpack value type args passed as oop and then jump to // the verified entry point (skipping the unverified entry). - int sp_inc = __ unpack_inline_args(ra_->C, _receiver_only); + int sp_inc = __ unpack_value_args(ra_->C, _receiver_only); // Emit code for verified entry and save increment for stack repair on return __ verified_entry(ra_->C, sp_inc); if (Compile::current()->output()->in_scratch_emit_size()) { @@ -3683,7 +3683,7 @@ encode %{ // Check that stack depth is unchanged: find majik cookie on stack __ call_Unimplemented(); } - if (tf()->returns_inline_type_as_fields() && !_method->is_method_handle_intrinsic() && _method->return_type()->is_loaded()) { + if (tf()->returns_value_type_as_fields() && !_method->is_method_handle_intrinsic() && _method->return_type()->is_loaded()) { // The last return value is not set by the callee but used to pass the null marker to compiled code. // Search for the corresponding projection, get the register and emit code that initializes it. uint con = (tf()->range_cc()->cnt() - 1); @@ -3704,9 +3704,9 @@ encode %{ } } if (return_value_is_used()) { - // An inline type is returned as fields in multiple registers. - // R0 either contains an oop if the inline type is buffered or a pointer - // to the corresponding InlineKlass with the lowest bit set to 1. Zero r0 + // A value type is returned as fields in multiple registers. + // R0 either contains an oop if the value type is buffered or a pointer + // to the corresponding ValueKlass with the lowest bit set to 1. Zero r0 // if the lowest bit is set to allow C2 to use the oop after null checking. // r0 &= (r0 & 1) - 1 __ andr(rscratch1, r0, 0x1); @@ -3856,15 +3856,9 @@ frame %{ // return address specifies a type (REG or STACK) and a number // representing the register number (i.e. - use a register name) or // stack slot. - // Ret Addr is on stack in slot 0 if no locks or verification or alignment. - // Otherwise, it is above the locks and verification slot and alignment word - // TODO this may well be correct but need to check why that - 2 is there - // ppc port uses 0 but we definitely need to allow for fixed_slots - // which folds in the space used for monitors - return_addr(STACK - 2 + - align_up((Compile::current()->in_preserve_stack_slots() + - Compile::current()->fixed_slots()), - stack_alignment_in_slots())); + // Ret Addr is on stack 2 slots below _old_SP, i.e. in slot 0 if no locks + // or verification or alignment. + return_addr(STACK OptoReg::reg2stack(_old_SP) - 2); // Location of compiled Java return values. Same as C for now. return_value diff --git a/src/hotspot/cpu/aarch64/aarch64_atomic.ad b/src/hotspot/cpu/aarch64/aarch64_atomic.ad index 13fbe7815183..378a1ea8f131 100644 --- a/src/hotspot/cpu/aarch64/aarch64_atomic.ad +++ b/src/hotspot/cpu/aarch64/aarch64_atomic.ad @@ -31,10 +31,16 @@ // can't check the type of memory ordering here, so we always emit a // STLXR. +// CompareAndSwapX, GetAndSetX, and GetAndAddX represent sequentially +// consistent operations. C2 emits a trailing MemBarAcquire for +// these nodes, so their AArch64 implementation always needs acquire semantics. +// Non-acquiring match rules would consequently be unreachable. + // This section is generated from aarch64_atomic_ad.m4 instruct compareAndExchangeB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + predicate(!needs_acquiring_load_exclusive(n)); match(Set res (CompareAndExchangeB mem (Binary oldval newval))); ins_cost(2*VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); @@ -50,6 +56,7 @@ instruct compareAndExchangeB(iRegINoSp res, indirect mem, iRegI oldval, iRegI ne %} instruct compareAndExchangeS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + predicate(!needs_acquiring_load_exclusive(n)); match(Set res (CompareAndExchangeS mem (Binary oldval newval))); ins_cost(2*VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); @@ -65,6 +72,7 @@ instruct compareAndExchangeS(iRegINoSp res, indirect mem, iRegI oldval, iRegI ne %} instruct compareAndExchangeI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + predicate(!needs_acquiring_load_exclusive(n)); match(Set res (CompareAndExchangeI mem (Binary oldval newval))); ins_cost(2*VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); @@ -79,6 +87,7 @@ instruct compareAndExchangeI(iRegINoSp res, indirect mem, iRegI oldval, iRegI ne %} instruct compareAndExchangeL(iRegLNoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ + predicate(!needs_acquiring_load_exclusive(n)); match(Set res (CompareAndExchangeL mem (Binary oldval newval))); ins_cost(2*VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); @@ -93,7 +102,7 @@ instruct compareAndExchangeL(iRegLNoSp res, indirect mem, iRegL oldval, iRegL ne %} instruct compareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); + predicate(!needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); match(Set res (CompareAndExchangeN mem (Binary oldval newval))); ins_cost(2*VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); @@ -108,7 +117,7 @@ instruct compareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN ne %} instruct compareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); + predicate(!needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0)); match(Set res (CompareAndExchangeP mem (Binary oldval newval))); ins_cost(2*VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); @@ -214,98 +223,6 @@ instruct compareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP ins_pipe(pipe_slow); %} -instruct compareAndSwapB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - match(Set res (CompareAndSwapB mem (Binary oldval newval))); - ins_cost(2*VOLATILE_REF_COST); - effect(KILL cr); - format %{ - "cmpxchgb $res = $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval" - "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::byte, memory_order_release); - __ csetw($res$$Register, Assembler::EQ); - %} - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - match(Set res (CompareAndSwapS mem (Binary oldval newval))); - ins_cost(2*VOLATILE_REF_COST); - effect(KILL cr); - format %{ - "cmpxchgs $res = $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval" - "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::halfword, memory_order_release); - __ csetw($res$$Register, Assembler::EQ); - %} - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ - match(Set res (CompareAndSwapI mem (Binary oldval newval))); - ins_cost(2*VOLATILE_REF_COST); - effect(KILL cr); - format %{ - "cmpxchgw $res = $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" - "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, memory_order_release); - __ csetw($res$$Register, Assembler::EQ); - %} - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ - match(Set res (CompareAndSwapL mem (Binary oldval newval))); - ins_cost(2*VOLATILE_REF_COST); - effect(KILL cr); - format %{ - "cmpxchg $res = $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval" - "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, memory_order_release); - __ csetw($res$$Register, Assembler::EQ); - %} - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); - match(Set res (CompareAndSwapN mem (Binary oldval newval))); - ins_cost(2*VOLATILE_REF_COST); - effect(KILL cr); - format %{ - "cmpxchgw $res = $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval" - "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, memory_order_release); - __ csetw($res$$Register, Assembler::EQ); - %} - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); - match(Set res (CompareAndSwapP mem (Binary oldval newval))); - ins_cost(2*VOLATILE_REF_COST); - effect(KILL cr); - format %{ - "cmpxchg $res = $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval" - "csetw $res, EQ\t# $res <-- (EQ ? 1 : 0)" - %} - ins_encode %{ - __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, memory_order_release); - __ csetw($res$$Register, Assembler::EQ); - %} - ins_pipe(pipe_slow); -%} - instruct compareAndSwapBAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set res (CompareAndSwapB mem (Binary oldval newval))); @@ -403,6 +320,7 @@ instruct compareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP new %} instruct weakCompareAndSwapB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + predicate(!needs_acquiring_load_exclusive(n)); match(Set res (WeakCompareAndSwapB mem (Binary oldval newval))); ins_cost(2*VOLATILE_REF_COST); effect(KILL cr); @@ -418,6 +336,7 @@ instruct weakCompareAndSwapB(iRegINoSp res, indirect mem, iRegI oldval, iRegI ne %} instruct weakCompareAndSwapS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + predicate(!needs_acquiring_load_exclusive(n)); match(Set res (WeakCompareAndSwapS mem (Binary oldval newval))); ins_cost(2*VOLATILE_REF_COST); effect(KILL cr); @@ -433,6 +352,7 @@ instruct weakCompareAndSwapS(iRegINoSp res, indirect mem, iRegI oldval, iRegI ne %} instruct weakCompareAndSwapI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{ + predicate(!needs_acquiring_load_exclusive(n)); match(Set res (WeakCompareAndSwapI mem (Binary oldval newval))); ins_cost(2*VOLATILE_REF_COST); effect(KILL cr); @@ -448,6 +368,7 @@ instruct weakCompareAndSwapI(iRegINoSp res, indirect mem, iRegI oldval, iRegI ne %} instruct weakCompareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{ + predicate(!needs_acquiring_load_exclusive(n)); match(Set res (WeakCompareAndSwapL mem (Binary oldval newval))); ins_cost(2*VOLATILE_REF_COST); effect(KILL cr); @@ -463,7 +384,7 @@ instruct weakCompareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL ne %} instruct weakCompareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); + predicate(!needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); ins_cost(2*VOLATILE_REF_COST); effect(KILL cr); @@ -479,7 +400,7 @@ instruct weakCompareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN ne %} instruct weakCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); + predicate(!needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0)); match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); ins_cost(2*VOLATILE_REF_COST); effect(KILL cr); @@ -590,48 +511,6 @@ instruct weakCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP ins_pipe(pipe_slow); %} -instruct getAndSetI(indirect mem, iRegI newval, iRegINoSp oldval) %{ - match(Set oldval (GetAndSetI mem newval)); - ins_cost(2*VOLATILE_REF_COST); - format %{ "atomic_xchgw $oldval, $newval, [$mem]" %} - ins_encode %{ - __ atomic_xchgw($oldval$$Register, $newval$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct getAndSetL(indirect mem, iRegL newval, iRegLNoSp oldval) %{ - match(Set oldval (GetAndSetL mem newval)); - ins_cost(2*VOLATILE_REF_COST); - format %{ "atomic_xchg $oldval, $newval, [$mem]" %} - ins_encode %{ - __ atomic_xchg($oldval$$Register, $newval$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct getAndSetN(indirect mem, iRegN newval, iRegNNoSp oldval) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); - match(Set oldval (GetAndSetN mem newval)); - ins_cost(2*VOLATILE_REF_COST); - format %{ "atomic_xchgw $oldval, $newval, [$mem]" %} - ins_encode %{ - __ atomic_xchgw($oldval$$Register, $newval$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - -instruct getAndSetP(indirect mem, iRegP newval, iRegPNoSp oldval) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); - match(Set oldval (GetAndSetP mem newval)); - ins_cost(2*VOLATILE_REF_COST); - format %{ "atomic_xchg $oldval, $newval, [$mem]" %} - ins_encode %{ - __ atomic_xchg($oldval$$Register, $newval$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - instruct getAndSetIAcq(indirect mem, iRegI newval, iRegINoSp oldval) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set oldval (GetAndSetI mem newval)); @@ -676,16 +555,6 @@ instruct getAndSetPAcq(indirect mem, iRegP newval, iRegPNoSp oldval) %{ ins_pipe(pipe_serial); %} -instruct getAndAddI(indirect mem, iRegINoSp newval, iRegIorL2I incr) %{ - match(Set newval (GetAndAddI mem incr)); - ins_cost(2*VOLATILE_REF_COST+1); - format %{ "get_and_addI $newval, [$mem], $incr" %} - ins_encode %{ - __ atomic_addw($newval$$Register, $incr$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - instruct getAndAddIAcq(indirect mem, iRegINoSp newval, iRegIorL2I incr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set newval (GetAndAddI mem incr)); @@ -697,17 +566,6 @@ instruct getAndAddIAcq(indirect mem, iRegINoSp newval, iRegIorL2I incr) %{ ins_pipe(pipe_serial); %} -instruct getAndAddINoRes(indirect mem, Universe dummy, iRegIorL2I incr) %{ - predicate(n->as_LoadStore()->result_not_used()); - match(Set dummy (GetAndAddI mem incr)); - ins_cost(2*VOLATILE_REF_COST); - format %{ "get_and_addI noreg, [$mem], $incr" %} - ins_encode %{ - __ atomic_addw(noreg, $incr$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - instruct getAndAddIAcqNoRes(indirect mem, Universe dummy, iRegIorL2I incr) %{ predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n)); match(Set dummy (GetAndAddI mem incr)); @@ -719,16 +577,6 @@ instruct getAndAddIAcqNoRes(indirect mem, Universe dummy, iRegIorL2I incr) %{ ins_pipe(pipe_serial); %} -instruct getAndAddIConst(indirect mem, iRegINoSp newval, immIAddSub incr) %{ - match(Set newval (GetAndAddI mem incr)); - ins_cost(2*VOLATILE_REF_COST+1); - format %{ "get_and_addI $newval, [$mem], $incr" %} - ins_encode %{ - __ atomic_addw($newval$$Register, $incr$$constant, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - instruct getAndAddIAcqConst(indirect mem, iRegINoSp newval, immIAddSub incr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set newval (GetAndAddI mem incr)); @@ -740,17 +588,6 @@ instruct getAndAddIAcqConst(indirect mem, iRegINoSp newval, immIAddSub incr) %{ ins_pipe(pipe_serial); %} -instruct getAndAddINoResConst(indirect mem, Universe dummy, immIAddSub incr) %{ - predicate(n->as_LoadStore()->result_not_used()); - match(Set dummy (GetAndAddI mem incr)); - ins_cost(2*VOLATILE_REF_COST); - format %{ "get_and_addI noreg, [$mem], $incr" %} - ins_encode %{ - __ atomic_addw(noreg, $incr$$constant, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - instruct getAndAddIAcqNoResConst(indirect mem, Universe dummy, immIAddSub incr) %{ predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n)); match(Set dummy (GetAndAddI mem incr)); @@ -762,16 +599,6 @@ instruct getAndAddIAcqNoResConst(indirect mem, Universe dummy, immIAddSub incr) ins_pipe(pipe_serial); %} -instruct getAndAddL(indirect mem, iRegLNoSp newval, iRegL incr) %{ - match(Set newval (GetAndAddL mem incr)); - ins_cost(2*VOLATILE_REF_COST+1); - format %{ "get_and_addL $newval, [$mem], $incr" %} - ins_encode %{ - __ atomic_add($newval$$Register, $incr$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - instruct getAndAddLAcq(indirect mem, iRegLNoSp newval, iRegL incr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set newval (GetAndAddL mem incr)); @@ -783,17 +610,6 @@ instruct getAndAddLAcq(indirect mem, iRegLNoSp newval, iRegL incr) %{ ins_pipe(pipe_serial); %} -instruct getAndAddLNoRes(indirect mem, Universe dummy, iRegL incr) %{ - predicate(n->as_LoadStore()->result_not_used()); - match(Set dummy (GetAndAddL mem incr)); - ins_cost(2*VOLATILE_REF_COST); - format %{ "get_and_addL noreg, [$mem], $incr" %} - ins_encode %{ - __ atomic_add(noreg, $incr$$Register, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - instruct getAndAddLAcqNoRes(indirect mem, Universe dummy, iRegL incr) %{ predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n)); match(Set dummy (GetAndAddL mem incr)); @@ -805,16 +621,6 @@ instruct getAndAddLAcqNoRes(indirect mem, Universe dummy, iRegL incr) %{ ins_pipe(pipe_serial); %} -instruct getAndAddLConst(indirect mem, iRegLNoSp newval, immLAddSub incr) %{ - match(Set newval (GetAndAddL mem incr)); - ins_cost(2*VOLATILE_REF_COST+1); - format %{ "get_and_addL $newval, [$mem], $incr" %} - ins_encode %{ - __ atomic_add($newval$$Register, $incr$$constant, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - instruct getAndAddLAcqConst(indirect mem, iRegLNoSp newval, immLAddSub incr) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set newval (GetAndAddL mem incr)); @@ -826,17 +632,6 @@ instruct getAndAddLAcqConst(indirect mem, iRegLNoSp newval, immLAddSub incr) %{ ins_pipe(pipe_serial); %} -instruct getAndAddLNoResConst(indirect mem, Universe dummy, immLAddSub incr) %{ - predicate(n->as_LoadStore()->result_not_used()); - match(Set dummy (GetAndAddL mem incr)); - ins_cost(2*VOLATILE_REF_COST); - format %{ "get_and_addL noreg, [$mem], $incr" %} - ins_encode %{ - __ atomic_add(noreg, $incr$$constant, as_Register($mem$$base)); - %} - ins_pipe(pipe_serial); -%} - instruct getAndAddLAcqNoResConst(indirect mem, Universe dummy, immLAddSub incr) %{ predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_exclusive(n)); match(Set dummy (GetAndAddL mem incr)); diff --git a/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 index d6b3abd1e6fa..82cbbd0c6f5d 100644 --- a/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 +++ b/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 @@ -31,6 +31,11 @@ // can't check the type of memory ordering here, so we always emit a // STLXR. +// CompareAndSwapX, GetAndSetX, and GetAndAddX represent sequentially +// consistent operations. C2 emits a trailing MemBarAcquire for +// these nodes, so their AArch64 implementation always needs acquire semantics. +// Non-acquiring match rules would consequently be unreachable. + // This section is generated from aarch64_atomic_ad.m4 dnl Return Arg1 with two spaces before it. We need this because m4 @@ -44,7 +49,8 @@ dnl define(`CAE_INSN1', ` instruct compareAndExchange$1$7(iReg$2NoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{ -ifelse($7,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));),`dnl') +ifelse($7,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));), + INDENT(predicate(!needs_acquiring_load_exclusive(n));)) match(Set res (CompareAndExchange$1 mem (Binary oldval newval))); ins_cost(`'ifelse($7,Acq,,2*)VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); @@ -63,10 +69,10 @@ define(`CAE_INSN2', instruct compareAndExchange$1$6(iReg$2NoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{ ifelse($1$6,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));), $1$6,NAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);), - $1,P,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), - $1,N,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), + $1,P,INDENT(predicate(!needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));), + $1,N,INDENT(predicate(!needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);), $6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));), - `dnl') + INDENT(predicate(!needs_acquiring_load_exclusive(n));)) match(Set res (CompareAndExchange$1 mem (Binary oldval newval))); ins_cost(`'ifelse($6,Acq,,2*)VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); @@ -101,7 +107,8 @@ dnl define(`CAS_INSN1', ` instruct ifelse($7,Weak,'weakCompare`,'compare`)AndSwap$1$6(iRegINoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{ -ifelse($6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));),`dnl') +ifelse($6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));), + INDENT(predicate(!needs_acquiring_load_exclusive(n));)) match(Set res ($7CompareAndSwap$1 mem (Binary oldval newval))); ins_cost(`'ifelse($6,Acq,,2*)VOLATILE_REF_COST); effect(KILL cr); @@ -121,10 +128,10 @@ define(`CAS_INSN2', instruct ifelse($7,Weak,'weakCompare`,'compare`)AndSwap$1$6(iRegINoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{ ifelse($1$6,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));), $1$6,NAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);), - $1,P,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), - $1,N,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), + $1,P,INDENT(predicate(!needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));), + $1,N,INDENT(predicate(!needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);), $6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));), - `dnl') + INDENT(predicate(!needs_acquiring_load_exclusive(n));)) match(Set res ($7CompareAndSwap$1 mem (Binary oldval newval))); ins_cost(`'ifelse($6,Acq,,2*)VOLATILE_REF_COST); effect(KILL cr); @@ -139,13 +146,6 @@ ifelse($1$6,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_Lo ins_pipe(pipe_slow); %}')dnl dnl -CAS_INSN1(B, I, byte, byte, b, , ) -CAS_INSN1(S, I, short, halfword, s, , ) -CAS_INSN2(I, I, int, word, w, , ) -CAS_INSN2(L, L, long, xword, , , ) -CAS_INSN2(N, N, narrow oop, word, w, , ) -CAS_INSN2(P, P, ptr, xword, , , ) -dnl CAS_INSN1(B, I, byte, byte, b, Acq, ) CAS_INSN1(S, I, short, halfword, s, Acq, ) CAS_INSN2(I, I, int, word, w, Acq, ) @@ -189,11 +189,6 @@ ifelse($1$3,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_Lo ins_pipe(pipe_serial); %}')dnl dnl -GAS_INSN1(I, w, ) -GAS_INSN1(L, , ) -GAS_INSN1(N, w, ) -GAS_INSN1(P, , ) -dnl GAS_INSN1(I, w, Acq) GAS_INSN1(L, , Acq) GAS_INSN1(N, w, Acq) @@ -220,21 +215,13 @@ ifelse($4$5,AcqNoRes,INDENT(predicate(n->as_LoadStore()->result_not_used() && ne %}')dnl dnl dnl -GAA_INSN1(I, IorL2I, w, , , ) GAA_INSN1(I, IorL2I, w, Acq, , ) -GAA_INSN1(I, IorL2I, w, , NoRes, ) GAA_INSN1(I, IorL2I, w, Acq, NoRes, ) -GAA_INSN1(I, I, w, , , Const) GAA_INSN1(I, I, w, Acq, , Const) -GAA_INSN1(I, I, w, , NoRes, Const) GAA_INSN1(I, I, w, Acq, NoRes, Const) dnl -GAA_INSN1(L, L, , , , ) GAA_INSN1(L, L, , Acq, , ) -GAA_INSN1(L, L, , , NoRes, ) GAA_INSN1(L, L, , Acq, NoRes, ) -GAA_INSN1(L, L, , , , Const) GAA_INSN1(L, L, , Acq, , Const) -GAA_INSN1(L, L, , , NoRes, Const) GAA_INSN1(L, L, , Acq, NoRes, Const) dnl diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index 0c7d4c272cde..2ae9f0d6e9fe 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -1023,12 +1023,15 @@ class Assembler : public AbstractAssembler { INSN(smc, 0b000, 0, 0b11); INSN(brk, 0b001, 0, 0b00); INSN(hlt, 0b010, 0, 0b00); - INSN(dcps1, 0b101, 0, 0b01); - INSN(dcps2, 0b101, 0, 0b10); - INSN(dcps3, 0b101, 0, 0b11); #undef INSN + // Reserved + void udf(uint16_t imm) { + starti; + f(0, 31, 16), f(imm, 15, 0); + } + // System void system(int op0, int op1, int CRn, int CRm, int op2, Register rt = dummy_reg) diff --git a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp index 25b0625d60ed..d6854a09ad0d 100644 --- a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp @@ -276,7 +276,7 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) { if (_throw_ie_stub != nullptr) { // When we come here, _obj_reg has already been checked to be non-null. __ ldr(rscratch1, Address(_obj_reg->as_register(), oopDesc::mark_offset_in_bytes())); - __ mov(rscratch2, markWord::inline_type_pattern); + __ mov(rscratch2, markWord::value_type_pattern); __ andr(rscratch1, rscratch1, rscratch2); __ cmp(rscratch1, rscratch2); diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index 9a35a01c4d2d..72cd9e5c4dfd 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -33,9 +33,9 @@ #include "c1/c1_Runtime1.hpp" #include "c1/c1_ValueStack.hpp" #include "ci/ciArrayKlass.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciInstance.hpp" #include "ci/ciObjArrayKlass.hpp" +#include "ci/ciValueKlass.hpp" #include "code/aotCodeCache.hpp" #include "code/compiledIC.hpp" #include "gc/shared/collectedHeap.hpp" @@ -458,11 +458,11 @@ int LIR_Assembler::emit_deopt_handler() { void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) { assert(result->is_illegal() || !result->is_single_cpu() || result->as_register() == r0, "word returns are in r0,"); - if (InlineTypeReturnedAsFields) { - // Check if we are returning a non-null inline type and load its fields into registers + if (ValueTypeReturnedAsFields) { + // Check if we are returning a non-null value type and load its fields into registers ciType* return_type = compilation()->method()->return_type(); - if (return_type->is_inlinetype()) { - ciInlineKlass* vk = return_type->as_inline_klass(); + if (return_type->is_value_klass()) { + ciValueKlass* vk = return_type->as_value_klass(); if (vk->can_be_returned_as_fields()) { address unpack_handler = vk->unpack_handler(); assert(unpack_handler != nullptr, "must be"); @@ -483,14 +483,14 @@ void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) { __ b(skip); __ bind(not_null); - // Check if we are returning a non-null inline type and load its fields into registers - __ test_oop_is_not_inline_type(r0, rscratch2, skip, /* can_be_null= */ false); + // Check if we are returning a non-null value type and load its fields into registers + __ test_oop_is_not_value_type(r0, rscratch2, skip, /* can_be_null= */ false); - // Load fields from a buffered value with an inline class specific handler + // Load fields from a buffered value with a value class specific handler __ load_klass(rscratch1 /*dst*/, r0 /*src*/, rscratch2 /*tmp*/); - __ ldr(rscratch1, Address(rscratch1, InlineKlass::adr_members_offset())); - __ ldr(rscratch1, Address(rscratch1, InlineKlass::unpack_handler_offset())); - // Unpack handler can be null if inline type is not scalarizable in returns + __ ldr(rscratch1, Address(rscratch1, ValueKlass::adr_members_offset())); + __ ldr(rscratch1, Address(rscratch1, ValueKlass::unpack_handler_offset())); + // Unpack handler can be null if value type is not scalarizable in returns __ cbz(rscratch1, skip); __ blr(rscratch1); @@ -513,8 +513,8 @@ void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) { __ ret(lr); } -int LIR_Assembler::store_inline_type_fields_to_buf(ciInlineKlass* vk) { - return (__ store_inline_type_fields_to_buf(vk, false)); +int LIR_Assembler::store_value_type_fields_to_buf(ciValueKlass* vk) { + return (__ store_value_type_fields_to_buf(vk, false)); } int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) { @@ -1371,10 +1371,14 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L assert_different_registers(obj, k_RInfo, klass_RInfo); + Register mdo = noreg; + if (should_profile) { + mdo = klass_RInfo; + __ mov_metadata(mdo, md->constant_encoding()); + } + if (op->need_null_check()) { if (should_profile) { - Register mdo = klass_RInfo; - __ mov_metadata(mdo, md->constant_encoding()); Label not_null; __ cbnz(obj, not_null); // Object is null; update MDO and exit @@ -1387,13 +1391,15 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L __ strb(rscratch1, data_addr); __ b(*obj_is_null); __ bind(not_null); + } else { + __ cbz(obj, *obj_is_null); + } + } + if (should_profile) { Register recv = k_RInfo; __ load_klass(recv, obj, rscratch1); type_profile_helper(mdo, md, data, recv); - } else { - __ cbz(obj, *obj_is_null); - } } if (!k->is_loaded()) { @@ -1593,25 +1599,25 @@ void LIR_Assembler::emit_opSubstitutabilityCheck(LIR_OpSubstitutabilityCheck* op ciKlass* left_klass = op->left_klass(); ciKlass* right_klass = op->right_klass(); - // (2) Inline type check -- if either of the operands is not an inline type, + // (2) Value type check -- if either of the operands is not a value type, // they are not substitutable. We do this only if we are not sure that the - // operands are inline type + // operands are value type if ((left_klass == nullptr || right_klass == nullptr) ||// The klass is still unloaded, or came from a Phi node. - !left_klass->is_inlinetype() || !right_klass->is_inlinetype()) { + !left_klass->is_value_klass() || !right_klass->is_value_klass()) { Register tmp1 = op->tmp1()->as_register(); Register tmp2 = op->tmp2()->as_register(); - __ mov(tmp1, markWord::inline_type_pattern); + __ mov(tmp1, markWord::value_type_pattern); __ ldr(tmp2, Address(left, oopDesc::mark_offset_in_bytes())); __ andr(tmp1, tmp1, tmp2); __ ldr(tmp2, Address(right, oopDesc::mark_offset_in_bytes())); __ andr(tmp1, tmp1, tmp2); - __ cmp(tmp1, (u1)markWord::inline_type_pattern); + __ cmp(tmp1, (u1)markWord::value_type_pattern); __ br(Assembler::NE, L_oops_not_equal); } // (3) Same klass check: if the operands are of different klasses, they are not substitutable. - if (left_klass != nullptr && left_klass->is_inlinetype() && left_klass == right_klass) { - // No need to load klass -- the operands are statically known to be the same inline klass. + if (left_klass != nullptr && left_klass->is_value_klass() && left_klass == right_klass) { + // No need to load klass -- the operands are statically known to be the same value klass. __ b(*op->stub()->entry()); } else { Register tmp1 = op->tmp1()->as_register(); @@ -2323,7 +2329,7 @@ void LIR_Assembler::store_parameter(jobject o, int offset_from_rsp_in_words) { __ str(rscratch1, Address(sp, offset_from_rsp_in_bytes)); } -void LIR_Assembler::arraycopy_inlinetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check) { +void LIR_Assembler::arraycopy_valuetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check) { if (null_check) { __ cbz(obj, *slow_path->entry()); } @@ -2411,12 +2417,12 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { return; } - // Handle inline type arrays - if (flags & LIR_OpArrayCopy::src_inlinetype_check) { - arraycopy_inlinetype_check(src, tmp, stub, false, (flags & LIR_OpArrayCopy::src_null_check)); + // Handle value type arrays + if (flags & LIR_OpArrayCopy::src_valuetype_check) { + arraycopy_valuetype_check(src, tmp, stub, false, (flags & LIR_OpArrayCopy::src_null_check)); } - if (flags & LIR_OpArrayCopy::dst_inlinetype_check) { - arraycopy_inlinetype_check(dst, tmp, stub, true, (flags & LIR_OpArrayCopy::dst_null_check)); + if (flags & LIR_OpArrayCopy::dst_valuetype_check) { + arraycopy_valuetype_check(dst, tmp, stub, true, (flags & LIR_OpArrayCopy::dst_null_check)); } assert(default_type != nullptr && default_type->is_array_klass() && default_type->is_loaded(), "must be true at this point"); @@ -2933,25 +2939,25 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { COMMENT("} emit_profile_type"); } -void LIR_Assembler::emit_profile_inline_type(LIR_OpProfileInlineType* op) { +void LIR_Assembler::emit_profile_value_type(LIR_OpProfileValueType* op) { Register obj = op->obj()->as_register(); Register tmp = op->tmp()->as_pointer_register(); bool not_null = op->not_null(); int flag = op->flag(); - Label not_inline_type; + Label not_value_type; if (!not_null) { - __ cbz(obj, not_inline_type); + __ cbz(obj, not_value_type); } - __ test_oop_is_not_inline_type(obj, tmp, not_inline_type); + __ test_oop_is_not_value_type(obj, tmp, not_value_type); Address mdo_addr = as_Address(op->mdp()->as_address_ptr(), rscratch2); __ ldrb(rscratch1, mdo_addr); __ orr(rscratch1, rscratch1, flag); __ strb(rscratch1, mdo_addr); - __ bind(not_inline_type); + __ bind(not_value_type); } void LIR_Assembler::align_backward_branch_target() { diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp index 5b58a586f295..699b8129a475 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp @@ -78,7 +78,7 @@ friend class ArrayCopyStub; _deopt_handler_size = 4 * NativeInstruction::instruction_size }; - void arraycopy_inlinetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check); + void arraycopy_valuetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check); void move(LIR_Opr src, LIR_Opr dst); public: diff --git a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp index fb68826ee906..eeca0d8a2aec 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp @@ -32,9 +32,9 @@ #include "c1/c1_Runtime1.hpp" #include "c1/c1_ValueStack.hpp" #include "ci/ciArray.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciObjArrayKlass.hpp" #include "ci/ciTypeArrayKlass.hpp" +#include "ci/ciValueKlass.hpp" #include "compiler/compilerDefinitions.inline.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" @@ -326,7 +326,7 @@ void LIRGenerator::do_MonitorEnter(MonitorEnter* x) { } CodeStub* throw_ie_stub = - x->maybe_inlinetype() ? + x->maybe_valuetype() ? new SimpleExceptionStub(StubId::c1_throw_identity_exception_id, obj.result(), state_for(x)) : nullptr; @@ -1137,7 +1137,7 @@ void LIRGenerator::do_NewInstance(NewInstance* x) { CodeEmitInfo* info = state_for(x, x->needs_state_before() ? x->state_before() : x->state()); LIR_Opr reg = result_register_for(x->type()); new_instance(reg, x->klass(), x->is_unresolved(), - !x->is_unresolved() && x->klass()->is_inlinetype(), + !x->is_unresolved() && x->klass()->is_value_klass(), FrameMap::r10_oop_opr, FrameMap::r11_oop_opr, FrameMap::r4_oop_opr, diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp index 32d2832dbbe8..60f8cf99560a 100644 --- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp @@ -261,7 +261,7 @@ void C1_MacroAssembler::build_frame_helper(int frame_size_in_bytes, int sp_offse void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, bool has_scalarized_args, - Label* verified_inline_entry_label) { + Label* verified_value_entry_label) { // Make sure there is enough stack space for this method's activation. // Note that we do this before creating a frame. assert(bang_size_in_bytes >= frame_size_in_bytes, "stack bang size incorrect"); @@ -273,9 +273,9 @@ void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_by BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); bs->nmethod_entry_barrier(this, nullptr /* slow_path */, nullptr /* continuation */, nullptr /* guard */); - if (verified_inline_entry_label != nullptr) { + if (verified_value_entry_label != nullptr) { // Jump here from the scalarized entry points that already created the frame. - bind(*verified_inline_entry_label); + bind(*verified_value_entry_label); } } @@ -289,20 +289,20 @@ void C1_MacroAssembler::verified_entry(bool breakAtEntry) { if (C1Breakpoint) brk(1); } -int C1_MacroAssembler::scalarized_entry(const CompiledEntrySignature* ces, int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, Label& verified_inline_entry_label, bool is_inline_ro_entry) { - assert(InlineTypePassFieldsAsArgs, "sanity"); +int C1_MacroAssembler::scalarized_entry(const CompiledEntrySignature* ces, int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, Label& verified_value_entry_label, bool is_value_ro_entry) { + assert(ValueTypePassFieldsAsArgs, "sanity"); // Make sure there is enough stack space for this method's activation. assert(bang_size_in_bytes >= frame_size_in_bytes, "stack bang size incorrect"); generate_stack_overflow_check(bang_size_in_bytes); GrowableArray* sig = ces->sig(); - GrowableArray* sig_cc = is_inline_ro_entry ? ces->sig_cc_ro() : ces->sig_cc(); + GrowableArray* sig_cc = is_value_ro_entry ? ces->sig_cc_ro() : ces->sig_cc(); VMRegPair* regs = ces->regs(); - VMRegPair* regs_cc = is_inline_ro_entry ? ces->regs_cc_ro() : ces->regs_cc(); + VMRegPair* regs_cc = is_value_ro_entry ? ces->regs_cc_ro() : ces->regs_cc(); int args_on_stack = ces->args_on_stack(); - int args_on_stack_cc = is_inline_ro_entry ? ces->args_on_stack_cc_ro() : ces->args_on_stack_cc(); + int args_on_stack_cc = is_value_ro_entry ? ces->args_on_stack_cc_ro() : ces->args_on_stack_cc(); - assert(sig->length() <= sig_cc->length(), "Zero-sized inline class not allowed!"); + assert(sig->length() <= sig_cc->length(), "Zero-sized value class not allowed!"); BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, sig_cc->length()); int args_passed = sig->length(); int args_passed_cc = SigEntry::fill_sig_bt(sig_cc, sig_bt); @@ -316,10 +316,10 @@ int C1_MacroAssembler::scalarized_entry(const CompiledEntrySignature* ces, int f bs->nmethod_entry_barrier(this, nullptr /* slow_path */, nullptr /* continuation */, nullptr /* guard */); mov(r19, (intptr_t) ces->method()); - if (is_inline_ro_entry) { - far_call(RuntimeAddress(Runtime1::entry_for(StubId::c1_buffer_inline_args_no_receiver_id))); + if (is_value_ro_entry) { + far_call(RuntimeAddress(Runtime1::entry_for(StubId::c1_buffer_value_args_no_receiver_id))); } else { - far_call(RuntimeAddress(Runtime1::entry_for(StubId::c1_buffer_inline_args_id))); + far_call(RuntimeAddress(Runtime1::entry_for(StubId::c1_buffer_value_args_id))); } int rt_call_offset = offset(); @@ -332,16 +332,16 @@ int C1_MacroAssembler::scalarized_entry(const CompiledEntrySignature* ces, int f assert(args_on_stack <= args_on_stack_cc, "Sanity check"); - shuffle_inline_args(true, is_inline_ro_entry, sig_cc, - args_passed_cc, args_on_stack_cc, regs_cc, // from - args_passed, args_on_stack, regs, // to - 0, val_array); + shuffle_value_args(true, is_value_ro_entry, sig_cc, + args_passed_cc, args_on_stack_cc, regs_cc, // from + args_passed, args_on_stack, regs, // to + 0, val_array); // Create the real frame. Below jump will then skip over the stack banging and frame - // setup code in the verified_inline_entry (which has a different real_frame_size). + // setup code in the verified_value_entry (which has a different real_frame_size). build_frame_helper(frame_size_in_bytes, sp_offset_for_orig_pc, false); - b(verified_inline_entry_label); + b(verified_value_entry_label); return rt_call_offset; } diff --git a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp index 3bf91da8662f..add96b787083 100644 --- a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp @@ -773,14 +773,14 @@ OopMapSet* Runtime1::generate_code_for(StubId id, StubAssembler* sasm) { __ br(Assembler::EQ, ok); __ cmpw(t0, Klass::_lh_array_tag_flat_value); // new "[LVT;" __ br(Assembler::EQ, ok); - __ stop("assert(is an object or inline type array klass)"); + __ stop("assert(is an object or value type array klass)"); break; case StubId::c1_new_null_free_array_id: __ cmpw(t0, Klass::_lh_array_tag_flat_value); // the array can be a flat array. __ br(Assembler::EQ, ok); __ cmpw(t0, Klass::_lh_array_tag_ref_value); // the array cannot be a flat array (due to the InlineArrayElementMaxFlatSize, etc.) __ br(Assembler::EQ, ok); - __ stop("assert(is an object or inline type array klass)"); + __ stop("assert(is an object or value type array klass)"); break; default: ShouldNotReachHere(); } @@ -833,17 +833,17 @@ OopMapSet* Runtime1::generate_code_for(StubId id, StubAssembler* sasm) { } break; - case StubId::c1_buffer_inline_args_id: - case StubId::c1_buffer_inline_args_no_receiver_id: + case StubId::c1_buffer_value_args_id: + case StubId::c1_buffer_value_args_no_receiver_id: { - const char* name = (id == StubId::c1_buffer_inline_args_id) ? - "buffer_inline_args" : "buffer_inline_args_no_receiver"; + const char* name = (id == StubId::c1_buffer_value_args_id) ? + "buffer_value_args" : "buffer_value_args_no_receiver"; StubFrame f(sasm, name, dont_gc_arguments); OopMap* map = save_live_registers(sasm); Register method = r19; // Incoming - address entry = (id == StubId::c1_buffer_inline_args_id) ? - CAST_FROM_FN_PTR(address, buffer_inline_args) : - CAST_FROM_FN_PTR(address, buffer_inline_args_no_receiver); + address entry = (id == StubId::c1_buffer_value_args_id) ? + CAST_FROM_FN_PTR(address, buffer_value_args) : + CAST_FROM_FN_PTR(address, buffer_value_args_no_receiver); // This is called from a C1 method's scalarized entry point // where r0-r7 may be holding live argument values so we can't // return the result in r0 as the other stubs do. LR is used as diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp index cc8d8b82e7b0..283a0a1e3c27 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp @@ -160,7 +160,7 @@ bool frame::safe_for_sender(JavaThread *thread) { // Just strip it for now. sender_pc = pauth_strip_pointer((address) *(sender_sp - 1)); - // Repair the sender sp if this is a method with scalarized inline type args + // Repair the sender sp if this is a method with scalarized value type args sender_sp = repair_sender_sp(sender_sp, saved_fp_addr); sender_unextended_sp = sender_sp; } diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.hpp index b096583c1cf4..4d784b630647 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.hpp @@ -150,7 +150,7 @@ } public: - // Support for scalarized inline type calling convention + // Support for scalarized value type calling convention intptr_t* repair_sender_sp(intptr_t* sender_sp, intptr_t** saved_fp_addr) const; struct CompiledFramePointers { intptr_t* sender_sp; // The top of the stack of the sender diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp index e062fabfb7b3..4db8c5500874 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp @@ -448,7 +448,7 @@ ALWAYSINLINE frame frame::sender_raw(RegisterMap* map) const { return frame(sender_sp(), link(), sender_pc()); } -// Check for a method with scalarized inline type arguments that needs +// Check for a method with scalarized value type arguments that needs // a stack repair and return the repaired sender stack pointer. ALWAYSINLINE intptr_t* frame::repair_sender_sp(intptr_t* sender_sp, intptr_t** saved_fp_addr) const { nmethod* nm = _cb->as_nmethod_or_null(); @@ -510,8 +510,8 @@ ALWAYSINLINE frame frame::sender_for_compiled_frame(RegisterMap* map) const { #ifdef COMPILER1 nmethod* nm = _cb->as_nmethod_or_null(); if (nm != nullptr && nm->is_compiled_by_c1() && nm->method()->has_scalarized_args() && - pc() < nm->verified_inline_entry_point()) { - // The VEP and VIEP(RO) of C1-compiled methods call buffer_inline_args_xxx + pc() < nm->verified_value_entry_point()) { + // The VEP and VIEP(RO) of C1-compiled methods call buffer_value_args_xxx // before doing any argument shuffling, so we need to scan the oops // as the caller passes them. c1_buffering = true; diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp index 4851a76ebe67..6dcb27ee578a 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp @@ -138,15 +138,15 @@ void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators } void BarrierSetAssembler::flat_field_copy(MacroAssembler* masm, DecoratorSet decorators, - Register src, Register dst, Register inline_layout_info) { + Register src, Register dst, Register value_field_layout_info) { // flat_field_copy implementation is fairly complex, and there are not any // "short-cuts" to be made from asm. What there is, appears to have the same // cost in C++, so just "call_VM_leaf" for now rather than maintain hundreds // of hand-rolled instructions... if (decorators & IS_DEST_UNINITIALIZED) { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetRuntime::value_copy_is_dest_uninitialized), src, dst, inline_layout_info); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetRuntime::value_copy_is_dest_uninitialized), src, dst, value_field_layout_info); } else { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetRuntime::value_copy), src, dst, inline_layout_info); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetRuntime::value_copy), src, dst, value_field_layout_info); } } diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp index d2fcc6568ec4..773814c9d8ff 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp @@ -100,7 +100,7 @@ class BarrierSetAssembler: public CHeapObj { Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); virtual void flat_field_copy(MacroAssembler* masm, DecoratorSet decorators, - Register src, Register dst, Register inline_layout_info); + Register src, Register dst, Register value_field_layout_info); virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, Register obj, Register tmp, Label& slowpath); diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp index 1ebef02241fd..93b808442618 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp @@ -83,11 +83,11 @@ static int* decode_guard_from_instruction(nmethod* nm, address& instruction) { // // The mapping of C1-compiled methods (scalarization used) looks as follows: // * alt1: verified entry point -// * alt2 (optional): verified inline ro entry point +// * alt2 (optional): verified value ro entry point // // The mapping of C2-compiled methods (scalarization used) looks as follows: -// * alt1: verified inline entry point -// * alt2 (optional): verified inline ro entry point +// * alt1: verified value entry point +// * alt2 (optional): verified value ro entry point // // In other scenarios, neither alt1 nor alt2 are defined. class NativeNMethodBarrier { @@ -119,19 +119,19 @@ class NativeNMethodBarrier { // If the nmethod has scalarized arguments, then there are more entry // points, each with their own nmethod entry barrier. if (!nm->is_osr_method() && nm->method()->has_scalarized_args()) { - assert(nm->verified_entry_point() != nm->verified_inline_entry_point(), "scalarized entry point not found"); - address method_body = nm->is_compiled_by_c1() ? nm->verified_inline_entry_point() : nm->verified_entry_point(); + assert(nm->verified_entry_point() != nm->verified_value_entry_point(), "scalarized entry point not found"); + address method_body = nm->is_compiled_by_c1() ? nm->verified_value_entry_point() : nm->verified_entry_point(); int barrier_offset = _default_entry_instruction - method_body; // Set the first alternative entry point. - address entry_point2 = nm->is_compiled_by_c1() ? nm->verified_entry_point() : nm->verified_inline_entry_point(); + address entry_point2 = nm->is_compiled_by_c1() ? nm->verified_entry_point() : nm->verified_value_entry_point(); _verified_alt1_instruction = entry_point2 + barrier_offset; assert(_default_entry_instruction != _verified_alt1_instruction, "sanity"); _verified_alt1_guard = decode_guard_from_instruction(nm, _verified_alt1_instruction); // If there is a second alternative entry point, set it too. - if (method_body != nm->verified_inline_ro_entry_point() && entry_point2 != nm->verified_inline_ro_entry_point()) { - _verified_alt2_instruction = nm->verified_inline_ro_entry_point() + barrier_offset; + if (method_body != nm->verified_value_ro_entry_point() && entry_point2 != nm->verified_value_ro_entry_point()) { + _verified_alt2_instruction = nm->verified_value_ro_entry_point() + barrier_offset; _verified_alt2_guard = decode_guard_from_instruction(nm, _verified_alt2_instruction); assert(_default_entry_instruction != _verified_alt2_instruction && _verified_alt1_instruction != _verified_alt2_instruction, diff --git a/src/hotspot/cpu/aarch64/globals_aarch64.hpp b/src/hotspot/cpu/aarch64/globals_aarch64.hpp index 24a80c70d0ab..eb19d08134c8 100644 --- a/src/hotspot/cpu/aarch64/globals_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/globals_aarch64.hpp @@ -67,8 +67,8 @@ define_pd_global(bool, RewriteFrequentPairs, true); define_pd_global(bool, PreserveFramePointer, false); -define_pd_global(bool, InlineTypePassFieldsAsArgs, true); -define_pd_global(bool, InlineTypeReturnedAsFields, true); +define_pd_global(bool, ValueTypePassFieldsAsArgs, true); +define_pd_global(bool, ValueTypeReturnedAsFields, true); define_pd_global(uintx, TypeProfileLevel, 111); diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp index 20cbf6e963a7..174cedb41a9e 100644 --- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp @@ -36,10 +36,10 @@ #include "oops/markWord.hpp" #include "oops/method.hpp" #include "oops/methodData.hpp" -#include "oops/inlineKlass.hpp" #include "oops/resolvedFieldEntry.hpp" #include "oops/resolvedIndyEntry.hpp" #include "oops/resolvedMethodEntry.hpp" +#include "oops/valueKlass.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiThreadState.hpp" #include "runtime/basicLock.hpp" @@ -221,7 +221,7 @@ void InterpreterMacroAssembler::write_flat_field(Register entry, Register field_ Label slow_path, done; load_unsigned_byte(tmp1, Address(entry, in_bytes(ResolvedFieldEntry::flags_offset()))); - test_field_is_not_null_free_inline_type(tmp1, noreg /* temp */, slow_path); + test_field_is_not_null_free_value_type(tmp1, noreg /* temp */, slow_path); null_check(r0); // FIXME JDK-8341120 @@ -233,7 +233,7 @@ void InterpreterMacroAssembler::write_flat_field(Register entry, Register field_ Register layout_info = field_offset; load_unsigned_short(tmp1, Address(entry, in_bytes(ResolvedFieldEntry::field_index_offset()))); ldr(tmp2, Address(entry, in_bytes(ResolvedFieldEntry::field_holder_offset()))); - inline_layout_info(tmp2, tmp1, layout_info); + value_field_layout_info(tmp2, tmp1, layout_info); flat_field_copy(IN_HEAP, r0, obj, layout_info); b(done); @@ -695,7 +695,7 @@ void InterpreterMacroAssembler::remove_activation(TosState state, bind(no_reserved_zone_enabling); } - if (state == atos && InlineTypeReturnedAsFields) { + if (state == atos && ValueTypeReturnedAsFields) { Label skip; Label not_null; cbnz(r0, not_null); @@ -710,14 +710,14 @@ void InterpreterMacroAssembler::remove_activation(TosState state, b(skip); bind(not_null); - // Check if we are returning a non-null inline type and load its fields into registers - test_oop_is_not_inline_type(r0, rscratch2, skip, /* can_be_null= */ false); + // Check if we are returning a non-null value type and load its fields into registers + test_oop_is_not_value_type(r0, rscratch2, skip, /* can_be_null= */ false); - // Load fields from a buffered value with an inline class specific handler + // Load fields from a buffered value with a value class specific handler load_klass(rscratch1 /*dst*/, r0 /*src*/, rscratch2 /*tmp*/); - ldr(rscratch1, Address(rscratch1, InlineKlass::adr_members_offset())); - ldr(rscratch1, Address(rscratch1, InlineKlass::unpack_handler_offset())); - // Unpack handler can be null if inline type is not scalarizable in returns + ldr(rscratch1, Address(rscratch1, ValueKlass::adr_members_offset())); + ldr(rscratch1, Address(rscratch1, ValueKlass::unpack_handler_offset())); + // Unpack handler can be null if value type is not scalarizable in returns cbz(rscratch1, skip); blr(rscratch1); @@ -1298,18 +1298,18 @@ void InterpreterMacroAssembler::profile_acmp(Register mdp, mov(tmp, left); profile_obj_type(tmp, Address(mdp, in_bytes(ACmpData::left_offset()))); - Label left_not_inline_type; - test_oop_is_not_inline_type(left, tmp, left_not_inline_type); - set_mdp_flag_at(mdp, ACmpData::left_inline_type_byte_constant()); - bind(left_not_inline_type); + Label left_not_value_type; + test_oop_is_not_value_type(left, tmp, left_not_value_type); + set_mdp_flag_at(mdp, ACmpData::left_value_type_byte_constant()); + bind(left_not_value_type); mov(tmp, right); profile_obj_type(tmp, Address(mdp, in_bytes(ACmpData::right_offset()))); - Label right_not_inline_type; - test_oop_is_not_inline_type(right, tmp, right_not_inline_type); - set_mdp_flag_at(mdp, ACmpData::right_inline_type_byte_constant()); - bind(right_not_inline_type); + Label right_not_value_type; + test_oop_is_not_value_type(right, tmp, right_not_value_type); + set_mdp_flag_at(mdp, ACmpData::right_value_type_byte_constant()); + bind(right_not_value_type); bind(profile_continue); } diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp index d72137a09448..0c3cee6178bd 100644 --- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp @@ -158,7 +158,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void get_cache_index_at_bcp(Register index, int bcp_offset, size_t index_size = sizeof(u2)); void get_method_counters(Register method, Register mcs, Label& skip); - // Allocate instance in "obj" and read in the content of the inline field + // Allocate instance in "obj" and read in the content of the flat field // NOTES: // - input holder object via "obj", which must be r0, // will return new instance via the same reg diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 74fd6e0d42af..fa3217c0dbb5 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -27,7 +27,7 @@ #include "asm/assembler.inline.hpp" #include "cds/archiveBuilder.hpp" #include "ci/ciEnv.hpp" -#include "ci/ciInlineKlass.hpp" +#include "ci/ciValueKlass.hpp" #include "code/compiledIC.hpp" #include "compiler/compileTask.hpp" #include "compiler/disassembler.hpp" @@ -2045,7 +2045,7 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file, stp(rscratch2, lr, Address(pre(sp, -2 * wordSize))); mov(r0, reg); - lea(rscratch1, ExternalAddress((address)b)); + lea(rscratch1, Address((address)b, external_word_Relocation::spec_for_immediate())); // call indirectly to solve generation ordering problem lea(rscratch2, RuntimeAddress(StubRoutines::verify_oop_subroutine_entry_address())); @@ -2096,7 +2096,7 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* f } else { ldr(r0, addr); } - lea(rscratch1, ExternalAddress((address)b)); + lea(rscratch1, Address((address)b, external_word_Relocation::spec_for_immediate())); // call indirectly to solve generation ordering problem lea(rscratch2, RuntimeAddress(StubRoutines::verify_oop_subroutine_entry_address())); @@ -2374,36 +2374,36 @@ void MacroAssembler::null_check(Register reg, int offset) { } } -void MacroAssembler::test_markword_is_inline_type(Register markword, Label& is_inline_type) { +void MacroAssembler::test_markword_is_value_type(Register markword, Label& is_value_type) { assert_different_registers(markword, rscratch2); - mov(rscratch2, markWord::inline_type_pattern_mask); + mov(rscratch2, markWord::value_type_pattern_mask); andr(markword, markword, rscratch2); - mov(rscratch2, markWord::inline_type_pattern); + mov(rscratch2, markWord::value_type_pattern); cmp(markword, rscratch2); - br(Assembler::EQ, is_inline_type); + br(Assembler::EQ, is_value_type); } -void MacroAssembler::test_oop_is_not_inline_type(Register object, Register tmp, Label& not_inline_type, bool can_be_null) { +void MacroAssembler::test_oop_is_not_value_type(Register object, Register tmp, Label& not_value_type, bool can_be_null) { assert_different_registers(tmp, rscratch1); if (can_be_null) { - cbz(object, not_inline_type); + cbz(object, not_value_type); } - const int is_inline_type_mask = markWord::inline_type_pattern; + const int is_value_type_mask = markWord::value_type_pattern; ldr(tmp, Address(object, oopDesc::mark_offset_in_bytes())); - mov(rscratch1, is_inline_type_mask); + mov(rscratch1, is_value_type_mask); andr(tmp, tmp, rscratch1); cmp(tmp, rscratch1); - br(Assembler::NE, not_inline_type); + br(Assembler::NE, not_value_type); } -void MacroAssembler::test_field_is_null_free_inline_type(Register flags, Register temp_reg, Label& is_null_free_inline_type) { +void MacroAssembler::test_field_is_null_free_value_type(Register flags, Register temp_reg, Label& is_null_free_value_type) { assert(temp_reg == noreg, "not needed"); // keep signature uniform with x86 - tbnz(flags, ResolvedFieldEntry::is_null_free_inline_type_shift, is_null_free_inline_type); + tbnz(flags, ResolvedFieldEntry::is_null_free_value_type_shift, is_null_free_value_type); } -void MacroAssembler::test_field_is_not_null_free_inline_type(Register flags, Register temp_reg, Label& not_null_free_inline_type) { +void MacroAssembler::test_field_is_not_null_free_value_type(Register flags, Register temp_reg, Label& not_null_free_value_type) { assert(temp_reg == noreg, "not needed"); // keep signature uniform with x86 - tbz(flags, ResolvedFieldEntry::is_null_free_inline_type_shift, not_null_free_inline_type); + tbz(flags, ResolvedFieldEntry::is_null_free_value_type_shift, not_null_free_value_type); } void MacroAssembler::test_field_is_flat(Register flags, Register temp_reg, Label& is_flat) { @@ -3487,7 +3487,7 @@ void MacroAssembler::stop(const char* msg) { // load msg into r0 so we can access it from the signal handler // ExternalAddress enables saving and restoring via the code cache lea(c_rarg0, ExternalAddress((address) str)); - dcps1(0xdeae); + udf(NativeInstruction::udf_stop); } void MacroAssembler::unimplemented(const char* what) { @@ -5666,20 +5666,20 @@ void MacroAssembler::access_store_at(BasicType type, DecoratorSet decorators, } void MacroAssembler::flat_field_copy(DecoratorSet decorators, Register src, Register dst, - Register inline_layout_info) { + Register value_field_layout_info) { BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); - bs->flat_field_copy(this, decorators, src, dst, inline_layout_info); + bs->flat_field_copy(this, decorators, src, dst, value_field_layout_info); } -void MacroAssembler::payload_offset(Register inline_klass, Register offset) { - ldr(offset, Address(inline_klass, InlineKlass::adr_members_offset())); - ldrw(offset, Address(offset, InlineKlass::payload_offset_offset())); +void MacroAssembler::payload_offset(Register value_klass, Register offset) { + ldr(offset, Address(value_klass, ValueKlass::adr_members_offset())); + ldrw(offset, Address(offset, ValueKlass::payload_offset_offset())); } -void MacroAssembler::payload_address(Register oop, Register data, Register inline_klass) { +void MacroAssembler::payload_address(Register oop, Register data, Register value_klass) { // ((address) (void*) o) + vk->payload_offset(); Register offset = (data == oop) ? rscratch1 : data; - payload_offset(inline_klass, offset); + payload_offset(value_klass, offset); if (data == oop) { add(data, data, offset); } else { @@ -5801,9 +5801,9 @@ void MacroAssembler::verify_tlab() { #endif } -void MacroAssembler::inline_layout_info(Register holder_klass, Register index, Register layout_info) { +void MacroAssembler::value_field_layout_info(Register holder_klass, Register index, Register layout_info) { assert_different_registers(holder_klass, index, layout_info); - InlineLayoutInfo array[2]; + ValueFieldLayoutInfo array[2]; int size = (char*)&array[1] - (char*)&array[0]; // computing size of array elements if (is_power_of_2(size)) { lsl(index, index, log2i_exact(size)); // Scale index by power of 2 @@ -5811,8 +5811,8 @@ void MacroAssembler::inline_layout_info(Register holder_klass, Register index, R mov(layout_info, size); mul(index, index, layout_info); // Scale the index to be the entry index * array_element_size } - ldr(layout_info, Address(holder_klass, InstanceKlass::inline_layout_info_array_offset())); - add(layout_info, layout_info, Array::base_offset_in_bytes()); + ldr(layout_info, Address(holder_klass, InstanceKlass::value_field_layout_info_array_offset())); + add(layout_info, layout_info, Array::base_offset_in_bytes()); lea(layout_info, Address(layout_info, index)); } @@ -7019,13 +7019,13 @@ void MacroAssembler::verified_entry(Compile* C, int sp_inc) { } #endif // COMPILER2 -int MacroAssembler::store_inline_type_fields_to_buf(ciInlineKlass* vk, bool from_interpreter) { - assert(InlineTypeReturnedAsFields, "Inline types should never be returned as fields"); - // An inline type might be returned. If fields are in registers we - // need to allocate an inline type instance and initialize it with +int MacroAssembler::store_value_type_fields_to_buf(ciValueKlass* vk, bool from_interpreter) { + assert(ValueTypeReturnedAsFields, "Value types should never be returned as fields"); + // A value type might be returned. If fields are in registers we + // need to allocate a value type instance and initialize it with // the value of the fields. Label skip; - // We only need a new buffered inline type if a new one is not returned + // We only need a new buffered value type if a new one is not returned tbz(r0, 0, skip); int call_offset = -1; @@ -7038,21 +7038,21 @@ int MacroAssembler::store_inline_type_fields_to_buf(ciInlineKlass* vk, bool from // e.g. object size is always not zero, sometimes it's constant; storing klass ptr after // allocating is not necessary if vk != nullptr, etc. Label slow_case; - // 1. Try to allocate a new buffered inline instance either from TLAB or eden space + // 1. Try to allocate a new buffered value instance either from TLAB or eden space mov(r0_preserved, r0); // save r0 for slow_case since *_allocate may corrupt it when allocation failed if (vk != nullptr) { // Called from C1, where the return type is statically known. - movptr(klass, (intptr_t)vk->get_InlineKlass()); + movptr(klass, (intptr_t)vk->get_ValueKlass()); jint lh = vk->layout_helper(); - assert(lh != Klass::_lh_neutral_value, "inline class in return type must have been resolved"); + assert(lh != Klass::_lh_neutral_value, "value class in return type must have been resolved"); if (UseTLAB && !Klass::layout_helper_needs_slow_path(lh)) { tlab_allocate(r0, noreg, lh, tmp1, tmp2, slow_case); } else { b(slow_case); } } else { - // Call from interpreter. R0 contains ((the InlineKlass* of the return type) | 0x01) + // Call from interpreter. R0 contains ((the ValueKlass* of the return type) | 0x01) andr(klass, r0, -2); if (UseTLAB) { ldrw(tmp2, Address(klass, Klass::layout_helper_offset())); @@ -7064,13 +7064,13 @@ int MacroAssembler::store_inline_type_fields_to_buf(ciInlineKlass* vk, bool from } } if (UseTLAB) { - // 2. Initialize buffered inline instance header + // 2. Initialize buffered value instance header Register buffer_obj = r0; if (UseCompactObjectHeaders) { ldr(rscratch1, Address(klass, Klass::prototype_header_offset())); str(rscratch1, Address(buffer_obj, oopDesc::mark_offset_in_bytes())); } else { - mov(rscratch1, (intptr_t)markWord::inline_type_prototype().value()); + mov(rscratch1, (intptr_t)markWord::value_type_prototype().value()); str(rscratch1, Address(buffer_obj, oopDesc::mark_offset_in_bytes())); store_klass_gap(buffer_obj, zr); if (vk == nullptr) { @@ -7080,12 +7080,12 @@ int MacroAssembler::store_inline_type_fields_to_buf(ciInlineKlass* vk, bool from store_klass(buffer_obj, klass, rscratch1); klass = tmp1; } - // 3. Initialize its fields with an inline class specific handler + // 3. Initialize its fields with a value class specific handler if (vk != nullptr) { far_call(RuntimeAddress(vk->pack_handler())); // no need for call info as this will not safepoint. } else { - ldr(tmp1, Address(klass, InlineKlass::adr_members_offset())); - ldr(tmp1, Address(tmp1, InlineKlass::pack_handler_offset())); + ldr(tmp1, Address(klass, ValueKlass::adr_members_offset())); + ldr(tmp1, Address(tmp1, ValueKlass::pack_handler_offset())); blr(tmp1); } @@ -7096,16 +7096,16 @@ int MacroAssembler::store_inline_type_fields_to_buf(ciInlineKlass* vk, bool from DEBUG_ONLY(should_not_reach_here()); } bind(slow_case); - // We failed to allocate a new inline type, fall back to a runtime + // We failed to allocate a new value type, fall back to a runtime // call. Some oop field may be live in some registers but we can't // tell. That runtime call will take care of preserving them // across a GC if there's one. mov(r0, r0_preserved); if (from_interpreter) { - super_call_VM_leaf(SharedRuntime::store_inline_type_fields_to_buf_entry()); + super_call_VM_leaf(SharedRuntime::store_value_type_fields_to_buf_entry()); } else { - far_call(RuntimeAddress(SharedRuntime::store_inline_type_fields_to_buf_entry())); + far_call(RuntimeAddress(SharedRuntime::store_value_type_fields_to_buf_entry())); call_offset = offset(); } membar(Assembler::StoreStore); @@ -7175,9 +7175,9 @@ bool MacroAssembler::move_helper(VMReg from, VMReg to, BasicType bt, RegState re return true; } -// Calculate the extra stack space required for packing or unpacking inline +// Calculate the extra stack space required for packing or unpacking value // args and adjust the stack pointer -int MacroAssembler::extend_stack_for_inline_args(int args_on_stack) { +int MacroAssembler::extend_stack_for_value_args(int args_on_stack) { int sp_inc = args_on_stack * VMRegImpl::stack_slot_size; sp_inc = align_up(sp_inc, StackAlignmentInBytes); assert(sp_inc > 0, "sanity"); @@ -7196,10 +7196,10 @@ int MacroAssembler::extend_stack_for_inline_args(int args_on_stack) { return sp_inc + 2 * wordSize; // Account for the FP/LR space } -// Read all fields from an inline type oop and store the values in registers/stack slots -bool MacroAssembler::unpack_inline_helper(const GrowableArray* sig, int& sig_index, - VMReg from, int& from_index, VMRegPair* to, int to_count, int& to_index, - RegState reg_state[]) { +// Read all fields from a value type oop and store the values in registers/stack slots +bool MacroAssembler::unpack_value_helper(const GrowableArray* sig, int& sig_index, + VMReg from, int& from_index, VMRegPair* to, int to_count, int& to_index, + RegState reg_state[]) { assert(sig->at(sig_index)._bt == T_VOID, "should be at end delimiter"); assert(from->is_valid(), "source must be valid"); bool progress = false; @@ -7220,7 +7220,7 @@ bool MacroAssembler::unpack_inline_helper(const GrowableArray* sig, in #endif Register fromReg = noreg; - ScalarizedInlineArgsStream stream(sig, sig_index, to, to_count, to_index, true); + ScalarizedValueArgsStream stream(sig, sig_index, to, to_count, to_index, true); bool done = true; bool mark_done = true; VMReg toReg; @@ -7260,7 +7260,7 @@ bool MacroAssembler::unpack_inline_helper(const GrowableArray* sig, in fromReg = tmp1; } if (null_check) { - // Nullable inline type argument, emit null check + // Nullable value type argument, emit null check cbz(fromReg, L_null); } } @@ -7342,10 +7342,10 @@ bool MacroAssembler::unpack_inline_helper(const GrowableArray* sig, in return done; } -// Pack fields back into an inline type oop -bool MacroAssembler::pack_inline_helper(const GrowableArray* sig, int& sig_index, int vtarg_index, - VMRegPair* from, int from_count, int& from_index, VMReg to, - RegState reg_state[], Register val_array) { +// Pack fields back into a value type oop +bool MacroAssembler::pack_value_helper(const GrowableArray* sig, int& sig_index, int vtarg_index, + VMRegPair* from, int from_count, int& from_index, VMReg to, + RegState reg_state[], Register val_array) { assert(sig->at(sig_index)._bt == T_METADATA, "should be at delimiter"); assert(to->is_valid(), "destination must be valid"); @@ -7376,7 +7376,7 @@ bool MacroAssembler::pack_inline_helper(const GrowableArray* sig, int& val_obj = val_obj_tmp; } - ScalarizedInlineArgsStream stream(sig, sig_index, from, from_count, from_index); + ScalarizedValueArgsStream stream(sig, sig_index, from, from_count, from_index); VMReg fromReg; BasicType bt; Label L_null; @@ -7386,7 +7386,7 @@ bool MacroAssembler::pack_inline_helper(const GrowableArray* sig, int& int off = sig->at(stream.sig_index())._offset; if (off == -1) { - // Nullable inline type argument, emit null check + // Nullable value type argument, emit null check Label L_notNull; if (fromReg->is_stack()) { int ld_off = fromReg->reg2stack() * VMRegImpl::stack_slot_size; @@ -7892,8 +7892,8 @@ void MacroAssembler::fast_lock(Register basic_lock, Register obj, Register t1, R assert(oopDesc::mark_offset_in_bytes() == 0, "required to avoid lea"); orr(mark, mark, markWord::lock_neutral_value); if (Arguments::is_valhalla_enabled()) { - // Mask inline_type bit such that we go to the slow path if object is an inline type - andr(mark, mark, ~((int) markWord::inline_type_bit_in_place)); + // Mask value_type bit such that we go to the slow path if object is a value type + andr(mark, mark, ~((int) markWord::value_type_bit_in_place)); } eor(t, mark, markWord::lock_neutral_value); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index ba46983c7a07..648fe784a1ca 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -40,7 +40,7 @@ #include "runtime/signature.hpp" -class ciInlineKlass; +class ciValueKlass; class OopMap; struct GtestFriendToMacroAssembler; @@ -716,13 +716,13 @@ class MacroAssembler: public Assembler { static bool uses_implicit_null_check(void* address); // markWord tests, kills markWord reg - void test_markword_is_inline_type(Register markword, Label& is_inline_type); + void test_markword_is_value_type(Register markword, Label& is_value_type); - // inlineKlass queries, kills temp_reg - void test_oop_is_not_inline_type(Register object, Register tmp, Label& not_inline_type, bool can_be_null = true); + // ValueKlass queries, kills temp_reg + void test_oop_is_not_value_type(Register object, Register tmp, Label& not_value_type, bool can_be_null = true); - void test_field_is_null_free_inline_type(Register flags, Register temp_reg, Label& is_null_free); - void test_field_is_not_null_free_inline_type(Register flags, Register temp_reg, Label& not_null_free); + void test_field_is_null_free_value_type(Register flags, Register temp_reg, Label& is_null_free); + void test_field_is_not_null_free_value_type(Register flags, Register temp_reg, Label& not_null_free); void test_field_is_flat(Register flags, Register temp_reg, Label& is_flat); // Check oops for special arrays, i.e. flat arrays and/or null-free arrays @@ -980,11 +980,11 @@ class MacroAssembler: public Assembler { void access_store_at(BasicType type, DecoratorSet decorators, Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); - void flat_field_copy(DecoratorSet decorators, Register src, Register dst, Register inline_layout_info); + void flat_field_copy(DecoratorSet decorators, Register src, Register dst, Register value_field_layout_info); - // inline type data payload offsets... - void payload_offset(Register inline_klass, Register offset); - void payload_address(Register oop, Register data, Register inline_klass); + // value type data payload offsets... + void payload_offset(Register value_klass, Register offset); + void payload_address(Register oop, Register data, Register value_klass); void load_heap_oop(Register dst, Address src, Register tmp1, Register tmp2, DecoratorSet decorators = 0); @@ -1055,7 +1055,7 @@ class MacroAssembler: public Assembler { ); void verify_tlab(); - void inline_layout_info(Register holder_klass, Register index, Register layout_info); + void value_field_layout_info(Register holder_klass, Register index, Register layout_info); // interface method calling void lookup_interface_method(Register recv_klass, @@ -1522,7 +1522,7 @@ class MacroAssembler: public Assembler { void verified_entry(Compile* C, int sp_inc); - // Inline type specific methods + // Value type specific methods #include "asm/macroAssembler_common.hpp" void save_stack_increment(int sp_inc, int frame_size); diff --git a/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp b/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp index fb130ec88ca7..2456b99cf29b 100644 --- a/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp @@ -161,11 +161,11 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth __ BIND(run_compiled_code); } - // The following jump might pass an inline type argument that was erased to Object as oop to a - // callee that expects inline type arguments to be passed as fields. We need to call the compiled - // value entry (_code->inline_entry_point() or _adapter->c2i_inline_entry()) which will take care + // The following jump might pass a value type argument that was erased to Object as oop to a + // callee that expects value type arguments to be passed as fields. We need to call the compiled + // value entry (_code->value_entry_point() or _adapter->c2i_value_entry()) which will take care // of translating between the calling conventions. - const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_inline_offset() : + const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_value_offset() : Method::from_interpreted_offset(); __ ldr(rscratch1,Address(method, entry_offset)); __ br(rscratch1); diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp index e17993b4c8ae..b56d5b332d87 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp @@ -346,12 +346,8 @@ bool NativeInstruction::is_movk() { return Instruction_aarch64::extract(int_at(0), 30, 23) == 0b11100101; } -void NativeIllegalInstruction::insert(address code_pos) { - *(juint*)code_pos = 0xd4bbd5a1; // dcps1 #0xdead -} - bool NativeInstruction::is_stop() { - return uint_at(0) == 0xd4bbd5c1; // dcps1 #0xdeae + return is_udf(udf_stop); } //------------------------------------------------------------------- @@ -398,15 +394,7 @@ void NativeDeoptInstruction::verify() { // Inserts an undefined instruction at a given pc void NativeDeoptInstruction::insert(address code_pos) { - // 1 1 0 1 | 0 1 0 0 | 1 0 1 imm16 0 0 0 0 1 - // d | 4 | a | de | 0 | 0 | - // 0xd4, 0x20, 0x00, 0x00 - uint32_t insn = 0xd4ade001; - uint32_t *pos = (uint32_t *) code_pos; - *pos = insn; - /**code_pos = 0xd4; - *(code_pos+1) = 0x60; - *(code_pos+2) = 0x00; - *(code_pos+3) = 0x00;*/ + *(uint32_t*)code_pos = udf_deopt; + assert(((NativeInstruction*)code_pos)->is_udf(udf_deopt), "incorrect UDF"); ICache::invalidate_range(code_pos, 4); } diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp index c406b471f20b..c90ac79ed30a 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp @@ -39,7 +39,6 @@ // - - NativeMovRegMem // - - NativeJump // - - - NativeGeneralJump -// - - NativeIllegalInstruction // - - NativeCallTrampolineStub // - - NativeMembar // - - NativeLdSt @@ -81,6 +80,14 @@ class NativeInstruction { bool is_movk(); bool is_stop(); + bool is_udf(uint16_t imm) { + uint32_t insn = uint_at(0); + return Instruction_aarch64::extract(insn, 31, 16) == 0 && + Instruction_aarch64::extract(insn, 15, 0) == imm; + } + + enum : uint16_t { udf_stop = 1, udf_deopt }; + protected: address addr_at(int offset) const { return address(this) + offset; } @@ -416,12 +423,6 @@ inline NativeGeneralJump* nativeGeneralJump_at(address address) { return jump; } -class NativeIllegalInstruction: public NativeInstruction { -public: - // Insert illegal opcode as specific address - static void insert(address code_pos); -}; - inline bool NativeInstruction::is_nop() const{ uint32_t insn = *(uint32_t*)addr_at(0); return insn == 0xd503201f; @@ -621,8 +622,7 @@ class NativeDeoptInstruction: public NativeInstruction { static bool is_deopt_at(address instr) { assert(instr != nullptr, ""); - uint32_t value = *(uint32_t *) instr; - return value == 0xd4ade001; + return nativeInstruction_at(instr)->is_udf(udf_deopt); } // MT-safe patching diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index e2b8e1a1ed94..2a0dc58aa09c 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -464,25 +464,25 @@ static void patch_callers_callsite(MacroAssembler *masm) { __ bind(L); } -// For each inline type argument, sig includes the list of fields of -// the inline type. This utility function computes the number of -// arguments for the call if inline types are passed by reference (the +// For each value type argument, sig includes the list of fields of +// the value type. This utility function computes the number of +// arguments for the call if value types are passed by reference (the // calling convention the interpreter expects). static int compute_total_args_passed_int(const GrowableArray* sig_extended) { int total_args_passed = 0; - if (InlineTypePassFieldsAsArgs) { + if (ValueTypePassFieldsAsArgs) { for (int i = 0; i < sig_extended->length(); i++) { BasicType bt = sig_extended->at(i)._bt; if (bt == T_METADATA) { - // In sig_extended, an inline type argument starts with: + // In sig_extended, a value type argument starts with: // T_METADATA, followed by the types of the fields of the - // inline type and T_VOID to mark the end of the value - // type. Inline types are flattened so, for instance, in the - // case of an inline type with an int field and an inline type + // value type and T_VOID to mark the end of the value + // type. Value types are flattened so, for instance, in the + // case of a value type with an int field and a value type // field that itself has 2 fields, an int and a long: // T_METADATA T_INT T_METADATA T_INT T_LONG T_VOID (second - // slot for the T_LONG) T_VOID (inner inline type) T_VOID - // (outer inline type) + // slot for the T_LONG) T_VOID (inner value type) T_VOID + // (outer value type) total_args_passed++; int vt = 1; do { @@ -619,8 +619,8 @@ static void gen_c2i_adapter(MacroAssembler *masm, // anything except r0-r7 which are arguments in the Java calling // convention, rmethod (r12), and r19 which holds the outgoing sender // SP for the interpreter. - Register buf_array = r10; // Array of buffered inline types - Register buf_oop = r11; // Buffered inline type oop + Register buf_array = r10; // Array of buffered value types + Register buf_oop = r11; // Buffered value type oop Register tmp1 = r15; Register tmp2 = r16; Register tmp3 = r17; @@ -634,13 +634,13 @@ static void gen_c2i_adapter(MacroAssembler *masm, assert(clobbered_gp_regs.contains(tmp3), "tmp3 must be saved explicitly if it's not a clobber"); #endif - if (InlineTypePassFieldsAsArgs) { - // Is there an inline type argument? - bool has_inline_argument = false; - for (int i = 0; i < sig_extended->length() && !has_inline_argument; i++) { - has_inline_argument = (sig_extended->at(i)._bt == T_METADATA); + if (ValueTypePassFieldsAsArgs) { + // Is there a value type argument? + bool has_value_argument = false; + for (int i = 0; i < sig_extended->length() && !has_value_argument; i++) { + has_value_argument = (sig_extended->at(i)._bt == T_METADATA); } - if (has_inline_argument) { + if (has_value_argument) { // There is at least a value type argument: we're coming from // compiled code so we may not have buffers to back the value // objects. Allocate the buffers here with a runtime call for @@ -658,7 +658,7 @@ static void gen_c2i_adapter(MacroAssembler *masm, __ mov(c_rarg1, rmethod); __ mov(c_rarg2, (int64_t)alloc_inline_receiver); - __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::allocate_inline_types))); + __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::allocate_value_types))); __ blr(rscratch1); __ bind(retaddr); @@ -699,22 +699,22 @@ static void gen_c2i_adapter(MacroAssembler *masm, // Now write the args into the outgoing interpreter space // next_arg_comp is the next argument from the compiler point of - // view (inline type fields are passed in registers/on the stack). In - // sig_extended, an inline type argument starts with: T_METADATA, - // followed by the types of the fields of the inline type and T_VOID - // to mark the end of the inline type. ignored counts the number of - // T_METADATA/T_VOID. next_vt_arg is the next inline type argument: + // view (value type fields are passed in registers/on the stack). In + // sig_extended, a value type argument starts with: T_METADATA, + // followed by the types of the fields of the value type and T_VOID + // to mark the end of the value type. ignored counts the number of + // T_METADATA/T_VOID. next_vt_arg is the next value type argument: // used to get the buffer for that argument from the pool of buffers // we allocated above and want to pass to the // interpreter. next_arg_int is the next argument from the - // interpreter point of view (inline types are passed by reference). + // interpreter point of view (value types are passed by reference). for (int next_arg_comp = 0, ignored = 0, next_vt_arg = 0, next_arg_int = 0; next_arg_comp < sig_extended->length(); next_arg_comp++) { assert(ignored <= next_arg_comp, "shouldn't skip over more slots than there are arguments"); assert(next_arg_int <= total_args_passed, "more arguments for the interpreter than expected?"); BasicType bt = sig_extended->at(next_arg_comp)._bt; int st_off = (total_args_passed - next_arg_int - 1) * Interpreter::stackElementSize; - if (!InlineTypePassFieldsAsArgs || bt != T_METADATA) { + if (!ValueTypePassFieldsAsArgs || bt != T_METADATA) { int next_off = st_off - Interpreter::stackElementSize; const int offset = (bt == T_LONG || bt == T_DOUBLE) ? next_off : st_off; const VMRegPair reg_pair = regs[next_arg_comp-ignored]; @@ -734,10 +734,10 @@ static void gen_c2i_adapter(MacroAssembler *masm, next_arg_int++; int vt = 1; // write fields we get from compiled code in registers/stack - // slots to the buffer: we know we are done with that inline type + // slots to the buffer: we know we are done with that value type // argument when we hit the T_VOID that acts as an end of inline - // type delimiter for this inline type. Inline types are flattened - // so we might encounter embedded inline types. Each entry in + // type delimiter for this value type. Value types are flattened + // so we might encounter embedded value types. Each entry in // sig_extended contains a field offset in the buffer. Label L_null; Label not_null_buffer; @@ -767,7 +767,7 @@ static void gen_c2i_adapter(MacroAssembler *masm, } else { int off = sig_extended->at(next_arg_comp)._offset; if (off == -1) { - // Nullable inline type argument, emit null check + // Nullable value type argument, emit null check VMReg reg = regs[next_arg_comp-ignored].first(); Label L_notNull; if (reg->is_stack()) { @@ -841,7 +841,7 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, int comp_args_on_stack // Will jump to the compiled code just as if compiled code was doing it. // Pre-load the register-jump target early, to schedule it better. - __ ldr(rscratch1, Address(rmethod, in_bytes(Method::from_compiled_inline_offset()))); + __ ldr(rscratch1, Address(rmethod, in_bytes(Method::from_compiled_value_offset()))); int total_args_passed = sig->length(); @@ -978,7 +978,7 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler* masm, // compiled code, which relies solely on SP and not FP, get sick). entry_address[AdapterBlob::C2I_Unverified] = __ pc(); - entry_address[AdapterBlob::C2I_Unverified_Inline] = __ pc(); + entry_address[AdapterBlob::C2I_Unverified_Value] = __ pc(); Label skip_fixup; gen_inline_cache_check(masm, skip_fixup); @@ -989,7 +989,7 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler* masm, // Scalarized c2i adapter with non-scalarized receiver (i.e., don't pack receiver) entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr; - entry_address[AdapterBlob::C2I_Inline_RO] = __ pc(); + entry_address[AdapterBlob::C2I_Value_RO] = __ pc(); if (regs_cc != regs_cc_ro) { // No class init barrier needed because method is guaranteed to be non-static gen_c2i_adapter(masm, sig_cc_ro, regs_cc_ro, /* requires_clinit_barrier = */ false, entry_address[AdapterBlob::C2I_No_Clinit_Check], @@ -998,20 +998,20 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler* masm, } // Scalarized c2i adapter - entry_address[AdapterBlob::C2I] = __ pc(); - entry_address[AdapterBlob::C2I_Inline] = __ pc(); + entry_address[AdapterBlob::C2I] = __ pc(); + entry_address[AdapterBlob::C2I_Value] = __ pc(); gen_c2i_adapter(masm, sig_cc, regs_cc, /* requires_clinit_barrier = */ true, entry_address[AdapterBlob::C2I_No_Clinit_Check], skip_fixup, entry_address[AdapterBlob::I2C], oop_maps, frame_complete, frame_size_in_words, /* alloc_inline_receiver = */ true); // Non-scalarized c2i adapter if (regs != regs_cc) { - entry_address[AdapterBlob::C2I_Unverified_Inline] = __ pc(); - Label inline_entry_skip_fixup; - gen_inline_cache_check(masm, inline_entry_skip_fixup); + entry_address[AdapterBlob::C2I_Unverified_Value] = __ pc(); + Label value_entry_skip_fixup; + gen_inline_cache_check(masm, value_entry_skip_fixup); - entry_address[AdapterBlob::C2I_Inline] = __ pc(); + entry_address[AdapterBlob::C2I_Value] = __ pc(); gen_c2i_adapter(masm, sig, regs, /* requires_clinit_barrier = */ true, entry_address[AdapterBlob::C2I_No_Clinit_Check], - inline_entry_skip_fixup, entry_address[AdapterBlob::I2C], oop_maps, frame_complete, frame_size_in_words, /* alloc_inline_receiver = */ false); + value_entry_skip_fixup, entry_address[AdapterBlob::I2C], oop_maps, frame_complete, frame_size_in_words, /* alloc_inline_receiver = */ false); } // The c2i adapters might safepoint and trigger a GC. The caller must make sure that @@ -2906,8 +2906,8 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(StubId id, address destination return rs_blob; } -BufferedInlineTypeBlob* SharedRuntime::generate_buffered_inline_type_adapter(const InlineKlass* vk) { - CodeBuffer buffer("inline types pack/unpack", 16 * K, 0); +BufferedValueTypeBlob* SharedRuntime::generate_buffered_value_type_adapter(const ValueKlass* vk) { + CodeBuffer buffer("value types pack/unpack", 16 * K, 0); if (buffer.blob() == nullptr) { return nullptr; } @@ -3052,7 +3052,7 @@ BufferedInlineTypeBlob* SharedRuntime::generate_buffered_inline_type_adapter(con // Code will be copied. No ICache sync required. - return BufferedInlineTypeBlob::create(&buffer, pack_fields_off, pack_fields_jobject_off, unpack_fields_off); + return BufferedValueTypeBlob::create(&buffer, pack_fields_off, pack_fields_jobject_off, unpack_fields_off); } // Continuation point for throwing of implicit exceptions that are @@ -3166,9 +3166,9 @@ RuntimeStub* SharedRuntime::generate_throw_exception(StubId id, address runtime_ } // Call here from the interpreter or compiled code to store returned -// values to a newly allocated inline type instance. +// values to a newly allocated value type instance. RuntimeStub* SharedRuntime::generate_return_value_stub(address destination) { - StubId id = StubId::shared_store_inline_type_fields_to_buf_id; + StubId id = StubId::shared_store_value_type_fields_to_buf_id; const char* name = SharedRuntime::stub_name(id); CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::SharedBlob, StubInfo::blob(id)); @@ -3282,14 +3282,14 @@ RuntimeStub* SharedRuntime::generate_return_value_stub(address destination) { __ ldr(rscratch1, Address(rthread, in_bytes(Thread::pending_exception_offset()))); __ cbnz(rscratch1, pending); - // We just called SharedRuntime::store_inline_type_fields_to_buf. Check if we still - // need to initialize the buffer and if so, call the inline class specific pack handler. + // We just called SharedRuntime::store_value_type_fields_to_buf. Check if we still + // need to initialize the buffer and if so, call the value class specific pack handler. Label skip_pack; __ get_vm_result_oop(r0, rthread); __ get_vm_result_metadata(rscratch1, rthread); __ cbz(rscratch1, skip_pack); - __ ldr(rscratch1, Address(rscratch1, InlineKlass::adr_members_offset())); - __ ldr(rscratch1, Address(rscratch1, InlineKlass::pack_handler_offset())); + __ ldr(rscratch1, Address(rscratch1, ValueKlass::adr_members_offset())); + __ ldr(rscratch1, Address(rscratch1, ValueKlass::pack_handler_offset())); __ blr(rscratch1); __ membar(Assembler::StoreStore); __ bind(skip_pack); @@ -3324,6 +3324,13 @@ static void jfr_epilogue(MacroAssembler* masm) { // It returns a jobject handle to the event writer. // The handle is dereferenced and the return value is the event writer oop. RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { + StubId id = StubId::shared_jfr_write_checkpoint_id; + + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::SharedBlob, StubInfo::blob(id)); + if (blob != nullptr) { + return blob->as_runtime_stub(); + } + enum layout { rbp_off, rbpH_off, @@ -3334,7 +3341,7 @@ RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { int insts_size = 1024; int locs_size = 64; - const char* name = SharedRuntime::stub_name(StubId::shared_jfr_write_checkpoint_id); + const char* name = SharedRuntime::stub_name(id); CodeBuffer code(name, insts_size, locs_size); OopMapSet* oop_maps = new OopMapSet(); MacroAssembler* masm = new MacroAssembler(&code); @@ -3357,11 +3364,19 @@ RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { RuntimeStub::new_runtime_stub(name, &code, frame_complete, (framesize >> (LogBytesPerWord - LogBytesPerInt)), oop_maps, false); + AOTCodeCache::store_code_blob(*stub, AOTCodeEntry::SharedBlob, StubInfo::blob(id)); return stub; } // For c2: call to return a leased buffer. RuntimeStub* SharedRuntime::generate_jfr_return_lease() { + StubId id = StubId::shared_jfr_return_lease_id; + + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::SharedBlob, StubInfo::blob(id)); + if (blob != nullptr) { + return blob->as_runtime_stub(); + } + enum layout { rbp_off, rbpH_off, @@ -3373,7 +3388,7 @@ RuntimeStub* SharedRuntime::generate_jfr_return_lease() { int insts_size = 1024; int locs_size = 64; - const char* name = SharedRuntime::stub_name(StubId::shared_jfr_return_lease_id); + const char* name = SharedRuntime::stub_name(id); CodeBuffer code(name, insts_size, locs_size); OopMapSet* oop_maps = new OopMapSet(); MacroAssembler* masm = new MacroAssembler(&code); @@ -3396,6 +3411,7 @@ RuntimeStub* SharedRuntime::generate_jfr_return_lease() { RuntimeStub::new_runtime_stub(name, &code, frame_complete, (framesize >> (LogBytesPerWord - LogBytesPerInt)), oop_maps, false); + AOTCodeCache::store_code_blob(*stub, AOTCodeEntry::SharedBlob, StubInfo::blob(id)); return stub; } diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index ca78fc0952f2..14cf4b089894 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -504,9 +504,9 @@ class StubGenerator: public StubCodeGenerator { // T_OBJECT, T_LONG, T_FLOAT or T_DOUBLE is treated as T_INT) // n.b. this assumes Java returns an integral result in r0 // and a floating result in j_farg0 - // All of j_rargN may be used to return inline type fields so be careful + // All of j_rargN may be used to return value type fields so be careful // not to clobber those. - // SharedRuntime::generate_buffered_inline_type_adapter() knows the register + // SharedRuntime::generate_buffered_value_type_adapter() knows the register // assignment of Rresult below. Register Rresult = r14, Rresult_type = r15; __ ldr(Rresult, result); @@ -575,13 +575,13 @@ class StubGenerator: public StubCodeGenerator { // handle return types different from T_INT __ BIND(check_prim); - if (InlineTypeReturnedAsFields) { + if (ValueTypeReturnedAsFields) { // Check for scalarized return value __ tbz(r0, 0, is_long); // Load pack handler address __ andr(rscratch1, r0, -2); - __ ldr(rscratch1, Address(rscratch1, InlineKlass::adr_members_offset())); - __ ldr(rscratch1, Address(rscratch1, InlineKlass::pack_handler_jobject_offset())); + __ ldr(rscratch1, Address(rscratch1, ValueKlass::adr_members_offset())); + __ ldr(rscratch1, Address(rscratch1, ValueKlass::pack_handler_jobject_offset())); __ blr(rscratch1); __ b(exit); } @@ -2621,10 +2621,10 @@ class StubGenerator: public StubCodeGenerator { __ cbnz(rscratch2, L_failed); if (Arguments::is_valhalla_enabled()) { - // Check for flat inline type array -> return -1 + // Check for flat value type array -> return -1 __ test_flat_array_oop(src, rscratch2, L_failed); - // Check for null-free (non-flat) inline type array -> handle as object array + // Check for null-free (non-flat) value type array -> handle as object array __ test_null_free_array_oop(src, rscratch2, L_objArray); } @@ -12420,7 +12420,7 @@ class StubGenerator: public StubCodeGenerator { #endif // LINUX static void save_return_registers(MacroAssembler* masm) { - if (InlineTypeReturnedAsFields) { + if (ValueTypeReturnedAsFields) { masm->push(RegSet::range(r0, r7), sp); masm->sub(sp, sp, 4 * wordSize); masm->st1(v0, v1, v2, v3, masm->T1D, Address(sp)); @@ -12433,7 +12433,7 @@ class StubGenerator: public StubCodeGenerator { } static void restore_return_registers(MacroAssembler* masm) { - if (InlineTypeReturnedAsFields) { + if (ValueTypeReturnedAsFields) { masm->ld1(v4, v5, v6, v7, masm->T1D, Address(masm->post(sp, 4 * wordSize))); masm->ld1(v0, v1, v2, v3, masm->T1D, Address(masm->post(sp, 4 * wordSize))); masm->pop(RegSet::range(r0, r7), sp); diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp index c317629d6cc9..57e2cdc7107f 100644 --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp @@ -41,9 +41,9 @@ #include "oops/methodCounters.hpp" #include "oops/methodData.hpp" #include "oops/oop.inline.hpp" -#include "oops/inlineKlass.hpp" #include "oops/resolvedIndyEntry.hpp" #include "oops/resolvedMethodEntry.hpp" +#include "oops/valueKlass.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiThreadState.hpp" #include "runtime/arguments.hpp" @@ -469,8 +469,8 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, // and null it as marker that esp is now tos until next java call __ str(zr, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize)); - if (state == atos && InlineTypeReturnedAsFields) { - __ store_inline_type_fields_to_buf(nullptr, true); + if (state == atos && ValueTypeReturnedAsFields) { + __ store_value_type_fields_to_buf(nullptr, true); } __ restore_bcp(); diff --git a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp index 518b641e26e8..4f68356a117c 100644 --- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp @@ -2022,8 +2022,8 @@ void TemplateTable::if_acmp(Condition cc) { __ profile_acmp(r2, r1, r0, r4); - Register is_inline_type_mask = rscratch1; - __ mov(is_inline_type_mask, markWord::inline_type_pattern); + Register is_value_type_mask = rscratch1; + __ mov(is_value_type_mask, markWord::value_type_pattern); if (Arguments::is_valhalla_enabled()) { // The substitutability test is only necessary if r1 and r0 are not the same... @@ -2036,11 +2036,11 @@ void TemplateTable::if_acmp(Condition cc) { // ...and both are values... __ ldr(r2, Address(r1, oopDesc::mark_offset_in_bytes())); - __ andr(r2, r2, is_inline_type_mask); + __ andr(r2, r2, is_value_type_mask); __ ldr(r4, Address(r0, oopDesc::mark_offset_in_bytes())); - __ andr(r4, r4, is_inline_type_mask); + __ andr(r4, r4, is_value_type_mask); __ andr(r2, r2, r4); - __ cmp(r2, is_inline_type_mask); + __ cmp(r2, is_value_type_mask); __ br(Assembler::NE, (cc == equal) ? not_taken : taken); // ...with the same value klass @@ -3037,7 +3037,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr __ pop(atos); if (is_static) { Label is_nullable; - __ test_field_is_not_null_free_inline_type(flags, noreg /* temp */, is_nullable); + __ test_field_is_not_null_free_value_type(flags, noreg /* temp */, is_nullable); __ null_check(r0); // FIXME JDK-8341120 __ bind(is_nullable); do_oop_store(_masm, field, r0, IN_HEAP); @@ -3045,7 +3045,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr } else { Label null_free_reference, is_flat, rewrite_inline; __ test_field_is_flat(flags, noreg /* temp */, is_flat); - __ test_field_is_null_free_inline_type(flags, noreg /* temp */, null_free_reference); + __ test_field_is_null_free_value_type(flags, noreg /* temp */, null_free_reference); pop_and_check_object(obj); // Store into the field // Clobbers: r10, r11, r3 @@ -3054,7 +3054,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr patch_bytecode(Bytecodes::_fast_aputfield, bc, r19, true, byte_no); } __ b(Done); - // Implementation of the inline type semantic + // Implementation of the value type semantic __ bind(null_free_reference); __ null_check(r0); // FIXME JDK-8341120 pop_and_check_object(obj); @@ -4104,9 +4104,9 @@ void TemplateTable::monitorenter() // check for null object __ null_check(r0); - Label is_inline_type; + Label is_value_type; __ ldr(rscratch1, Address(r0, oopDesc::mark_offset_in_bytes())); - __ test_markword_is_inline_type(rscratch1, is_inline_type); + __ test_markword_is_value_type(rscratch1, is_value_type); const Address monitor_block_top( rfp, frame::interpreter_frame_monitor_block_top_offset * wordSize); @@ -4210,7 +4210,7 @@ void TemplateTable::monitorenter() // next instruction. __ dispatch_next(vtos); - __ bind(is_inline_type); + __ bind(is_value_type); __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_identity_exception), r0); __ should_not_reach_here(); @@ -4224,10 +4224,10 @@ void TemplateTable::monitorexit() // check for null object __ null_check(r0); - const int is_inline_type_mask = markWord::inline_type_pattern; + const int is_value_type_mask = markWord::value_type_pattern; Label has_identity; __ ldr(rscratch1, Address(r0, oopDesc::mark_offset_in_bytes())); - __ mov(rscratch2, is_inline_type_mask); + __ mov(rscratch2, is_value_type_mask); __ andr(rscratch1, rscratch1, rscratch2); __ cmp(rscratch1, rscratch2); __ br(Assembler::NE, has_identity); diff --git a/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp b/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp index c81bf733a1fb..9218135bb386 100644 --- a/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp @@ -63,7 +63,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index, bool caller_is_c1) int slop_bytes = 0; int slop_delta = 0; - ByteSize entry_offset = caller_is_c1 ? Method::from_compiled_inline_offset() : Method::from_compiled_inline_ro_offset(); + ByteSize entry_offset = caller_is_c1 ? Method::from_compiled_value_offset() : Method::from_compiled_value_ro_offset(); ResourceMark rm; CodeBuffer cb(s->entry_point(), stub_code_length); @@ -155,7 +155,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index, bool caller_is_c1) int slop_bytes = 0; int slop_delta = 0; - ByteSize entry_offset = caller_is_c1 ? Method::from_compiled_inline_offset() : Method::from_compiled_inline_ro_offset(); + ByteSize entry_offset = caller_is_c1 ? Method::from_compiled_value_offset() : Method::from_compiled_value_ro_offset(); ResourceMark rm; CodeBuffer cb(s->entry_point(), stub_code_length); diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp index a3f24592e9d2..246ee211973a 100644 --- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp @@ -2559,7 +2559,7 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { fatal("Type profiling not implemented on this platform"); } -void LIR_Assembler::emit_profile_inline_type(LIR_OpProfileInlineType* op) { +void LIR_Assembler::emit_profile_value_type(LIR_OpProfileValueType* op) { Unimplemented(); } @@ -2868,7 +2868,7 @@ void LIR_Assembler::check_orig_pc() { Unimplemented(); } -int LIR_Assembler::store_inline_type_fields_to_buf(ciInlineKlass* vk) { +int LIR_Assembler::store_value_type_fields_to_buf(ciValueKlass* vk) { Unimplemented(); return 0; } diff --git a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp index 81739b645e28..22c6c7f8fd11 100644 --- a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp @@ -45,7 +45,7 @@ void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, bool has_scalarized_args, - Label* verified_inline_entry_label) { + Label* verified_value_entry_label) { assert(bang_size_in_bytes >= frame_size_in_bytes, "stack bang size incorrect"); assert((frame_size_in_bytes % StackAlignmentInBytes) == 0, "frame size should be aligned"); @@ -220,7 +220,7 @@ void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register basic // Success: fall through } -int C1_MacroAssembler::scalarized_entry(const CompiledEntrySignature* ces, int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, Label& verified_inline_entry_label, bool is_inline_ro_entry) { +int C1_MacroAssembler::scalarized_entry(const CompiledEntrySignature* ces, int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, Label& verified_value_entry_label, bool is_value_ro_entry) { Unimplemented(); } diff --git a/src/hotspot/cpu/arm/globals_arm.hpp b/src/hotspot/cpu/arm/globals_arm.hpp index ca5f013d0447..df03f2530a10 100644 --- a/src/hotspot/cpu/arm/globals_arm.hpp +++ b/src/hotspot/cpu/arm/globals_arm.hpp @@ -73,8 +73,8 @@ define_pd_global(bool, CompactStrings, false); define_pd_global(intx, InitArrayShortSize, 8*BytesPerLong); -define_pd_global(bool, InlineTypePassFieldsAsArgs, false); -define_pd_global(bool, InlineTypeReturnedAsFields, false); +define_pd_global(bool, ValueTypePassFieldsAsArgs, false); +define_pd_global(bool, ValueTypeReturnedAsFields, false); #define ARCH_FLAGS(develop, \ product, \ diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.cpp b/src/hotspot/cpu/arm/macroAssembler_arm.cpp index ce79fc57ccd4..39f0ac2e0dbb 100644 --- a/src/hotspot/cpu/arm/macroAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/macroAssembler_arm.cpp @@ -1894,8 +1894,8 @@ void MacroAssembler::remove_frame(int frame_size_in_bytes) { raw_pop(FP, LR); } -// Unimplemented methods for inline types. -int MacroAssembler::store_inline_type_fields_to_buf(ciInlineKlass* vk, bool from_interpreter) { +// Unimplemented methods for value types. +int MacroAssembler::store_value_type_fields_to_buf(ciValueKlass* vk, bool from_interpreter) { Unimplemented(); } @@ -1903,19 +1903,19 @@ bool MacroAssembler::move_helper(VMReg from, VMReg to, BasicType bt, RegState re Unimplemented(); } -bool MacroAssembler::unpack_inline_helper(const GrowableArray* sig, int& sig_index, +bool MacroAssembler::unpack_value_helper(const GrowableArray* sig, int& sig_index, VMReg from, int& from_index, VMRegPair* to, int to_count, int& to_index, RegState reg_state[]) { Unimplemented(); } -bool MacroAssembler::pack_inline_helper(const GrowableArray* sig, int& sig_index, int vtarg_index, +bool MacroAssembler::pack_value_helper(const GrowableArray* sig, int& sig_index, int vtarg_index, VMRegPair* from, int from_count, int& from_index, VMReg to, RegState reg_state[], Register val_array) { Unimplemented(); } -int MacroAssembler::extend_stack_for_inline_args(int args_on_stack) { +int MacroAssembler::extend_stack_for_value_args(int args_on_stack) { Unimplemented(); } diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.hpp b/src/hotspot/cpu/arm/macroAssembler_arm.hpp index 59c13e05ef6f..d2f3fe87903f 100644 --- a/src/hotspot/cpu/arm/macroAssembler_arm.hpp +++ b/src/hotspot/cpu/arm/macroAssembler_arm.hpp @@ -28,7 +28,7 @@ #include "code/relocInfo.hpp" #include "utilities/powerOfTwo.hpp" -class ciInlineKlass; +class ciValueKlass; class SigEntry; class VMRegPair; @@ -1086,7 +1086,7 @@ class MacroAssembler: public Assembler { static int ic_check_size(); int ic_check(int end_alignment); - // Inline type specific methods + // Value type specific methods #include "asm/macroAssembler_common.hpp" void remove_frame(int initial_framesize); diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index ed4d9c8f2e73..8327d3b47c3d 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -351,7 +351,7 @@ int SharedRuntime::c_calling_convention(const BasicType *sig_bt, return slot; } -// InlineTypeReturnedAsFields is disabled, so we need to only care about the single return value +// ValueTypeReturnedAsFields is disabled, so we need to only care about the single return value // in this calling convention. const uint SharedRuntime::java_return_convention_max_int = 1; const uint SharedRuntime::java_return_convention_max_float = 1; @@ -707,7 +707,7 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler* masm, gen_i2c_adapter(masm, comp_args_on_stack, sig, regs); entry_address[AdapterBlob::C2I_Unverified] = __ pc(); - entry_address[AdapterBlob::C2I_Unverified_Inline] = __ pc(); + entry_address[AdapterBlob::C2I_Unverified_Value] = __ pc(); Label skip_fixup; const Register receiver = R0; const Register holder_klass = Rtemp; // XXX should be OK for C2 but not 100% sure @@ -721,8 +721,8 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler* masm, __ jump(SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type, noreg, ne); entry_address[AdapterBlob::C2I] = __ pc(); - entry_address[AdapterBlob::C2I_Inline] = __ pc(); - entry_address[AdapterBlob::C2I_Inline_RO] = __ pc(); + entry_address[AdapterBlob::C2I_Value] = __ pc(); + entry_address[AdapterBlob::C2I_Value_RO] = __ pc(); entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr; gen_c2i_adapter(masm, comp_args_on_stack, sig, regs, skip_fixup); @@ -1943,13 +1943,13 @@ RuntimeStub* SharedRuntime::generate_jfr_return_lease() { #endif // INCLUDE_JFR -BufferedInlineTypeBlob* SharedRuntime::generate_buffered_inline_type_adapter(const InlineKlass* vk) { +BufferedValueTypeBlob* SharedRuntime::generate_buffered_value_type_adapter(const ValueKlass* vk) { Unimplemented(); return nullptr; } // Call here from the interpreter or compiled code to store returned -// values to a newly allocated inline type instance. +// values to a newly allocated value type instance. RuntimeStub* SharedRuntime::generate_return_value_stub(address destination) { Unimplemented(); return nullptr; diff --git a/src/hotspot/cpu/arm/vm_version_arm_32.cpp b/src/hotspot/cpu/arm/vm_version_arm_32.cpp index ef845a0da2ab..6d653ac3fd89 100644 --- a/src/hotspot/cpu/arm/vm_version_arm_32.cpp +++ b/src/hotspot/cpu/arm/vm_version_arm_32.cpp @@ -350,13 +350,13 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseUnalignedAccesses, false); } - if (InlineTypePassFieldsAsArgs) { - warning("InlineTypePassFieldsAsArgs is not supported on this CPU"); - FLAG_SET_DEFAULT(InlineTypePassFieldsAsArgs, false); + if (ValueTypePassFieldsAsArgs) { + warning("ValueTypePassFieldsAsArgs is not supported on this CPU"); + FLAG_SET_DEFAULT(ValueTypePassFieldsAsArgs, false); } - if (InlineTypeReturnedAsFields) { - warning("InlineTypeReturnedAsFields is not supported on this CPU"); - FLAG_SET_DEFAULT(InlineTypeReturnedAsFields, false); + if (ValueTypeReturnedAsFields) { + warning("ValueTypeReturnedAsFields is not supported on this CPU"); + FLAG_SET_DEFAULT(ValueTypeReturnedAsFields, false); } if (UseArrayFlattening) { warning("UseArrayFlattening is not supported on this CPU"); diff --git a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp index 74a8e17dd700..26326eca63c7 100644 --- a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp @@ -340,7 +340,7 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); if (_throw_ie_stub != nullptr) { // When we come here, _obj_reg has already been checked to be non-null. - const int is_value_mask = markWord::inline_type_pattern; + const int is_value_mask = markWord::value_type_pattern; __ ld(R0, oopDesc::mark_offset_in_bytes(), _obj_reg->as_register()); __ andi(R0, R0, is_value_mask); __ cmpdi(CR0, R0, is_value_mask); diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index cd9bb80d9507..4ee77770acaa 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -664,7 +664,7 @@ int LIR_Assembler::store(LIR_Opr from_reg, Register base, int offset, BasicType if (UseCompressedOops && !wide) { // Encoding done in caller __ stw(from_reg->as_register(), offset, base); - __ verify_coop(from_reg->as_register(), FILE_AND_LINE); + __ verify_oop(from_reg->as_register(), FILE_AND_LINE, /*compressed*/ true); // kills R0 } else { __ std(from_reg->as_register(), offset, base); if (VerifyOops) { @@ -708,7 +708,7 @@ int LIR_Assembler::store(LIR_Opr from_reg, Register base, Register disp, BasicTy if (UseCompressedOops && !wide) { // Encoding done in caller. __ stwx(from_reg->as_register(), base, disp); - __ verify_coop(from_reg->as_register(), FILE_AND_LINE); // kills R0 + __ verify_oop(from_reg->as_register(), FILE_AND_LINE, /*compressed*/ true); // kills R0 } else { __ stdx(from_reg->as_register(), base, disp); if (VerifyOops) { @@ -1246,7 +1246,7 @@ void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) { const Register return_pc = R31; // Must survive C-call to enable_stack_reserved_zone(). const Register temp = R12; - assert(!InlineTypeReturnedAsFields, "unimplemented"); + assert(!ValueTypeReturnedAsFields, "unimplemented"); // Pop the stack before the safepoint code. int frame_size = initial_frame_size_in_bytes(); @@ -1777,7 +1777,7 @@ void LIR_Assembler::unwind_op(LIR_Opr exceptionOop) { } -void LIR_Assembler::arraycopy_inlinetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check) { +void LIR_Assembler::arraycopy_valuetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check) { if (null_check) { __ cmpdi(CR0, obj, 0); __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CR0, Assembler::equal), *slow_path->entry()); @@ -1853,12 +1853,12 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { return; } - // Handle inline type arrays - if (flags & LIR_OpArrayCopy::src_inlinetype_check) { - arraycopy_inlinetype_check(src, tmp, stub, false, (flags & LIR_OpArrayCopy::src_null_check)); + // Handle value type arrays + if (flags & LIR_OpArrayCopy::src_valuetype_check) { + arraycopy_valuetype_check(src, tmp, stub, false, (flags & LIR_OpArrayCopy::src_null_check)); } - if (flags & LIR_OpArrayCopy::dst_inlinetype_check) { - arraycopy_inlinetype_check(dst, tmp, stub, true, (flags & LIR_OpArrayCopy::dst_null_check)); + if (flags & LIR_OpArrayCopy::dst_valuetype_check) { + arraycopy_valuetype_check(dst, tmp, stub, true, (flags & LIR_OpArrayCopy::dst_null_check)); } assert(default_type != nullptr && default_type->is_array_klass() && default_type->is_loaded(), "must be true at this point"); @@ -2415,12 +2415,16 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { CodeStub* stub = op->stub(); // Check if it needs to be profiled. ciMethodData* md = nullptr; + Register mdo = noreg; ciProfileData* data = nullptr; int mdo_offset_bias = 0; if (should_profile) { ciMethod* method = op->profiled_method(); assert(method != nullptr, "Should have method"); setup_md_access(method, op->profiled_bci(), md, data, mdo_offset_bias); + mdo = k_RInfo; + metadata2reg(md->constant_encoding(), mdo); + __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0); } Label done; @@ -2428,26 +2432,26 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { if (op->need_null_check()) { if (should_profile) { Label not_null; - Register mdo = k_RInfo; Register data_val = Rtmp1; - metadata2reg(md->constant_encoding(), mdo); - __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0); __ cmpdi(CR0, value, 0); __ bne(CR0, not_null); + // Object is null, update mdo and exit __ lbz(data_val, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias, mdo); __ ori(data_val, data_val, BitData::null_seen_byte_constant()); __ stb(data_val, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias, mdo); __ b(done); __ bind(not_null); - - Register recv = klass_RInfo; - __ load_klass(recv, value); - type_profile_helper(mdo, mdo_offset_bias, md, data, recv, Rtmp1); // kills recv } else { __ cmpdi(CR0, value, 0); __ beq(CR0, done); } } + if (should_profile) { + Register recv = klass_RInfo; + __ load_klass(recv, value); + type_profile_helper(mdo, mdo_offset_bias, md, data, recv, Rtmp1); // kills recv + } + if (!os::zero_page_read_protected() || !ImplicitNullChecks) { explicit_null_check(array, op->info_for_exception()); } else { @@ -3070,7 +3074,7 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { __ bind(Ldone); } -void LIR_Assembler::emit_profile_inline_type(LIR_OpProfileInlineType* op) { +void LIR_Assembler::emit_profile_value_type(LIR_OpProfileValueType* op) { Register obj = op->obj()->as_register(); //Register tmp = op->tmp()->as_pointer_register(); not needed! LIR_Address* mdo_addr = op->mdp()->as_address_ptr(); @@ -3080,14 +3084,14 @@ void LIR_Assembler::emit_profile_inline_type(LIR_OpProfileInlineType* op) { bool not_null = op->not_null(); int flag = op->flag(); - Label not_inline_type; - __ test_oop_is_not_inline_type(obj, not_inline_type, !not_null); + Label not_value_type; + __ test_oop_is_not_value_type(obj, not_value_type, !not_null); __ lbz(R0, mdo_offs, mdo_base); __ ori(R0, R0, flag); __ stb(R0, mdo_offs, mdo_base); - __ bind(not_inline_type); + __ bind(not_value_type); } void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) { @@ -3113,8 +3117,8 @@ void LIR_Assembler::check_orig_pc() { __ cmpdi(BOOL_RESULT, R0, (u1)NULL_WORD); } -int LIR_Assembler::store_inline_type_fields_to_buf(ciInlineKlass* vk) { - return (__ store_inline_type_fields_to_buf(vk, false)); +int LIR_Assembler::store_value_type_fields_to_buf(ciValueKlass* vk) { + return (__ store_value_type_fields_to_buf(vk, false)); } void LIR_Assembler::emit_opFlattenedArrayCheck(LIR_OpFlattenedArrayCheck* op) { @@ -3154,23 +3158,23 @@ void LIR_Assembler::emit_opSubstitutabilityCheck(LIR_OpSubstitutabilityCheck* op ciKlass* left_klass = op->left_klass(); ciKlass* right_klass = op->right_klass(); - // (2) Inline type check -- if either of the operands is not an inline type, + // (2) Value type check -- if either of the operands is not a value type, // they are not substitutable. We do this only if we are not sure that the - // operands are inline type + // operands are value type if ((left_klass == nullptr || right_klass == nullptr) ||// The klass is still unloaded, or came from a Phi node. - !left_klass->is_inlinetype() || !right_klass->is_inlinetype()) { + !left_klass->is_value_klass() || !right_klass->is_value_klass()) { Register tmp = op->tmp1()->as_register(); __ ld(tmp, oopDesc::mark_offset_in_bytes(), left); __ ld(R0, oopDesc::mark_offset_in_bytes(), right); - __ andi(tmp, tmp, (intptr_t)markWord::inline_type_pattern); + __ andi(tmp, tmp, (intptr_t)markWord::value_type_pattern); __ andr(tmp, tmp, R0); - __ cmpdi(CR0, tmp, (intptr_t)markWord::inline_type_pattern); + __ cmpdi(CR0, tmp, (intptr_t)markWord::value_type_pattern); __ bne(CR0, L_oops_not_equal); } // (3) Same klass check: if the operands are of different klasses, they are not substitutable. - if (left_klass != nullptr && left_klass->is_inlinetype() && left_klass == right_klass) { - // No need to load klass -- the operands are statically known to be the same inline klass. + if (left_klass != nullptr && left_klass->is_value_klass() && left_klass == right_klass) { + // No need to load klass -- the operands are statically known to be the same value klass. __ b(*op->stub()->entry()); } else { Register tmp1 = op->tmp1()->as_register(); diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.hpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.hpp index e7f796009201..a1eacba24106 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.hpp @@ -66,7 +66,7 @@ enum { _deopt_handler_size = MacroAssembler::bl64_patchable_size + BytesPerInstWord }; - void arraycopy_inlinetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check); + void arraycopy_valuetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check); // '_static_call_stub_size' is only used on ppc (see LIR_Assembler::emit_static_call_stub() // in c1_LIRAssembler_ppc.cpp. The other, shared getters are defined in c1_LIRAssembler.hpp diff --git a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp index 5fa10dcbfc90..0e5dcdd815f6 100644 --- a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp @@ -32,14 +32,15 @@ #include "c1/c1_Runtime1.hpp" #include "c1/c1_ValueStack.hpp" #include "ci/ciArray.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciObjArrayKlass.hpp" #include "ci/ciTypeArrayKlass.hpp" +#include "ci/ciValueKlass.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/vm_version.hpp" #include "utilities/powerOfTwo.hpp" #include "vmreg_ppc.inline.hpp" + #include #ifdef ASSERT @@ -353,7 +354,7 @@ void LIRGenerator::do_MonitorEnter(MonitorEnter* x) { } CodeStub* throw_ie_stub = - x->maybe_inlinetype() ? + x->maybe_valuetype() ? new SimpleExceptionStub(StubId::c1_throw_identity_exception_id, obj.result(), state_for(x)) : nullptr; @@ -844,7 +845,7 @@ void LIRGenerator::do_NewInstance(NewInstance* x) { LIR_Opr tmp2 = FrameMap::R6_oop_opr; LIR_Opr tmp3 = FrameMap::R7_oop_opr; LIR_Opr tmp4 = FrameMap::R8_oop_opr; - new_instance(reg, x->klass(), x->is_unresolved(), !x->is_unresolved() && x->klass()->is_inlinetype(), + new_instance(reg, x->klass(), x->is_unresolved(), !x->is_unresolved() && x->klass()->is_value_klass(), tmp1, tmp2, tmp3, tmp4, klass_reg, info); // Must prevent reordering of stores for object initialization diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp index 7c3f43fa8006..5b71f05b5821 100644 --- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp @@ -66,7 +66,7 @@ void C1_MacroAssembler::build_frame_helper(int frame_size_in_bytes, int sp_offse void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, bool has_scalarized_args, - Label* verified_inline_entry_label) { + Label* verified_value_entry_label) { // Make sure there is enough stack space for this method's activation. assert(bang_size_in_bytes >= frame_size_in_bytes, "stack bang size incorrect"); generate_stack_overflow_check(bang_size_in_bytes); @@ -76,9 +76,9 @@ void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_by BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); bs->nmethod_entry_barrier(this, R20); - if (verified_inline_entry_label != nullptr) { + if (verified_value_entry_label != nullptr) { // Jump here from the scalarized entry points that already created the frame. - bind(*verified_inline_entry_label); + bind(*verified_value_entry_label); } } @@ -363,6 +363,6 @@ void C1_MacroAssembler::null_check(Register r, Label* Lnull) { } } -int C1_MacroAssembler::scalarized_entry(const CompiledEntrySignature* ces, int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, Label& verified_inline_entry_label, bool is_inline_ro_entry) { +int C1_MacroAssembler::scalarized_entry(const CompiledEntrySignature* ces, int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, Label& verified_value_entry_label, bool is_value_ro_entry) { Unimplemented(); } diff --git a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp index b79491f0636e..c329a89850b9 100644 --- a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp @@ -455,13 +455,13 @@ OopMapSet* Runtime1::generate_code_for(StubId id, StubAssembler* sasm) { __ cmpwi(CR0, R0, Klass::_lh_array_tag_ref_value); // new "[Ljava/lang/Object;" __ cmpwi(CR1, R0, Klass::_lh_array_tag_flat_value); // new "[LVT;" __ cror(CR0, Assembler::equal, CR1, Assembler::equal); - __ asm_assert_eq("assert(is an object or inline type array klass)"); + __ asm_assert_eq("assert(is an object or value type array klass)"); break; case StubId::c1_new_null_free_array_id: __ cmpwi(CR0, R0, Klass::_lh_array_tag_flat_value); // the array can be a flat array. __ cmpwi(CR1, R0, Klass::_lh_array_tag_ref_value); // the array cannot be a flat array (due to the InlineArrayElementMaxFlatSize, etc.) __ cror(CR0, Assembler::equal, CR1, Assembler::equal); - __ asm_assert_eq("assert(is an object or inline type array klass)"); + __ asm_assert_eq("assert(is an object or value type array klass)"); break; default: ShouldNotReachHere(); } @@ -490,14 +490,14 @@ OopMapSet* Runtime1::generate_code_for(StubId id, StubAssembler* sasm) { } break; - case StubId::c1_buffer_inline_args_id: - case StubId::c1_buffer_inline_args_no_receiver_id: + case StubId::c1_buffer_value_args_id: + case StubId::c1_buffer_value_args_no_receiver_id: { - address entry = (id == StubId::c1_buffer_inline_args_id) ? - CAST_FROM_FN_PTR(address, buffer_inline_args) : - CAST_FROM_FN_PTR(address, buffer_inline_args_no_receiver); + address entry = (id == StubId::c1_buffer_value_args_id) ? + CAST_FROM_FN_PTR(address, buffer_value_args) : + CAST_FROM_FN_PTR(address, buffer_value_args_no_receiver); - __ unimplemented("c1_buffer_inline_args"); // TODO: handle arguments and return value + __ unimplemented("c1_buffer_value_args"); // TODO: handle arguments and return value OopMap* oop_map = save_live_registers(sasm); int call_offset = __ call_RT(noreg, noreg, entry, R3_ARG1); diff --git a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp index fb4213e9b538..d25d587c9151 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp @@ -339,7 +339,7 @@ inline frame frame::sender_for_compiled_frame(RegisterMap *map) const { #ifdef COMPILER1 DEBUG_ONLY(nmethod* nm = _cb->as_nmethod_or_null()); assert(nm == nullptr || !nm->is_compiled_by_c1() || !nm->method()->has_scalarized_args() || - pc() >= nm->verified_inline_entry_point(), "unsupported"); + pc() >= nm->verified_value_entry_point(), "unsupported"); #endif if (!_cb->is_nmethod()) { // compiled frames do not use callee-saved registers map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread())); diff --git a/src/hotspot/cpu/ppc/gc/g1/g1_ppc.ad b/src/hotspot/cpu/ppc/gc/g1/g1_ppc.ad index 0a4a94428558..edf36edec97c 100644 --- a/src/hotspot/cpu/ppc/gc/g1/g1_ppc.ad +++ b/src/hotspot/cpu/ppc/gc/g1/g1_ppc.ad @@ -1,6 +1,6 @@ // -// Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. -// Copyright (c) 2025 SAP SE. All rights reserved. +// Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2025, 2026 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 @@ -73,6 +73,136 @@ static void post_write_barrier(MacroAssembler* masm, g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, tmp1, tmp2, new_val_may_be_null, decode_new_val); } + + static void extract_narrow_oop(MacroAssembler* masm, Register dst, Register src, int off) { +#ifdef VM_LITTLE_ENDIAN + // offset 0 corresponds to the low word in the register. + if (off == 0) { + __ clrldi(dst, src, 32); // zero high word + } else { + precond(off == 4); + __ srdi(dst, src, 32); // shift right 32 bits and zero high word + } +#else + // offset 0 corresponds to the high word in the register. + if (off == 0) { + __ srdi(dst, src, 32); // shift right 32 bits and zero high word + } else { + precond(off == 4); + __ clrldi(dst, src, 32); // zero high word + } +#endif + } + +%} + +// TODO 8350865 (same applies to g1StoreLSpecialTwoOops) +// - Do not set/overwrite barrier data here, also handle G1C2BarrierPostNotNull +instruct g1StoreLSpecialOneOopOff0(indirect mem, iRegLsrc src, immI_0 off, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3, flagsRegCR0 cr0) +%{ + predicate(UseG1GC); + match(Set mem (StoreLSpecial mem (Binary src off))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr0); + ins_cost(2 * MEMORY_REF_COST); + format %{ "std $mem, $src\t# g1StoreLSpecialOneOopOff0" %} + ins_encode %{ + ((MachNode*)this)->set_barrier_data(G1C2BarrierPre | G1C2BarrierPost); + pre_write_barrier(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + + __ std($src$$Register, 0, $mem$$Register); + + extract_narrow_oop(masm, $tmp1$$Register, $src$$Register, 0); + __ decode_heap_oop($tmp1$$Register); + post_write_barrier(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_class_default); +%} + +instruct g1StoreLSpecialOneOopOff4(indirect mem, iRegLsrc src, immI_4 off, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3, iRegPdst tmp4, flagsRegCR0 cr0) +%{ + predicate(UseG1GC); + match(Set mem (StoreLSpecial mem (Binary src off))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr0); + ins_cost(2 * MEMORY_REF_COST); + format %{ "std $mem, $src\t# g1StoreLSpecialOneOopOff4" %} + ins_encode %{ + ((MachNode*)this)->set_barrier_data(G1C2BarrierPre | G1C2BarrierPost); + + // Adjust address to point to the narrow oop at offset 4. + __ addi($tmp4$$Register, $mem$$Register, 4); + pre_write_barrier(masm, this, + $tmp4$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register, $tmp4$$Register) /* preserve */); + + __ std($src$$Register, 0, $mem$$Register); + + extract_narrow_oop(masm, $tmp1$$Register, $src$$Register, 4); + __ decode_heap_oop($tmp1$$Register); + post_write_barrier(masm, this, + $tmp4$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_class_default); +%} + +instruct g1StoreLSpecialTwoOops(indirect mem, iRegLsrc src, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3, iRegPdst tmp4, flagsRegCR0 cr0) +%{ + predicate(UseG1GC); + match(Set mem (StoreLSpecial mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr0); + ins_cost(2 * MEMORY_REF_COST); + format %{ "std $mem, $src\t# g1StoreLSpecialTwoOops" %} + ins_encode %{ + ((MachNode*)this)->set_barrier_data(G1C2BarrierPre | G1C2BarrierPost); + + // Issue 2 pre-barriers for oops at offset 0 and 4 + pre_write_barrier(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ addi($tmp4$$Register, $mem$$Register, 4); + pre_write_barrier(masm, this, + $tmp4$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register, $tmp4$$Register) /* preserve */); + + __ std($src$$Register, 0, $mem$$Register); + + extract_narrow_oop(masm, $tmp1$$Register, $src$$Register, 0); + __ decode_heap_oop($tmp1$$Register); + post_write_barrier(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + + extract_narrow_oop(masm, $tmp1$$Register, $src$$Register, 4); + __ decode_heap_oop($tmp1$$Register); + post_write_barrier(masm, this, + $tmp4$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_class_default); %} instruct g1StoreP(indirect mem, iRegPsrc src, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp index 3ec6cb5c4a5a..8be5312b42dc 100644 --- a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp @@ -117,15 +117,15 @@ void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, } void BarrierSetAssembler::flat_field_copy(MacroAssembler* masm, DecoratorSet decorators, - Register src, Register dst, Register inline_layout_info) { + Register src, Register dst, Register value_field_layout_info) { // flat_field_copy implementation is fairly complex, and there are not any // "short-cuts" to be made from asm. What there is, appears to have the same // cost in C++, so just "call_VM_leaf" for now rather than maintain hundreds // of hand-rolled instructions... if (decorators & IS_DEST_UNINITIALIZED) { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetRuntime::value_copy_is_dest_uninitialized), src, dst, inline_layout_info); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetRuntime::value_copy_is_dest_uninitialized), src, dst, value_field_layout_info); } else { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetRuntime::value_copy), src, dst, inline_layout_info); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetRuntime::value_copy), src, dst, value_field_layout_info); } } diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.hpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.hpp index 27383be3cf85..655f337e73ea 100644 --- a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.hpp @@ -61,7 +61,7 @@ class BarrierSetAssembler: public CHeapObj { MacroAssembler::PreservationLevel preservation_level, Label *L_handle_null = nullptr); virtual void flat_field_copy(MacroAssembler* masm, DecoratorSet decorators, - Register src, Register dst, Register inline_layout_info); + Register src, Register dst, Register value_field_layout_info); virtual void resolve_jobject(MacroAssembler* masm, Register value, Register tmp1, Register tmp2, diff --git a/src/hotspot/cpu/ppc/globals_ppc.hpp b/src/hotspot/cpu/ppc/globals_ppc.hpp index e64794dc1661..49b7eb4cc55b 100644 --- a/src/hotspot/cpu/ppc/globals_ppc.hpp +++ b/src/hotspot/cpu/ppc/globals_ppc.hpp @@ -77,8 +77,8 @@ define_pd_global(bool, CompactStrings, true); // 2x unrolled loop is shorter with more than 9 HeapWords. define_pd_global(intx, InitArrayShortSize, 9*BytesPerLong); -define_pd_global(bool, InlineTypePassFieldsAsArgs, false); -define_pd_global(bool, InlineTypeReturnedAsFields, false); +define_pd_global(bool, ValueTypePassFieldsAsArgs, false); +define_pd_global(bool, ValueTypeReturnedAsFields, false); // Platform dependent flag handling: flags only defined on this platform. #define ARCH_FLAGS(develop, \ diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc.hpp b/src/hotspot/cpu/ppc/interp_masm_ppc.hpp index 043eda1a068a..90f509bdfa91 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc.hpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc.hpp @@ -288,7 +288,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void notify_method_exit(bool is_native_method, TosState state, NotifyMethodExitMode mode, bool check_exceptions); - // Allocate instance in "obj" and read in the content of the inline field + // Allocate instance in "obj" and read in the content of the value field // NOTES: // - input holder object via "obj", which must be r0, // will return new instance via the same reg diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp index c0507289b6ee..f4abace2fa30 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp @@ -923,12 +923,12 @@ void InterpreterMacroAssembler::remove_activation(TosState state, bind(no_reserved_zone_enabling); } - if (state == atos && InlineTypeReturnedAsFields) { + if (state == atos && ValueTypeReturnedAsFields) { Label skip, not_null; cmpdi(CR0, R17_tos, 0); bne(CR0, not_null); - untested("remove_activation InlineTypeReturnedAsFields null"); + untested("remove_activation ValueTypeReturnedAsFields null"); // Returned value is null, zero all return registers because they may belong to oop fields li(R3_ARG1, 0); li(R4_ARG2, 0); @@ -942,14 +942,14 @@ void InterpreterMacroAssembler::remove_activation(TosState state, bind(not_null); - // Check if we are returning an non-null inline type and load its fields into registers - test_oop_is_not_inline_type(R17_tos, skip, /* can_be_null= */ false); + // Check if we are returning an non-null value type and load its fields into registers + test_oop_is_not_value_type(R17_tos, skip, /* can_be_null= */ false); - // Load fields from a buffered value with an inline class specific handler + // Load fields from a buffered value with a value class specific handler load_klass(R11_scratch1, R17_tos); - ld(R11_scratch1, InlineKlass::adr_members_offset(), R11_scratch1); - ld(R11_scratch1, InlineKlass::unpack_handler_offset(), R11_scratch1); - // Unpack handler can be null if inline type is not scalarizable in returns + ld(R11_scratch1, ValueKlass::adr_members_offset(), R11_scratch1); + ld(R11_scratch1, ValueKlass::unpack_handler_offset(), R11_scratch1); + // Unpack handler can be null if value type is not scalarizable in returns cmpdi(CR0, R11_scratch1, 0); beq(CR0, skip); mtctr(R11_scratch1); @@ -1588,15 +1588,15 @@ void InterpreterMacroAssembler::profile_acmp(Register left, profile_obj_type(left, R28_mdx, in_bytes(ACmpData::left_offset()), tmp1, tmp2); - Label left_not_inline_type; - test_oop_is_not_inline_type(left, left_not_inline_type); - set_mdp_flag_at(ACmpData::left_inline_type_byte_constant(), tmp1); - bind(left_not_inline_type); + Label left_not_value_type; + test_oop_is_not_value_type(left, left_not_value_type); + set_mdp_flag_at(ACmpData::left_value_type_byte_constant(), tmp1); + bind(left_not_value_type); profile_obj_type(right, R28_mdx, in_bytes(ACmpData::right_offset()), tmp1, tmp2); - test_oop_is_not_inline_type(right, profile_continue); - set_mdp_flag_at(ACmpData::right_inline_type_byte_constant(), tmp1); + test_oop_is_not_value_type(right, profile_continue); + set_mdp_flag_at(ACmpData::right_value_type_byte_constant(), tmp1); bind(profile_continue); } @@ -2440,7 +2440,7 @@ void InterpreterMacroAssembler::write_flat_field(Register entry, Register tmp1, Label slow_path, done; lbz(tmp1, in_bytes(ResolvedFieldEntry::flags_offset()), entry); - test_field_is_not_null_free_inline_type(tmp1, slow_path); + test_field_is_not_null_free_value_type(tmp1, slow_path); null_check_throw(value, -1, tmp1); @@ -2452,7 +2452,7 @@ void InterpreterMacroAssembler::write_flat_field(Register entry, Register tmp1, Register layout_info = field_offset; lhz(tmp1, in_bytes(ResolvedFieldEntry::field_index_offset()), entry); ld(tmp2, in_bytes(ResolvedFieldEntry::field_holder_offset()), entry); - inline_layout_info(tmp2, tmp1, layout_info); + value_field_layout_info(tmp2, tmp1, layout_info); flat_field_copy(IN_HEAP, value, obj, layout_info); b(done); diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index c48071291062..9afa32bc364e 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -3295,32 +3295,32 @@ void MacroAssembler::load_method_holder(Register holder, Register method) { ld(holder, ConstantPool::pool_holder_offset(), holder); } -void MacroAssembler::test_markword_is_inline_type(Register markword, Label& is_inline_type) { +void MacroAssembler::test_markword_is_value_type(Register markword, Label& is_value_type) { assert_different_registers(markword, R0); - andi(R0, markword, markWord::inline_type_pattern_mask); - cmpwi(CR0, R0, markWord::inline_type_pattern); - beq(CR0, is_inline_type); + andi(R0, markword, markWord::value_type_pattern_mask); + cmpwi(CR0, R0, markWord::value_type_pattern); + beq(CR0, is_value_type); } -void MacroAssembler::test_oop_is_not_inline_type(Register object, Label& not_inline_type, bool can_be_null) { +void MacroAssembler::test_oop_is_not_value_type(Register object, Label& not_value_type, bool can_be_null) { if (can_be_null) { cmpdi(CR0, object, 0); - beq(CR0, not_inline_type); + beq(CR0, not_value_type); } ld(R0, oopDesc::mark_offset_in_bytes(), object); - andi(R0, R0, markWord::inline_type_pattern_mask); - cmpwi(CR0, R0, markWord::inline_type_pattern); - bne(CR0, not_inline_type); + andi(R0, R0, markWord::value_type_pattern_mask); + cmpwi(CR0, R0, markWord::value_type_pattern); + bne(CR0, not_value_type); } -void MacroAssembler::test_field_is_null_free_inline_type(Register flags, Label& is_null_free_inline_type) { - testbitdi(CR0, R0, flags, ResolvedFieldEntry::is_null_free_inline_type_shift); - bne(CR0, is_null_free_inline_type); +void MacroAssembler::test_field_is_null_free_value_type(Register flags, Label& is_null_free_value_type) { + testbitdi(CR0, R0, flags, ResolvedFieldEntry::is_null_free_value_type_shift); + bne(CR0, is_null_free_value_type); } -void MacroAssembler::test_field_is_not_null_free_inline_type(Register flags, Label& not_null_free_inline_type) { - testbitdi(CR0, R0, flags, ResolvedFieldEntry::is_null_free_inline_type_shift); - beq(CR0, not_null_free_inline_type); +void MacroAssembler::test_field_is_not_null_free_value_type(Register flags, Label& not_null_free_value_type) { + testbitdi(CR0, R0, flags, ResolvedFieldEntry::is_null_free_value_type_shift); + beq(CR0, not_null_free_value_type); } void MacroAssembler::test_field_is_flat(Register flags, Label& is_flat) { @@ -3374,33 +3374,33 @@ void MacroAssembler::load_metadata(Register dst, Register src) { } } -void MacroAssembler::flat_field_copy(DecoratorSet decorators, Register src, Register dst, Register inline_layout_info) { +void MacroAssembler::flat_field_copy(DecoratorSet decorators, Register src, Register dst, Register value_field_layout_info) { BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); - bs->flat_field_copy(this, decorators, src, dst, inline_layout_info); + bs->flat_field_copy(this, decorators, src, dst, value_field_layout_info); } -void MacroAssembler::payload_offset(Register inline_klass, Register offset) { - ld(offset, in_bytes(InlineKlass::adr_members_offset()), inline_klass); - lwz(offset, in_bytes(InlineKlass::payload_offset_offset()), offset); +void MacroAssembler::payload_offset(Register value_klass, Register offset) { + ld(offset, in_bytes(ValueKlass::adr_members_offset()), value_klass); + lwz(offset, in_bytes(ValueKlass::payload_offset_offset()), offset); } -void MacroAssembler::payload_address(Register oop, Register data, Register inline_klass, Register t1) { +void MacroAssembler::payload_address(Register oop, Register data, Register value_klass, Register t1) { // ((address) (void*) o) + vk->payload_offset(); - payload_offset(inline_klass, t1); + payload_offset(value_klass, t1); add(data, oop, t1); } -void MacroAssembler::inline_layout_info(Register holder_klass, Register index, Register layout_info) { +void MacroAssembler::value_field_layout_info(Register holder_klass, Register index, Register layout_info) { assert_different_registers(holder_klass, index, layout_info); - InlineLayoutInfo array[2]; + ValueFieldLayoutInfo array[2]; int size = (char*)&array[1] - (char*)&array[0]; // computing size of array elements if (is_power_of_2(size)) { sldi(index, index, log2i_exact(size)); // Scale index by power of 2 } else { mulld(index, index, size); // Scale the index to be the entry index * array_element_size } - ld(layout_info, InstanceKlass::inline_layout_info_array_offset(), holder_klass); - addi(layout_info, layout_info, Array::base_offset_in_bytes()); + ld(layout_info, InstanceKlass::value_field_layout_info_array_offset(), holder_klass); + addi(layout_info, layout_info, Array::base_offset_in_bytes()); add(layout_info, layout_info, index); } @@ -4655,15 +4655,8 @@ void MacroAssembler::asm_assert_mems_zero(AsmAssertCond cond, int size, int mem_ } #endif // ASSERT -void MacroAssembler::verify_coop(Register coop, const char* msg) { - if (!VerifyOops) { return; } - if (UseCompressedOops) { decode_heap_oop(coop); } - verify_oop(coop, msg); - if (UseCompressedOops) { encode_heap_oop(coop, coop); } -} - // READ: oop. KILL: R0. Volatile floats perhaps. -void MacroAssembler::verify_oop(Register oop, const char* msg) { +void MacroAssembler::verify_oop(Register oop, const char* msg, bool compressed) { if (!VerifyOops) { return; } @@ -4677,6 +4670,9 @@ void MacroAssembler::verify_oop(Register oop, const char* msg) { save_volatile_gprs(R1_SP, -nbytes_save); // except R0 mr_if_needed(R4_ARG2, oop); + if (compressed) { + decode_heap_oop(R4_ARG2); + } save_LR_CR(tmp); // save in old frame push_frame_reg_args(nbytes_save, tmp); // load FunctionDescriptor** / entry_address * @@ -4838,8 +4834,8 @@ void MacroAssembler::atomically_flip_locked_state(bool is_unlock, Register obj, if (!is_unlock) { ldarx(tmp, obj, MacroAssembler::cmpxchgx_hint_acquire_lock()); xori(tmp, tmp, markWord::lock_neutral_value); // flip lock-neutral bit - andi_(R0, tmp, markWord::lock_mask_in_place | markWord::inline_type_bit_in_place); - bne(CR0, failed); // failed if new header doesn't contain fast_locked_value (which is 0) or belongs to an inline type + andi_(R0, tmp, markWord::lock_mask_in_place | markWord::value_type_bit_in_place); + bne(CR0, failed); // failed if new header doesn't contain fast_locked_value (which is 0) or belongs to a value type } else { ldarx(tmp, obj, MacroAssembler::cmpxchgx_hint_release_lock()); andi_(R0, tmp, markWord::lock_mask_in_place); @@ -4992,8 +4988,8 @@ void MacroAssembler::fast_unlock(Register obj, Register t1, Label& slow) { bind(unlocked); } -// Unimplemented methods for inline types. -int MacroAssembler::store_inline_type_fields_to_buf(ciInlineKlass* vk, bool from_interpreter) { +// Unimplemented methods for value types. +int MacroAssembler::store_value_type_fields_to_buf(ciValueKlass* vk, bool from_interpreter) { Unimplemented(); } @@ -5001,19 +4997,19 @@ bool MacroAssembler::move_helper(VMReg from, VMReg to, BasicType bt, RegState re Unimplemented(); } -bool MacroAssembler::unpack_inline_helper(const GrowableArray* sig, int& sig_index, +bool MacroAssembler::unpack_value_helper(const GrowableArray* sig, int& sig_index, VMReg from, int& from_index, VMRegPair* to, int to_count, int& to_index, RegState reg_state[]) { Unimplemented(); } -bool MacroAssembler::pack_inline_helper(const GrowableArray* sig, int& sig_index, int vtarg_index, +bool MacroAssembler::pack_value_helper(const GrowableArray* sig, int& sig_index, int vtarg_index, VMRegPair* from, int from_count, int& from_index, VMReg to, RegState reg_state[], Register val_array) { Unimplemented(); } -int MacroAssembler::extend_stack_for_inline_args(int args_on_stack) { +int MacroAssembler::extend_stack_for_value_args(int args_on_stack) { Unimplemented(); } diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index 839e5dcd69d9..d4d4da17c443 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -35,7 +35,7 @@ class ciTypeArray; class OopMap; -class ciInlineKlass; +class ciValueKlass; class SigEntry; class VMRegPair; @@ -398,7 +398,7 @@ class MacroAssembler: public Assembler { Register Rmethod_toc = noreg, bool scratch_emit = false); - // Inline type specific methods + // Value type specific methods #include "asm/macroAssembler_common.hpp" void save_stack_increment(int sp_inc, int frame_size); @@ -823,13 +823,13 @@ class MacroAssembler: public Assembler { Register encode_klass_not_null(Register dst, Register src = noreg); // markWord tests, kills markWord reg - void test_markword_is_inline_type(Register markword, Label& is_inline_type); + void test_markword_is_value_type(Register markword, Label& is_value_type); - // inlineKlass queries, kills temp_reg - void test_oop_is_not_inline_type(Register object, Label& not_inline_type, bool can_be_null = true); + // ValueKlass queries, kills temp_reg + void test_oop_is_not_value_type(Register object, Label& not_value_type, bool can_be_null = true); - void test_field_is_null_free_inline_type(Register flags, Label& is_null_free); - void test_field_is_not_null_free_inline_type(Register flags, Label& not_null_free); + void test_field_is_null_free_value_type(Register flags, Label& is_null_free); + void test_field_is_not_null_free_value_type(Register flags, Label& not_null_free); void test_field_is_flat(Register flags, Label& is_flat); // Check oops for special arrays, i.e. flat arrays and/or null-free arrays @@ -844,13 +844,13 @@ class MacroAssembler: public Assembler { void load_metadata(Register dst, Register src); - void flat_field_copy(DecoratorSet decorators, Register src, Register dst, Register inline_layout_info); + void flat_field_copy(DecoratorSet decorators, Register src, Register dst, Register value_field_layout_info); - void inline_layout_info(Register holder_klass, Register index, Register layout_info); + void value_field_layout_info(Register holder_klass, Register index, Register layout_info); - // inline type data payload offsets... - void payload_offset(Register inline_klass, Register offset); - void payload_address(Register oop, Register data, Register inline_klass, Register t1); + // value type data payload offsets... + void payload_offset(Register value_klass, Register offset); + void payload_address(Register oop, Register data, Register value_klass, Register t1); // SIGTRAP-based range checks for arrays. inline void trap_range_check_l(Register a, Register b); @@ -1012,11 +1012,8 @@ class MacroAssembler: public Assembler { asm_assert_mems_zero(ne, 8, mem_offset, mem_base, msg); } - // Calls verify_oop. If UseCompressedOops is on, decodes the oop. - // Preserves reg. - void verify_coop(Register reg, const char*); // Emit code to verify that reg contains a valid oop if +VerifyOops is set. - void verify_oop(Register reg, const char* s = "broken oop"); + void verify_oop(Register reg, const char* s = "broken oop", bool compressed = false); void verify_oop_addr(RegisterOrConstant offs, Register base, const char* s = "contains broken oop"); // TODO: verify method and klass metadata (compare against vptr?) @@ -1051,7 +1048,7 @@ class MacroAssembler: public Assembler { void zap_from_to(Register low, int before, Register high, int after, Register val, Register addr) PRODUCT_RETURN; - // Inline type specific methods + // Value type specific methods #include "asm/macroAssembler_common.hpp" }; diff --git a/src/hotspot/cpu/ppc/methodHandles_ppc.cpp b/src/hotspot/cpu/ppc/methodHandles_ppc.cpp index 9341fc50904a..2937b9bef060 100644 --- a/src/hotspot/cpu/ppc/methodHandles_ppc.cpp +++ b/src/hotspot/cpu/ppc/methodHandles_ppc.cpp @@ -144,11 +144,11 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth __ cmplwi(CR0, R19_method, 0); __ beq(CR0, L_no_such_method); - // The following jump might pass an inline type argument that was erased to Object as oop to a - // callee that expects inline type arguments to be passed as fields. We need to call the compiled - // value entry (_code->inline_entry_point() or _adapter->c2i_inline_entry()) which will take care + // The following jump might pass a value type argument that was erased to Object as oop to a + // callee that expects value type arguments to be passed as fields. We need to call the compiled + // value entry (_code->value_entry_point() or _adapter->c2i_value_entry()) which will take care // of translating between the calling conventions. - const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_inline_offset() : + const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_value_offset() : Method::from_interpreted_offset(); __ ld(target, in_bytes(entry_offset), R19_method); __ mtctr(target); diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index 3681165812a5..7f38025bdeea 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -1398,7 +1398,7 @@ void MachPrologNode::emit(C2_MacroAssembler *masm, PhaseRegAlloc *ra_) const { const bool method_is_frameless = false /* TODO: PPC port C->is_frameless_method()*/; - const Register return_pc = R20; // Must match return_addr() in frame section. + const Register return_pc = R20; const Register callers_sp = R21; const Register push_frame_temp = R22; const Register toc_temp = R23; @@ -3424,6 +3424,60 @@ encode %{ //----------FRAME-------------------------------------------------------------- // Definition of frame structure and management information. +// +// S T A C K L A Y O U T Allocators stack-slot number +// | (to get allocators register number +// G Owned by | | v add OptoReg::stack0()) +// r CALLER | | +// o | +--------+ pad to even-align allocators stack-slot +// w V | pad0 | numbers; owned by CALLER +// t -----------+--------+----> Matcher::_in_arg_limit, unaligned +// h ^ | in | 5 +// | | args | 4 Holes in incoming args owned by SELF +// | | | | 3 +// | | +--------+ +// V | | old out| Empty on Intel, window on Sparc +// | old |preserve| Must be even aligned. +// | SP-+--------+----> Matcher::_old_SP, even aligned +// | | in | 3 area for Intel ret address +// Owned by |preserve| Empty on Sparc. +// SELF +--------+ +// | | pad2 | 2 pad to align old SP +// | +--------+ 1 +// | | locks | 0 +// | +--------+----> OptoReg::stack0(), even aligned +// | | pad1 | 11 pad to align new SP +// | +--------+ +// | | | 10 +// | | spills | 9 spills +// V | | 8 (pad0 slot for callee) +// -----------+--------+----> Matcher::_out_arg_limit, unaligned +// ^ | out | 7 +// | | args | 6 Holes in outgoing args owned by CALLEE +// Owned by +--------+ +// CALLEE | new out| 6 Empty on Intel, window on Sparc +// | new |preserve| Must be even-aligned. +// | SP-+--------+----> Matcher::_new_SP, even aligned +// | | | +// +// Note 1: Only region 8-11 is determined by the allocator. Region 0-5 is +// known from SELF's arguments and the Java calling convention. +// Region 6-7 is determined per call site. +// Note 2: If the calling convention leaves holes in the incoming argument +// area, those holes are owned by SELF. Holes in the outgoing area +// are owned by the CALLEE. Holes should not be necessary in the +// incoming area, as the Java calling convention is completely under +// the control of the AD file. Doubles can be sorted and packed to +// avoid holes. Holes in the outgoing arguments may be necessary for +// varargs C calling conventions. +// Note 3: Region 0-3 is even aligned, with pad2 as needed. Region 3-5 is +// even aligned with pad0 as needed. +// Region 6 is even aligned. Region 6-7 is NOT even aligned; +// region 6-11 is even aligned; it may be padded out more so that +// the region from SP to FP meets the minimum stack alignment. +// Note 4: For I2C adapters, the incoming FP may not meet the minimum stack +// alignment. Region 11, pad1, may be dynamically extended so that +// SP meets the minimum alignment. frame %{ // These two registers define part of the calling convention between @@ -3454,19 +3508,10 @@ frame %{ // return address specifies a type (REG or STACK) and a number // representing the register number (i.e. - use a register name) or // stack slot. - // - // A: Link register is stored in stack slot ... - // M: ... but it's in the caller's frame according to PPC-64 ABI. - // J: Therefore, we make sure that the link register is also in R11_scratch1 - // at the end of the prolog. - // B: We use R20, now. - //return_addr(REG R20); - - // G: After reading the comments made by all the luminaries on their - // failure to tell the compiler where the return address really is, - // I hardly dare to try myself. However, I'm convinced it's in slot - // 4 what apparently works and saves us some spills. - return_addr(STACK 4); + // Ret Addr is on stack 4 slots (16 bytes) above _old_SP. + // That's the after-PROLOG location. Actually it is passed in the LR register and + // the prolog saves it in the caller's abi section. + return_addr(STACK OptoReg::reg2stack(_old_SP) + 4); // Location of compiled Java return values. Same as C return_value %{ @@ -3737,6 +3782,15 @@ operand immI_minus1() %{ interface(CONST_INTER); %} +// constant 'int 4'. +operand immI_4() %{ + predicate(n->get_int() == 4); + match(ConI); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + // int value 16. operand immI_16() %{ predicate(n->get_int() == 16); @@ -9530,6 +9584,16 @@ instruct castP2X(iRegLdst dst, iRegP_N2P src) %{ ins_pipe(pipe_class_default); %} +instruct castI2N(iRegNdst dst, iRegIsrc src) %{ + match(Set dst (CastI2N src)); + format %{ "CLRLDI $dst, $src, #32 \t// int->Narrow Ptr" %} + size(4); + ins_encode %{ + __ clrldi($dst$$Register, $src$$Register, 32); // zero high word + %} + ins_pipe(pipe_class_default); +%} + instruct castN2X(iRegLdst dst, iRegNsrc src) %{ match(Set dst (CastP2X src)); diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index ae86f80cff4c..12e4d9994a1d 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -1020,25 +1020,25 @@ static void patch_callers_callsite(MacroAssembler *masm, int adapter_size, int t __ bind(L); } -// For each inline type argument, sig includes the list of fields of -// the inline type. This utility function computes the number of -// arguments for the call if inline types are passed by reference (the +// For each value type argument, sig includes the list of fields of +// the value type. This utility function computes the number of +// arguments for the call if value types are passed by reference (the // calling convention the interpreter expects). static int compute_total_args_passed_int(const GrowableArray* sig_extended) { int total_args_passed = 0; - if (InlineTypePassFieldsAsArgs) { + if (ValueTypePassFieldsAsArgs) { for (int i = 0; i < sig_extended->length(); i++) { BasicType bt = sig_extended->at(i)._bt; if (bt == T_METADATA) { - // In sig_extended, an inline type argument starts with: + // In sig_extended, a value type argument starts with: // T_METADATA, followed by the types of the fields of the - // inline type and T_VOID to mark the end of the value - // type. Inline types are flattened so, for instance, in the - // case of an inline type with an int field and an inline type + // value type and T_VOID to mark the end of the value + // type. Value types are flattened so, for instance, in the + // case of a value type with an int field and a value type // field that itself has 2 fields, an int and a long: // T_METADATA T_INT T_METADATA T_INT T_LONG T_VOID (second - // slot for the T_LONG) T_VOID (inner inline type) T_VOID - // (outer inline type) + // slot for the T_LONG) T_VOID (inner value type) T_VOID + // (outer value type) total_args_passed++; int vt = 1; do { @@ -1116,14 +1116,14 @@ static void gen_c2i_adapter(MacroAssembler *masm, __ bind(skip_fixup); - if (InlineTypePassFieldsAsArgs) { - // Is there an inline type argument? - bool has_inline_argument = false; - for (int i = 0; i < sig_extended->length() && !has_inline_argument; i++) { - has_inline_argument = (sig_extended->at(i)._bt == T_METADATA); + if (ValueTypePassFieldsAsArgs) { + // Is there a value type argument? + bool has_value_argument = false; + for (int i = 0; i < sig_extended->length() && !has_value_argument; i++) { + has_value_argument = (sig_extended->at(i)._bt == T_METADATA); } - if (has_inline_argument) { - __ unimplemented("c2i has_inline_argument"); + if (has_value_argument) { + __ unimplemented("c2i has_value_argument"); } } @@ -1145,7 +1145,7 @@ static void gen_c2i_adapter(MacroAssembler *masm, int st_off = adapter_size - wordSize; // Write the args into the outgoing interpreter space. - // TODO: support for InlineTypePassFieldsAsArgs + // TODO: support for ValueTypePassFieldsAsArgs for (int i = 0; i < total_args_passed; i++) { BasicType bt = sig_extended->at(i)._bt; @@ -1389,7 +1389,7 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler* masm, // compiled code, which relies solely on SP and not FP, get sick). entry_address[AdapterBlob::C2I_Unverified] = __ pc(); - entry_address[AdapterBlob::C2I_Unverified_Inline] = __ pc(); + entry_address[AdapterBlob::C2I_Unverified_Value] = __ pc(); Label skip_fixup; gen_inline_cache_check(masm, skip_fixup); @@ -1400,10 +1400,10 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler* masm, // Scalarized c2i adapter with non-scalarized receiver (i.e., don't pack receiver) entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr; - entry_address[AdapterBlob::C2I_Inline_RO] = __ pc(); + entry_address[AdapterBlob::C2I_Value_RO] = __ pc(); if (regs_cc != regs_cc_ro) { // No class init barrier needed because method is guaranteed to be non-static - __ unimplemented("C2I_Inline_RO"); + __ unimplemented("C2I_Value_RO"); #if 0 gen_c2i_adapter(masm, sig_cc_ro, regs_cc_ro, /* requires_clinit_barrier = */ false, entry_address[AdapterBlob::C2I_No_Clinit_Check], skip_fixup, entry_address[AdapterBlob::I2C], oop_maps, frame_complete, frame_size_in_words, /* alloc_inline_receiver = */ false); @@ -1412,25 +1412,25 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler* masm, } // Scalarized c2i adapter - entry_address[AdapterBlob::C2I] = __ pc(); - entry_address[AdapterBlob::C2I_Inline] = __ pc(); + entry_address[AdapterBlob::C2I] = __ pc(); + entry_address[AdapterBlob::C2I_Value] = __ pc(); gen_c2i_adapter(masm, sig_cc, regs_cc, /* requires_clinit_barrier = */ true, entry_address[AdapterBlob::C2I_No_Clinit_Check], skip_fixup, entry_address[AdapterBlob::I2C], oop_maps, frame_complete, frame_size_in_words, /* alloc_inline_receiver = */ true); // Non-scalarized c2i adapter if (regs != regs_cc) { - entry_address[AdapterBlob::C2I_Unverified_Inline] = __ pc(); - Label inline_entry_skip_fixup; - __ unimplemented("C2I_Unverified_Inline"); + entry_address[AdapterBlob::C2I_Unverified_Value] = __ pc(); + Label value_entry_skip_fixup; + __ unimplemented("C2I_Unverified_Value"); #if 0 - gen_inline_cache_check(masm, inline_entry_skip_fixup); + gen_inline_cache_check(masm, value_entry_skip_fixup); #endif - entry_address[AdapterBlob::C2I_Inline] = __ pc(); - __ unimplemented("C2I_Inline2"); + entry_address[AdapterBlob::C2I_Value] = __ pc(); + __ unimplemented("C2I_Value2"); #if 0 gen_c2i_adapter(masm, sig, regs, /* requires_clinit_barrier = */ true, entry_address[AdapterBlob::C2I_No_Clinit_Check], - inline_entry_skip_fixup, entry_address[AdapterBlob::I2C], oop_maps, frame_complete, frame_size_in_words, /* alloc_inline_receiver = */ false); + value_entry_skip_fixup, entry_address[AdapterBlob::I2C], oop_maps, frame_complete, frame_size_in_words, /* alloc_inline_receiver = */ false); #endif } // The c2i adapters might safepoint and trigger a GC. The caller must make sure that @@ -3864,13 +3864,13 @@ void SharedRuntime::montgomery_square(jint *a_ints, jint *n_ints, reverse_words(m, (unsigned long *)m_ints, longwords); } -BufferedInlineTypeBlob* SharedRuntime::generate_buffered_inline_type_adapter(const InlineKlass* vk) { +BufferedValueTypeBlob* SharedRuntime::generate_buffered_value_type_adapter(const ValueKlass* vk) { Unimplemented(); return nullptr; } // Call here from the interpreter or compiled code to store returned -// values to a newly allocated inline type instance. +// values to a newly allocated value type instance. RuntimeStub* SharedRuntime::generate_return_value_stub(address destination) { Unimplemented(); return nullptr; diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index 2d51119bcc9f..8048878aef85 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -340,15 +340,15 @@ class StubGenerator: public StubCodeGenerator { // case T_OBJECT: __ bind(ret_is_object); - if (InlineTypeReturnedAsFields) { + if (ValueTypeReturnedAsFields) { // Check for scalarized return value __ cmpdi(CR0, R3_RET, 0); __ beq(CR0, ret_is_long); // Load pack handler address - __ untested("call stub InlineTypeReturnedAsFields"); // TODO: check return registers usage + __ untested("call stub ValueTypeReturnedAsFields"); // TODO: check return registers usage __ andi(R12_scratch2, R3_RET, -2); - __ ld(R12_scratch2, InlineKlass::adr_members_offset(), R12_scratch2); - __ ld(R12_scratch2, InlineKlass::pack_handler_jobject_offset(), R12_scratch2); + __ ld(R12_scratch2, ValueKlass::adr_members_offset(), R12_scratch2); + __ ld(R12_scratch2, ValueKlass::pack_handler_jobject_offset(), R12_scratch2); __ mtctr(R12_scratch2); __ bctr(); // tail call } // else fall through @@ -604,13 +604,13 @@ class StubGenerator: public StubCodeGenerator { VectorRegister vTmp10 = VR10; VectorRegister vSwappedH = VR11; VectorRegister vTmp12 = VR12; - VectorRegister loadOrder = VR13; - VectorRegister vHigh = VR14; - VectorRegister vLow = VR15; - VectorRegister vState = VR16; - VectorRegister vPerm = VR17; - VectorRegister vCombinedResult = VR18; - VectorRegister vConstC2 = VR19; + VectorRegister vState = VR13; + VectorRegister vCombinedResult = VR14; + VectorRegister vConstC2 = VR15; + VectorRegister vp = VR16; // permute vector for byte vector accesses on P8 LE + + // vp must be computed before any byte vector access. Clobbers R0. + __ compute_vp_for_byte_vector_unaligned(vp, vTmp12); __ li(temp1, 0xc2); __ sldi(temp1, temp1, 56); @@ -638,14 +638,6 @@ class StubGenerator: public StubCodeGenerator { #endif __ clrldi(blocks, blocks, 32); __ mtctr(blocks); - __ lvsl(loadOrder, temp1); -#ifdef VM_LITTLE_ENDIAN - __ vspltisb(vTmp12, 0xf); - __ vxor(loadOrder, loadOrder, vTmp12); -#define LE_swap_bytes(x) __ vec_perm(x, x, x, loadOrder) -#else -#define LE_swap_bytes(x) -#endif // This code performs Karatsuba multiplication in Galois fields to compute the GHASH operation. // @@ -666,43 +658,22 @@ class StubGenerator: public StubCodeGenerator { // "Intel® Carry-Less Multiplication Instruction and its Usage for Computing the GCM Mode" // https://web.archive.org/web/20110609115824/https://software.intel.com/file/24918 // - Label L_aligned_loop, L_store, L_unaligned_loop, L_initialize_unaligned_loop; - __ andi(temp1, data, 15); - __ cmpwi(CR0, temp1, 0); - __ bne(CR0, L_initialize_unaligned_loop); - - __ bind(L_aligned_loop); - __ lvx(vH, temp1, data); - LE_swap_bytes(vH); - computeGCMProduct(_masm, vLowerH, vH, vHigherH, vConstC2, vZero, vState, - vLowProduct, vMidProduct, vHighProduct, vReducedLow, vTmp8, vTmp9, vCombinedResult, vSwappedH); - __ addi(data, data, 16); - __ bdnz(L_aligned_loop); - __ b(L_store); - __ bind(L_initialize_unaligned_loop); - __ li(temp1, 0); - __ lvsl(vPerm, temp1, data); - __ lvx(vHigh, temp1, data); -#ifdef VM_LITTLE_ENDIAN - __ vspltisb(vTmp12, -1); - __ vxor(vPerm, vPerm, vTmp12); -#endif - __ bind(L_unaligned_loop); - __ addi(data, data, 16); - __ lvx(vLow, temp1, data); - __ vec_perm(vH, vHigh, vLow, vPerm); + Label L_loop; + __ align(32); + __ bind(L_loop); + __ load_byte_vector_unaligned(vH, 0, data, temp1, vp); computeGCMProduct(_masm, vLowerH, vH, vHigherH, vConstC2, vZero, vState, - vLowProduct, vMidProduct, vHighProduct, vReducedLow, vTmp8, vTmp9, vCombinedResult, vSwappedH); - __ vmr(vHigh, vLow); - __ bdnz(L_unaligned_loop); + vLowProduct, vMidProduct, vHighProduct, vReducedLow, vTmp8, vTmp9, vCombinedResult, vSwappedH); + __ addi(data, data, 16); + __ bdnz(L_loop); - __ bind(L_store); __ stxvd2x(vState->to_vsr(), state); __ blr(); return start; } + // -XX:+OptimizeFill : convert fill/copy loops into intrinsic // // The code is implemented(ported from sparc) as we believe it benefits JVM98, however @@ -2622,10 +2593,10 @@ class StubGenerator: public StubCodeGenerator { __ cmpd(CR5, src_klass, dst_klass); // if (src->klass() != dst->klass()) return -1; __ bne(CR5, L_failed); - // Check for flat inline type array -> return -1 + // Check for flat value type array -> return -1 __ test_flat_array_oop(src, temp, L_failed); - // Check for null-free (non-flat) inline type array -> handle as object array + // Check for null-free (non-flat) value type array -> handle as object array __ test_null_free_array_oop(src, temp, L_objArray); __ cmpwi(CR6, lh, Klass::_lh_neutral_value); // if (!src->is_Array()) return -1; @@ -2776,8 +2747,6 @@ class StubGenerator: public StubCodeGenerator { address start = __ function_entry(); - Label L_doLast, L_error; - Register from = R3_ARG1; // source array address Register to = R4_ARG2; // destination array address Register key = R5_ARG3; // round key array @@ -2799,87 +2768,16 @@ class StubGenerator: public StubCodeGenerator { // load unaligned from[0-15] to vRet __ load_byte_vector_unaligned(vRet, 0, from, tmp, vp); - // load the 1st round key to vKey1 - __ load_word_vector_unaligned(vKey1, 0, key, tmp); - // load keylen (44 or 52 or 60) __ lwz (keylen, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT), key); - // 1st round - __ vxor (vRet, vRet, vKey1); - - // load the 2nd - 5th round key to vKey1 - vKey4 - __ load_word_vector_unaligned(vKey1, 16, key, tmp); - __ load_word_vector_unaligned(vKey2, 32, key, tmp); - __ load_word_vector_unaligned(vKey3, 48, key, tmp); - __ load_word_vector_unaligned(vKey4, 64, key, tmp); - - // 2nd - 5th rounds - __ vcipher (vRet, vRet, vKey1); - __ vcipher (vRet, vRet, vKey2); - __ vcipher (vRet, vRet, vKey3); - __ vcipher (vRet, vRet, vKey4); - - // load the 6th - 9th round key to vKey1 - vKey4 - __ load_word_vector_unaligned(vKey1, 80, key, tmp); - __ load_word_vector_unaligned(vKey2, 96, key, tmp); - __ load_word_vector_unaligned(vKey3, 112, key, tmp); - __ load_word_vector_unaligned(vKey4, 128, key, tmp); - - // 6th - 9th rounds - __ vcipher (vRet, vRet, vKey1); - __ vcipher (vRet, vRet, vKey2); - __ vcipher (vRet, vRet, vKey3); - __ vcipher (vRet, vRet, vKey4); - - // load the 10th - 11th round key to vKey1 - vKey2 - __ load_word_vector_unaligned(vKey1, 144, key, tmp); - __ load_word_vector_unaligned(vKey2, 160, key, tmp); - - // if all round keys are loaded, skip next 4 rounds - __ cmpwi (CR0, keylen, 44); - __ beq (CR0, L_doLast); - - // 10th - 11th rounds - __ vcipher (vRet, vRet, vKey1); - __ vcipher (vRet, vRet, vKey2); - - // load the 12th - 13th round key to vKey1 - vKey2 - __ load_word_vector_unaligned(vKey1, 176, key, tmp); - __ load_word_vector_unaligned(vKey2, 192, key, tmp); - - // if all round keys are loaded, skip next 2 rounds - __ cmpwi (CR0, keylen, 52); - __ beq (CR0, L_doLast); - -#ifdef ASSERT - __ cmpwi (CR0, keylen, 60); - __ bne (CR0, L_error); -#endif - - // 12th - 13th rounds - __ vcipher (vRet, vRet, vKey1); - __ vcipher (vRet, vRet, vKey2); - - // load the 14th - 15th round key to vKey1 - vKey2 - __ load_word_vector_unaligned(vKey1, 208, key, tmp); - __ load_word_vector_unaligned(vKey2, 224, key, tmp); - - __ bind(L_doLast); - - // last two rounds - __ vcipher (vRet, vRet, vKey1); - __ vcipherlast (vRet, vRet, vKey2); + aes_encrypt_rounds(vRet, key, keylen, tmp, vKey1, vKey2, vKey3, vKey4); // store result (unaligned) __ store_byte_vector_unaligned(vRet, 0, to, tmp, vp); __ blr(); -#ifdef ASSERT - __ bind(L_error); - __ stop("aescrypt_encryptBlock: invalid key length"); -#endif return start; } @@ -2894,8 +2792,6 @@ class StubGenerator: public StubCodeGenerator { address start = __ function_entry(); - Label L_doLast, L_do44, L_do52, L_error; - Register from = R3_ARG1; // source array address Register to = R4_ARG2; // destination array address Register key = R5_ARG3; // round key array @@ -2921,96 +2817,12 @@ class StubGenerator: public StubCodeGenerator { // load keylen (44 or 52 or 60) __ lwz (keylen, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT), key); - __ cmpwi (CR0, keylen, 44); - __ beq (CR0, L_do44); - - __ cmpwi (CR0, keylen, 52); - __ beq (CR0, L_do52); - -#ifdef ASSERT - __ cmpwi (CR0, keylen, 60); - __ bne (CR0, L_error); -#endif - - // load the 15th - 11th round key to vKey1 - vKey5 - __ load_word_vector_unaligned(vKey1, 224, key, tmp); - __ load_word_vector_unaligned(vKey2, 208, key, tmp); - __ load_word_vector_unaligned(vKey3, 192, key, tmp); - __ load_word_vector_unaligned(vKey4, 176, key, tmp); - __ load_word_vector_unaligned(vKey5, 160, key, tmp); - - // 1st - 5th rounds - __ vxor (vRet, vRet, vKey1); - __ vncipher (vRet, vRet, vKey2); - __ vncipher (vRet, vRet, vKey3); - __ vncipher (vRet, vRet, vKey4); - __ vncipher (vRet, vRet, vKey5); - - __ b (L_doLast); - - __ align(32); - __ bind (L_do52); - - // load the 13th - 11th round key to vKey1 - vKey3 - __ load_word_vector_unaligned(vKey1, 192, key, tmp); - __ load_word_vector_unaligned(vKey2, 176, key, tmp); - __ load_word_vector_unaligned(vKey3, 160, key, tmp); - - // 1st - 3rd rounds - __ vxor (vRet, vRet, vKey1); - __ vncipher (vRet, vRet, vKey2); - __ vncipher (vRet, vRet, vKey3); - - __ b (L_doLast); - - __ align(32); - __ bind (L_do44); - - // load the 11th round key to vKey1 - __ load_word_vector_unaligned(vKey1, 160, key, tmp); - - // 1st round - __ vxor (vRet, vRet, vKey1); - - __ bind (L_doLast); - - // load the 10th - 6th round key to vKey1 - vKey5 - __ load_word_vector_unaligned(vKey1, 144, key, tmp); - __ load_word_vector_unaligned(vKey2, 128, key, tmp); - __ load_word_vector_unaligned(vKey3, 112, key, tmp); - __ load_word_vector_unaligned(vKey4, 96, key, tmp); - __ load_word_vector_unaligned(vKey5, 80, key, tmp); - - // last 10th - 6th rounds - __ vncipher (vRet, vRet, vKey1); - __ vncipher (vRet, vRet, vKey2); - __ vncipher (vRet, vRet, vKey3); - __ vncipher (vRet, vRet, vKey4); - __ vncipher (vRet, vRet, vKey5); - - // load the 5th - 1st round key to vKey1 - vKey5 - __ load_word_vector_unaligned(vKey1, 64, key, tmp); - __ load_word_vector_unaligned(vKey2, 48, key, tmp); - __ load_word_vector_unaligned(vKey3, 32, key, tmp); - __ load_word_vector_unaligned(vKey4, 16, key, tmp); - __ load_word_vector_unaligned(vKey5, 0, key, tmp); - - // last 5th - 1th rounds - __ vncipher (vRet, vRet, vKey1); - __ vncipher (vRet, vRet, vKey2); - __ vncipher (vRet, vRet, vKey3); - __ vncipher (vRet, vRet, vKey4); - __ vncipherlast (vRet, vRet, vKey5); + aes_decrypt_rounds(vRet, key, keylen, tmp, vKey1, vKey2, vKey3, vKey4, vKey5); // store result (unaligned) __ store_byte_vector_unaligned(vRet, 0, to, tmp, vp); __ blr(); - -#ifdef ASSERT - __ bind(L_error); - __ stop("aescrypt_decryptBlock: invalid key length"); -#endif return start; } @@ -4920,7 +4732,7 @@ void generate_lookup_secondary_supers_table_stub() { } if (return_barrier) { - assert(!InlineTypeReturnedAsFields, "unsupported"); + assert(!ValueTypeReturnedAsFields, "unsupported"); __ mr(nvtmp, R3_RET); __ fmr(nvftmp, F1_RET); // preserve possible return value from a method returning to the return barrier DEBUG_ONLY(__ ld_ptr(tmp1, _abi0(callers_sp), R1_SP);) __ ld_ptr(R1_SP, JavaThread::cont_entry_offset(), R16_thread); @@ -4965,7 +4777,7 @@ void generate_lookup_secondary_supers_table_stub() { __ mr(R1_SP, R3_RET); // R3_RET contains the SP of the thawed top frame if (return_barrier) { - assert(!InlineTypeReturnedAsFields, "unsupported"); + assert(!ValueTypeReturnedAsFields, "unsupported"); // we're now in the caller of the frame that returned to the barrier __ mr(R3_RET, nvtmp); __ fmr(F1_RET, nvftmp); // restore return value (no safepoint in the call to thaw, so even an oop return value should be OK) } else { @@ -5137,7 +4949,7 @@ void generate_lookup_secondary_supers_table_stub() { // Generates all stubs and initializes the entry points // support for verify_oop (must happen after universe_init) - StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop(); + StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop(); // nmethod entry barriers for concurrent class unloading StubRoutines::_method_entry_barrier = generate_method_entry_barrier(); diff --git a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp index 69ff7c2a6a65..3cd907389ee2 100644 --- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp @@ -619,9 +619,9 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, default : ShouldNotReachHere(); } - if (state == atos && InlineTypeReturnedAsFields) { - __ unimplemented("return entry InlineTypeReturnedAsFields"); - //__ store_inline_type_fields_to_buf(nullptr, true); + if (state == atos && ValueTypeReturnedAsFields) { + __ unimplemented("return entry ValueTypeReturnedAsFields"); + //__ store_value_type_fields_to_buf(nullptr, true); } __ restore_interpreter_state(R11_scratch1, false /*bcp_and_mdx_only*/, true /*restore_top_frame_sp*/); diff --git a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp index dfb59f071d34..9a8f09f6bfc6 100644 --- a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp @@ -1868,7 +1868,7 @@ void TemplateTable::if_acmp(Condition cc) { __ profile_acmp(Rsecond, Rfirst, R11_scratch1, R12_scratch2); - const int is_inline_type_mask = markWord::inline_type_pattern; + const int is_value_type_mask = markWord::value_type_pattern; if (Arguments::is_valhalla_enabled()) { Label taken, not_taken; __ cmpd(CR0, Rfirst, Rsecond); @@ -1884,8 +1884,8 @@ void TemplateTable::if_acmp(Condition cc) { __ ld(R11_scratch1, oopDesc::mark_offset_in_bytes(), Rfirst); __ ld(R12_scratch2, oopDesc::mark_offset_in_bytes(), Rsecond); __ andr(R11_scratch1, R11_scratch1, R12_scratch2); - __ andi(R11_scratch1, R11_scratch1, is_inline_type_mask); - __ cmpdi(CR0, R11_scratch1, is_inline_type_mask); + __ andi(R11_scratch1, R11_scratch1, is_value_type_mask); + __ cmpdi(CR0, R11_scratch1, is_value_type_mask); __ bne(CR0, (cc == equal) ? not_taken : taken); // same value klass ? @@ -3208,7 +3208,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr } else { // Valhalla if (is_static) { Label is_nullable; - __ test_field_is_not_null_free_inline_type(Rflags, is_nullable); + __ test_field_is_not_null_free_value_type(Rflags, is_nullable); __ null_check_throw(R17_tos, -1, Rscratch); __ align(32, 12); __ bind(is_nullable); @@ -3216,7 +3216,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr } else { Label null_free_reference, is_flat, rewrite_inline; __ test_field_is_flat(Rflags, is_flat); - __ test_field_is_null_free_inline_type(Rflags, null_free_reference); + __ test_field_is_null_free_value_type(Rflags, null_free_reference); pop_and_check_object(Rclass_or_obj); // Store into the field do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, IN_HEAP); @@ -3228,7 +3228,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr } __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode())); - // Implementation of the inline type semantic + // Implementation of the value type semantic __ bind(null_free_reference); __ null_check_throw(R17_tos, -1, Rscratch); pop_and_check_object(Rclass_or_obj); @@ -4316,9 +4316,9 @@ void TemplateTable::monitorenter() { // Null pointer exception. __ null_check_throw(Robj_to_lock, -1, Rscratch1); - Label is_inline_type; + Label is_value_type; __ ld(Rscratch1, oopDesc::mark_offset_in_bytes(), Robj_to_lock); - __ test_markword_is_inline_type(Rscratch1, is_inline_type); + __ test_markword_is_value_type(Rscratch1, is_value_type); // Check if any slot is present => short cut to allocation if not. __ cmpld(CR0, Rcurrent_monitor, Rbot); @@ -4377,7 +4377,7 @@ void TemplateTable::monitorenter() { // The bcp has already been incremented. Just need to dispatch to next instruction. __ dispatch_next(vtos); - __ bind(is_inline_type); + __ bind(is_value_type); __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_identity_exception), Robj_to_lock); __ should_not_reach_here(); @@ -4404,10 +4404,10 @@ void TemplateTable::monitorexit() { // Null pointer check. __ null_check_throw(Robj_to_lock, -1, Rscratch); - const int is_inline_type_mask = markWord::inline_type_pattern; + const int is_value_type_mask = markWord::value_type_pattern; __ ld(Rscratch, oopDesc::mark_offset_in_bytes(), Robj_to_lock); - __ andi(Rscratch, Rscratch, is_inline_type_mask); - __ cmpwi(CR0, Rscratch, is_inline_type_mask); + __ andi(Rscratch, Rscratch, is_value_type_mask); + __ cmpwi(CR0, Rscratch, is_value_type_mask); __ beq(CR0, Lillegal_monitor_state); // Check corner case: unbalanced monitorEnter / Exit. diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.cpp b/src/hotspot/cpu/ppc/vm_version_ppc.cpp index b3b433cea948..1752040c8155 100644 --- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp +++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp @@ -342,22 +342,14 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseUnalignedAccesses, true); } - if (InlineTypePassFieldsAsArgs) { - warning("InlineTypePassFieldsAsArgs is not supported on this CPU"); - FLAG_SET_DEFAULT(InlineTypePassFieldsAsArgs, false); - } - if (InlineTypeReturnedAsFields) { - warning("InlineTypeReturnedAsFields is not supported on this CPU"); - FLAG_SET_DEFAULT(InlineTypeReturnedAsFields, false); - } - - // TODO: Valhalla optimizations - if (FLAG_IS_DEFAULT(UseArrayFlattening )) FLAG_SET_DEFAULT(UseArrayFlattening , false); - if (FLAG_IS_DEFAULT(UseFieldFlattening )) FLAG_SET_DEFAULT(UseFieldFlattening , false); - if (FLAG_IS_DEFAULT(UseNullFreeNonAtomicValueFlattening)) FLAG_SET_DEFAULT(UseNullFreeNonAtomicValueFlattening, false); - if (FLAG_IS_DEFAULT(UseNullableAtomicValueFlattening )) FLAG_SET_DEFAULT(UseNullableAtomicValueFlattening , false); - if (FLAG_IS_DEFAULT(UseNullFreeAtomicValueFlattening )) FLAG_SET_DEFAULT(UseNullFreeAtomicValueFlattening , false); - if (FLAG_IS_DEFAULT(UseNullableNonAtomicValueFlattening)) FLAG_SET_DEFAULT(UseNullableNonAtomicValueFlattening, false); + if (ValueTypePassFieldsAsArgs) { + warning("ValueTypePassFieldsAsArgs is not supported on this CPU"); + FLAG_SET_DEFAULT(ValueTypePassFieldsAsArgs, false); + } + if (ValueTypeReturnedAsFields) { + warning("ValueTypeReturnedAsFields is not supported on this CPU"); + FLAG_SET_DEFAULT(ValueTypeReturnedAsFields, false); + } check_virtualizations(); } diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index a689107493b1..d53c39b2a6ab 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -2831,6 +2831,8 @@ enum Nf { INSN(maxu, 0b0110011, 0b111, 0b0000101); INSN(min, 0b0110011, 0b100, 0b0000101); INSN(minu, 0b0110011, 0b101, 0b0000101); + INSN(clmul, 0b0110011, 0b001, 0b0000101); + INSN(clmulh, 0b0110011, 0b011, 0b0000101); #undef INSN diff --git a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp index 53af501e9b68..0d4ee072f044 100644 --- a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp @@ -265,7 +265,7 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) { if (_throw_ie_stub != nullptr) { // When we come here, _obj_reg has already been checked to be non-null. __ ld(t0, Address(_obj_reg->as_register(), oopDesc::mark_offset_in_bytes())); - __ mv(t1, markWord::inline_type_pattern); + __ mv(t1, markWord::value_type_pattern); __ andr(t0, t0, t1); __ beq(t0, t1, *_throw_ie_stub->entry(), /* is_far */ true); } diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.cpp index 979aae0b663b..36edaf3a93d2 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.cpp @@ -240,7 +240,7 @@ void LIR_Assembler::arraycopy_type_check(Register src, Register src_pos, Registe } } -void LIR_Assembler::arraycopy_inlinetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check) { +void LIR_Assembler::arraycopy_valuetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check) { if (null_check) { __ beqz(obj, *slow_path->entry(), /* is_far */ true); } @@ -278,11 +278,11 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { return; } - if (flags & LIR_OpArrayCopy::src_inlinetype_check) { - arraycopy_inlinetype_check(src, tmp, stub, false, (flags & LIR_OpArrayCopy::src_null_check)); + if (flags & LIR_OpArrayCopy::src_valuetype_check) { + arraycopy_valuetype_check(src, tmp, stub, false, (flags & LIR_OpArrayCopy::src_null_check)); } - if (flags & LIR_OpArrayCopy::dst_inlinetype_check) { - arraycopy_inlinetype_check(dst, tmp, stub, true, (flags & LIR_OpArrayCopy::dst_null_check)); + if (flags & LIR_OpArrayCopy::dst_valuetype_check) { + arraycopy_valuetype_check(dst, tmp, stub, true, (flags & LIR_OpArrayCopy::dst_null_check)); } assert(default_type != nullptr && default_type->is_array_klass() && default_type->is_loaded(), diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.hpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.hpp index 5e0b559cc12b..e089d924985d 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.hpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.hpp @@ -47,6 +47,6 @@ Register dst, Register dst_pos); void arraycopy_load_args(Register src, Register src_pos, Register length, Register dst, Register dst_pos); - void arraycopy_inlinetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check); + void arraycopy_valuetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check); #endif // CPU_RISCV_C1_LIRASSEMBLER_ARRAYCOPY_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index b2473a9356e5..f42f842a9665 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -33,9 +33,9 @@ #include "c1/c1_Runtime1.hpp" #include "c1/c1_ValueStack.hpp" #include "ci/ciArrayKlass.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciInstance.hpp" #include "ci/ciObjArrayKlass.hpp" +#include "ci/ciValueKlass.hpp" #include "code/aotCodeCache.hpp" #include "code/compiledIC.hpp" #include "gc/shared/collectedHeap.hpp" @@ -387,7 +387,7 @@ int LIR_Assembler::emit_deopt_handler() { void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) { assert(result->is_illegal() || !result->is_single_cpu() || result->as_register() == x10, "word returns are in x10"); - assert(!InlineTypeReturnedAsFields, "unimplemented"); + assert(!ValueTypeReturnedAsFields, "unimplemented"); // Pop the stack before the safepoint code __ remove_frame(initial_frame_size_in_bytes()); @@ -402,7 +402,7 @@ void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) { __ ret(); } -int LIR_Assembler::store_inline_type_fields_to_buf(ciInlineKlass* vk) { +int LIR_Assembler::store_value_type_fields_to_buf(ciValueKlass* vk) { Unimplemented(); return 0; } @@ -1140,19 +1140,23 @@ void LIR_Assembler::typecheck_helper_slowcheck(ciKlass *k, Register obj, Registe } } -void LIR_Assembler::profile_object(ciMethodData* md, ciProfileData* data, Register obj, +void LIR_Assembler::profile_object(LIR_OpTypeCheck* op, ciMethodData* md, ciProfileData* data, Register obj, Register k_RInfo, Register klass_RInfo, Label* obj_is_null) { + assert (op->should_profile(), "tried to profile though we should not"); + Register mdo = klass_RInfo; __ mov_metadata(mdo, md->constant_encoding()); - Label not_null; - __ bnez(obj, not_null); - // Object is null, update MDO and exit - Address data_addr = __ form_address(t1, mdo, md->byte_offset_of_slot(data, DataLayout::flags_offset())); - __ lbu(t0, data_addr); - __ ori(t0, t0, BitData::null_seen_byte_constant()); - __ sb(t0, data_addr); - __ j(*obj_is_null); - __ bind(not_null); + if (op->need_null_check()) { + Label not_null; + __ bnez(obj, not_null); + // Object is null, update MDO and exit + Address data_addr = __ form_address(t1, mdo, md->byte_offset_of_slot(data, DataLayout::flags_offset())); + __ lbu(t0, data_addr); + __ ori(t0, t0, BitData::null_seen_byte_constant()); + __ sb(t0, data_addr); + __ j(*obj_is_null); + __ bind(not_null); + } Register recv = k_RInfo; __ load_klass(recv, obj); @@ -1196,12 +1200,10 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L assert_different_registers(obj, k_RInfo, klass_RInfo); - if (op->need_null_check()) { - if (should_profile) { - profile_object(md, data, obj, k_RInfo, klass_RInfo, obj_is_null); - } else { - __ beqz(obj, *obj_is_null); - } + if (should_profile) { + profile_object(op, md, data, obj, k_RInfo, klass_RInfo, obj_is_null); + } else if (op->need_null_check()) { + __ beqz(obj, *obj_is_null); } typecheck_loaded(op, k, k_RInfo); @@ -1285,25 +1287,25 @@ void LIR_Assembler::emit_opSubstitutabilityCheck(LIR_OpSubstitutabilityCheck* op ciKlass* left_klass = op->left_klass(); ciKlass* right_klass = op->right_klass(); - // (2) Inline type check -- if either of the operands is not a inline type, + // (2) Value type check -- if either of the operands is not a value type, // they are not substitutable. We do this only if we are not sure that the - // operands are inline type + // operands are value type if ((left_klass == nullptr || right_klass == nullptr) ||// The klass is still unloaded, or came from a Phi node. - !left_klass->is_inlinetype() || !right_klass->is_inlinetype()) { + !left_klass->is_value_klass() || !right_klass->is_value_klass()) { Register tmp1 = op->tmp1()->as_register(); Register tmp2 = op->tmp2()->as_register(); - __ mv(tmp1, markWord::inline_type_pattern); + __ mv(tmp1, markWord::value_type_pattern); __ ld(tmp2, Address(left, oopDesc::mark_offset_in_bytes())); __ andr(tmp1, tmp1, tmp2); __ ld(tmp2, Address(right, oopDesc::mark_offset_in_bytes())); __ andr(tmp1, tmp1, tmp2); - __ mv(tmp2, (u1)markWord::inline_type_pattern); + __ mv(tmp2, (u1)markWord::value_type_pattern); __ bne(tmp1, tmp2, L_oops_not_equal); } // (3) Same klass check: if the operands are of different klasses, they are not substitutable. - if (left_klass != nullptr && left_klass->is_inlinetype() && left_klass == right_klass) { - // No need to load klass -- the operands are statically known to be the same inline klass. + if (left_klass != nullptr && left_klass->is_value_klass() && left_klass == right_klass) { + // No need to load klass -- the operands are statically known to be the same value klass. __ j(*op->stub()->entry()); } else { Register left_klass_op = op->tmp1()->as_register(); @@ -1335,7 +1337,7 @@ void LIR_Assembler::emit_opSubstitutabilityCheck(LIR_OpSubstitutabilityCheck* op __ bind(L_end); } -void LIR_Assembler::emit_profile_inline_type(LIR_OpProfileInlineType* op) { +void LIR_Assembler::emit_profile_value_type(LIR_OpProfileValueType* op) { Register obj = op->obj()->as_register(); Register tmp = op->tmp()->as_pointer_register(); bool not_null = op->not_null(); @@ -1343,12 +1345,12 @@ void LIR_Assembler::emit_profile_inline_type(LIR_OpProfileInlineType* op) { assert_different_registers(tmp, t0, t1); - Label not_inline_type; + Label not_value_type; if (!not_null) { - __ beqz(obj, not_inline_type); + __ beqz(obj, not_value_type); } - __ test_oop_is_not_inline_type(obj, tmp, not_inline_type); + __ test_oop_is_not_value_type(obj, tmp, not_value_type); Address mdo_addr = as_Address(op->mdp()->as_address_ptr(), t1); __ lbu(tmp, mdo_addr); @@ -1356,7 +1358,7 @@ void LIR_Assembler::emit_profile_inline_type(LIR_OpProfileInlineType* op) { __ orr(tmp, tmp, t0); __ sb(tmp, mdo_addr); - __ bind(not_inline_type); + __ bind(not_value_type); } void LIR_Assembler::check_orig_pc() { @@ -2225,7 +2227,7 @@ void LIR_Assembler::typecheck_lir_store(LIR_OpTypeCheck* op, bool should_profile Label* failure_target = stub->entry(); if (should_profile) { - profile_object(md, data, value, k_RInfo, klass_RInfo, &done); + profile_object(op, md, data, value, k_RInfo, klass_RInfo, &done); } else { __ beqz(value, done); } diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp index 85e2e2866e9e..fb39211bca84 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp @@ -94,7 +94,7 @@ friend class ArrayCopyStub; void typecheck_helper_slowcheck(ciKlass* k, Register obj, Register Rtmp1, Register k_RInfo, Register klass_RInfo, Label* failure_target, Label* success_target); - void profile_object(ciMethodData* md, ciProfileData* data, Register obj, + void profile_object(LIR_OpTypeCheck* op, ciMethodData* md, ciProfileData* data, Register obj, Register k_RInfo, Register klass_RInfo, Label* obj_is_null); void typecheck_loaded(LIR_OpTypeCheck* op, ciKlass* k, Register k_RInfo); diff --git a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp index f4645bbd0a7e..7d872db8a5a2 100644 --- a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp @@ -283,7 +283,7 @@ void LIRGenerator::do_MonitorEnter(MonitorEnter* x) { } CodeStub* throw_ie_stub = - x->maybe_inlinetype() ? + x->maybe_valuetype() ? new SimpleExceptionStub(StubId::c1_throw_identity_exception_id, obj.result(), state_for(x)) : nullptr; @@ -864,7 +864,75 @@ void LIRGenerator::do_update_CRC32(Intrinsic* x) { } void LIRGenerator::do_update_CRC32C(Intrinsic* x) { - ShouldNotReachHere(); + assert(UseCRC32CIntrinsics, "why are we here?"); + LIR_Opr result = rlock_result(x); + + switch (x->id()) { + case vmIntrinsics::_updateBytesCRC32C: + case vmIntrinsics::_updateDirectByteBufferCRC32C: { + bool is_updateBytes = (x->id() == vmIntrinsics::_updateBytesCRC32C); + int offset = is_updateBytes ? arrayOopDesc::base_offset_in_bytes(T_BYTE) : 0; + + LIRItem crc(x->argument_at(0), this); + LIRItem buf(x->argument_at(1), this); + LIRItem off(x->argument_at(2), this); + LIRItem end(x->argument_at(3), this); + + buf.load_item(); + off.load_nonconstant(); + end.load_nonconstant(); + + // len = end - off + LIR_Opr tmpA = new_register(T_INT); + LIR_Opr tmpB = new_register(T_INT); + __ move(end.result(), tmpA); + __ move(off.result(), tmpB); + __ sub(tmpA, tmpB, tmpA); + LIR_Opr len = tmpA; + + LIR_Opr index = off.result(); + if (off.result()->is_constant()) { + index = LIR_OprFact::illegalOpr; + offset += off.result()->as_jint(); + } + LIR_Opr base_op = buf.result(); + + if (index->is_valid()) { + LIR_Opr tmp = new_register(T_LONG); + __ convert(Bytecodes::_i2l, index, tmp); + index = tmp; + } + + if (offset) { + LIR_Opr tmp = new_pointer_register(); + __ add(base_op, LIR_OprFact::intConst(offset), tmp); + base_op = tmp; + offset = 0; + } + + LIR_Address* a = new LIR_Address(base_op, index, offset, T_BYTE); + BasicTypeList signature(3); + signature.append(T_INT); + signature.append(T_ADDRESS); + signature.append(T_INT); + CallingConvention* cc = frame_map()->c_calling_convention(&signature); + const LIR_Opr result_reg = result_register_for(x->type()); + + LIR_Opr addr = new_register(T_ADDRESS); + __ leal(LIR_OprFact::address(a), addr); + + crc.load_item_force(cc->at(0)); + __ move(addr, cc->at(1)); + __ move(len, cc->at(2)); + + __ call_runtime_leaf(StubRoutines::updateBytesCRC32C(), getThreadTemp(), result_reg, cc->args()); + __ move(result_reg, result); + break; + } + default: { + ShouldNotReachHere(); + } + } } void LIRGenerator::do_FmaIntrinsic(Intrinsic* x) { @@ -921,7 +989,7 @@ void LIRGenerator::do_NewInstance(NewInstance* x) { CodeEmitInfo* info = state_for(x, x->needs_state_before() ? x->state_before() : x->state()); LIR_Opr reg = result_register_for(x->type()); new_instance(reg, x->klass(), x->is_unresolved(), - !x->is_unresolved() && x->klass()->is_inlinetype(), + !x->is_unresolved() && x->klass()->is_value_klass(), FrameMap::r12_oop_opr, FrameMap::r15_oop_opr, FrameMap::r14_oop_opr, diff --git a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp index 0f303deeb57f..836e2558414f 100644 --- a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp @@ -256,7 +256,7 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len, Register tmp1 void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, bool has_scalarized_args, - Label* verified_inline_entry_label) { + Label* verified_value_entry_label) { assert(bang_size_in_bytes >= frame_size_in_bytes, "stack bang size incorrect"); assert(!has_scalarized_args, ""); @@ -270,9 +270,9 @@ void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_by BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); bs->nmethod_entry_barrier(this, nullptr /* slow_path */, nullptr /* continuation */, nullptr /* guard */); - if (verified_inline_entry_label != nullptr) { + if (verified_value_entry_label != nullptr) { // Jump here from the scalarized entry points that already created the frame. - bind(*verified_inline_entry_label); + bind(*verified_value_entry_label); } } @@ -287,7 +287,7 @@ void C1_MacroAssembler::verified_entry(bool breakAtEntry) { } int C1_MacroAssembler::scalarized_entry(const CompiledEntrySignature* ces, int frame_size_in_bytes, int bang_size_in_bytes, - int sp_offset_for_orig_pc, Label& verified_inline_entry_label, bool is_inline_ro_entry) { + int sp_offset_for_orig_pc, Label& verified_value_entry_label, bool is_value_ro_entry) { Unimplemented(); return 0; } diff --git a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp index b031a4ce5cc3..8aa2f902f4a7 100644 --- a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp @@ -769,14 +769,14 @@ OopMapSet* Runtime1::generate_code_for(StubId id, StubAssembler* sasm) { __ beq(t0, tmp, ok); __ mv(t0, (int)Klass::_lh_array_tag_flat_value); // new "[LVT;" __ beq(t0, tmp, ok); - __ stop("assert(is an object or inline type array klass)"); + __ stop("assert(is an object or value type array klass)"); break; case StubId::c1_new_null_free_array_id: __ mv(t0, (int)Klass::_lh_array_tag_flat_value); // the array can be a flat array. __ beq(t0, tmp, ok); __ mv(t0, (int)Klass::_lh_array_tag_ref_value); // the array cannot be a flat array (due to the InlineArrayElementMaxFlatSize, etc.) __ beq(t0, tmp, ok); - __ stop("assert(is an object or inline type array klass)"); + __ stop("assert(is an object or value type array klass)"); break; default: ShouldNotReachHere(); } @@ -834,17 +834,17 @@ OopMapSet* Runtime1::generate_code_for(StubId id, StubAssembler* sasm) { } break; - case StubId::c1_buffer_inline_args_id: - case StubId::c1_buffer_inline_args_no_receiver_id: + case StubId::c1_buffer_value_args_id: + case StubId::c1_buffer_value_args_no_receiver_id: { - const char* name = (id == StubId::c1_buffer_inline_args_id) ? - "buffer_inline_args" : "buffer_inline_args_no_receiver"; + const char* name = (id == StubId::c1_buffer_value_args_id) ? + "buffer_value_args" : "buffer_value_args_no_receiver"; StubFrame f(sasm, name, dont_gc_arguments); OopMap* map = save_live_registers(sasm); Register method = x9; // Incoming - address entry = (id == StubId::c1_buffer_inline_args_id) ? - CAST_FROM_FN_PTR(address, buffer_inline_args) : - CAST_FROM_FN_PTR(address, buffer_inline_args_no_receiver); + address entry = (id == StubId::c1_buffer_value_args_id) ? + CAST_FROM_FN_PTR(address, buffer_value_args) : + CAST_FROM_FN_PTR(address, buffer_value_args_no_receiver); // This is called from a C1 method's scalarized entry point // where x10-x17 may be holding live argument values so we can't // return the result in x10 as the other stubs do. RA is used as diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index c2684982c140..1be4613579a5 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -354,15 +354,10 @@ void C2_MacroAssembler::fast_unlock(Register obj, Register box, bind(not_recursive); - const Register tmp2_owner_addr = tmp2; - - // Compute owner address. - la(tmp2_owner_addr, Address(tmp1_monitor, ObjectMonitor::owner_offset())); - // Set owner to null. // Release to satisfy the JMM membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); - sd(zr, Address(tmp2_owner_addr)); + sd(zr, Address(tmp1_monitor, ObjectMonitor::owner_offset())); // We need a full fence after clearing owner to avoid stranding. // StoreLoad achieves this. membar(StoreLoad); diff --git a/src/hotspot/cpu/riscv/downcallLinker_riscv.cpp b/src/hotspot/cpu/riscv/downcallLinker_riscv.cpp index e1511f5b7f34..ea8cdd94d557 100644 --- a/src/hotspot/cpu/riscv/downcallLinker_riscv.cpp +++ b/src/hotspot/cpu/riscv/downcallLinker_riscv.cpp @@ -227,9 +227,9 @@ void DowncallLinker::StubGenerator::generate() { _oop_maps->add_gc_map(the_pc - start, map); // State transition - __ mv(t0, _thread_in_native); + __ mv(t1, _thread_in_native); __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); - __ sw(t0, Address(xthread, JavaThread::thread_state_offset())); + __ sw(t1, Address(xthread, JavaThread::thread_state_offset())); __ block_comment("} thread java2native"); } diff --git a/src/hotspot/cpu/riscv/frame_riscv.cpp b/src/hotspot/cpu/riscv/frame_riscv.cpp index 20efa12d832f..a5bad8107334 100644 --- a/src/hotspot/cpu/riscv/frame_riscv.cpp +++ b/src/hotspot/cpu/riscv/frame_riscv.cpp @@ -620,7 +620,7 @@ frame::frame(void* ptr_sp, void* ptr_fp, void* pc) : _on_heap(false) { #endif -// Check for a method with scalarized inline type arguments that needs +// Check for a method with scalarized value type arguments that needs // a stack repair and return the repaired sender stack pointer. intptr_t* frame::repair_sender_sp(nmethod* nm, intptr_t* sp, intptr_t** saved_fp_addr) { diff --git a/src/hotspot/cpu/riscv/frame_riscv.hpp b/src/hotspot/cpu/riscv/frame_riscv.hpp index 981501641a2c..221cc3aa8eb0 100644 --- a/src/hotspot/cpu/riscv/frame_riscv.hpp +++ b/src/hotspot/cpu/riscv/frame_riscv.hpp @@ -182,7 +182,7 @@ } public: - // Support for scalarized inline type calling convention + // Support for scalarized value type calling convention static intptr_t* repair_sender_sp(nmethod* nm, intptr_t* sp, intptr_t** saved_fp_addr); bool was_augmented_on_entry(int& real_size) const; diff --git a/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad b/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad index 8b34679c90fb..e3141e61a239 100644 --- a/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad +++ b/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad @@ -284,7 +284,7 @@ instruct g1EncodePAndStoreN(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp t instruct g1CompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr) %{ - predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + predicate(UseG1GC && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); match(Set res (CompareAndExchangeP mem (Binary oldval newval))); effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -348,7 +348,7 @@ instruct g1CompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRe instruct g1CompareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) %{ - predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + predicate(UseG1GC && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); match(Set res (CompareAndExchangeN mem (Binary oldval newval))); effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -408,7 +408,7 @@ instruct g1CompareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRe instruct g1CompareAndSwapP(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP oldval, rFlagsReg cr) %{ - predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + predicate(UseG1GC && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); match(Set res (CompareAndSwapP mem (Binary oldval newval))); match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); @@ -472,7 +472,7 @@ instruct g1CompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP newval, iRegPNo instruct g1CompareAndSwapN(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegN oldval, rFlagsReg cr) %{ - predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + predicate(UseG1GC && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); match(Set res (CompareAndSwapN mem (Binary oldval newval))); match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); @@ -538,7 +538,7 @@ instruct g1CompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN newval, iRegPNo instruct g1GetAndSetP(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp preval, rFlagsReg cr) %{ - predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + predicate(UseG1GC && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); match(Set preval (GetAndSetP mem newval)); effect(TEMP preval, TEMP tmp1, TEMP tmp2, KILL cr); ins_cost(2 * VOLATILE_REF_COST); @@ -590,7 +590,7 @@ instruct g1GetAndSetPAcq(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp t instruct g1GetAndSetN(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegNNoSp preval, rFlagsReg cr) %{ - predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + predicate(UseG1GC && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); match(Set preval (GetAndSetN mem newval)); effect(TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); ins_cost(2 * VOLATILE_REF_COST); diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp index f0f5abbfcaf9..c52fcf011b6f 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp @@ -137,15 +137,15 @@ void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators } void BarrierSetAssembler::flat_field_copy(MacroAssembler* masm, DecoratorSet decorators, - Register src, Register dst, Register inline_layout_info) { + Register src, Register dst, Register value_field_layout_info) { // flat_field_copy implementation is fairly complex, and there are not any // "short-cuts" to be made from asm. What there is, appears to have the same // cost in C++, so just "call_VM_leaf" for now rather than maintain hundreds // of hand-rolled instructions... if (decorators & IS_DEST_UNINITIALIZED) { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetRuntime::value_copy_is_dest_uninitialized), src, dst, inline_layout_info); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetRuntime::value_copy_is_dest_uninitialized), src, dst, value_field_layout_info); } else { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetRuntime::value_copy), src, dst, inline_layout_info); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetRuntime::value_copy), src, dst, value_field_layout_info); } } diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp index e9f330b2f4e2..0e159dfbc98b 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp @@ -76,7 +76,7 @@ class BarrierSetAssembler: public CHeapObj { Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); virtual void flat_field_copy(MacroAssembler* masm, DecoratorSet decorators, - Register src, Register dst, Register inline_layout_info); + Register src, Register dst, Register value_field_layout_info); virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, Register obj, Register tmp, Label& slowpath); diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp index 3fd8483ce138..74c676652cbc 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp @@ -77,11 +77,11 @@ static int* decode_guard_from_instruction(nmethod* nm, address& instruction) { // // The mapping of C1-compiled methods (scalarization used) looks as follows: // * alt1: verified entry point -// * alt2 (optional): verified inline ro entry point +// * alt2 (optional): verified value ro entry point // // The mapping of C2-compiled methods (scalarization used) looks as follows: -// * alt1: verified inline entry point -// * alt2 (optional): verified inline ro entry point +// * alt1: verified value entry point +// * alt2 (optional): verified value ro entry point // // In other scenarios, neither alt1 nor alt2 are defined. class NativeNMethodBarrier { diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp index 7e7781531353..0138046288b2 100644 --- a/src/hotspot/cpu/riscv/globals_riscv.hpp +++ b/src/hotspot/cpu/riscv/globals_riscv.hpp @@ -76,8 +76,8 @@ define_pd_global(intx, InitArrayShortSize, BytesPerLong); define_pd_global(intx, InlineSmallCode, 1000); -define_pd_global(bool, InlineTypePassFieldsAsArgs, false); -define_pd_global(bool, InlineTypeReturnedAsFields, false); +define_pd_global(bool, ValueTypePassFieldsAsArgs, false); +define_pd_global(bool, ValueTypeReturnedAsFields, false); #define ARCH_FLAGS(develop, \ product, \ @@ -104,6 +104,7 @@ define_pd_global(bool, InlineTypeReturnedAsFields, false); product(bool, UseRVV, false, DIAGNOSTIC, "Use RVV instructions") \ product(bool, UseZba, false, DIAGNOSTIC, "Use Zba instructions") \ product(bool, UseZbb, false, DIAGNOSTIC, "Use Zbb instructions") \ + product(bool, UseZbc, false, DIAGNOSTIC, "Use Zbc instructions") \ product(bool, UseZbkb, false, EXPERIMENTAL, "Use Zbkb instructions") \ product(bool, UseZbs, false, DIAGNOSTIC, "Use Zbs instructions") \ product(bool, UseZfa, false, DIAGNOSTIC, "Use Zfa instructions") \ diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp index 802cf7eac674..0c266d5de29c 100644 --- a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp @@ -36,10 +36,10 @@ #include "oops/markWord.hpp" #include "oops/method.hpp" #include "oops/methodData.hpp" -#include "oops/inlineKlass.hpp" #include "oops/resolvedFieldEntry.hpp" #include "oops/resolvedIndyEntry.hpp" #include "oops/resolvedMethodEntry.hpp" +#include "oops/valueKlass.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiThreadState.hpp" #include "runtime/basicLock.hpp" @@ -1287,18 +1287,18 @@ void InterpreterMacroAssembler::profile_acmp(Register mdp, mv(tmp, left); profile_obj_type(tmp, Address(mdp, in_bytes(ACmpData::left_offset())), t1); - Label left_not_inline_type; - test_oop_is_not_inline_type(left, tmp, left_not_inline_type); - set_mdp_flag_at(mdp, ACmpData::left_inline_type_byte_constant()); - bind(left_not_inline_type); + Label left_not_value_type; + test_oop_is_not_value_type(left, tmp, left_not_value_type); + set_mdp_flag_at(mdp, ACmpData::left_value_type_byte_constant()); + bind(left_not_value_type); mv(tmp, right); profile_obj_type(tmp, Address(mdp, in_bytes(ACmpData::right_offset())), t1); - Label right_not_inline_type; - test_oop_is_not_inline_type(right, tmp, right_not_inline_type); - set_mdp_flag_at(mdp, ACmpData::right_inline_type_byte_constant()); - bind(right_not_inline_type); + Label right_not_value_type; + test_oop_is_not_value_type(right, tmp, right_not_value_type); + set_mdp_flag_at(mdp, ACmpData::right_value_type_byte_constant()); + bind(right_not_value_type); bind(profile_continue); } @@ -1877,7 +1877,7 @@ void InterpreterMacroAssembler::write_flat_field(Register entry, Register field_ Label slow_path, done; load_unsigned_byte(tmp1, Address(entry, in_bytes(ResolvedFieldEntry::flags_offset()))); - test_field_is_not_null_free_inline_type(tmp1, tmp2, slow_path); + test_field_is_not_null_free_value_type(tmp1, tmp2, slow_path); null_check(x10); // FIXME JDK-8341120 @@ -1889,7 +1889,7 @@ void InterpreterMacroAssembler::write_flat_field(Register entry, Register field_ Register layout_info = field_offset; load_unsigned_short(tmp1, Address(entry, in_bytes(ResolvedFieldEntry::field_index_offset()))); ld(tmp2, Address(entry, in_bytes(ResolvedFieldEntry::field_holder_offset()))); - inline_layout_info(tmp2, tmp1, layout_info); + value_field_layout_info(tmp2, tmp1, layout_info); flat_field_copy(IN_HEAP, x10, obj, layout_info); j(done); diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.hpp b/src/hotspot/cpu/riscv/interp_masm_riscv.hpp index 2b6115a9302f..81ce0fa0f9ea 100644 --- a/src/hotspot/cpu/riscv/interp_masm_riscv.hpp +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.hpp @@ -161,7 +161,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void get_cache_index_at_bcp(Register index, Register tmp, int bcp_offset, size_t index_size = sizeof(u2)); void get_method_counters(Register method, Register mcs, Label& skip); - // Allocate instance in "obj" and read in the content of the inline field + // Allocate instance in "obj" and read in the content of the value field // NOTES: // - input holder object via "obj", which must be x10, // will return new instance via the same reg diff --git a/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp b/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp index dcdbe4a6dc18..ffcb4086cf1d 100644 --- a/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp +++ b/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp @@ -105,10 +105,10 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { bs->try_resolve_jobject_in_native(masm, c_rarg0, robj, t0, slow); __ srli(roffset, c_rarg2, jfieldIDWorkaround::offset_shift); // offset + __ add(roffset, robj, roffset); assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); speculative_load_pclist[count] = __ pc(); // Used by the segfault handler - __ add(roffset, robj, roffset); switch (type) { case T_BOOLEAN: __ lbu(result, Address(roffset, 0)); break; diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 2f44cf42dc37..e778dde7d43c 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -27,7 +27,7 @@ #include "asm/assembler.hpp" #include "asm/assembler.inline.hpp" #include "cds/archiveBuilder.hpp" -#include "ci/ciInlineKlass.hpp" +#include "ci/ciValueKlass.hpp" #include "code/aotCodeCache.hpp" #include "code/compiledIC.hpp" #include "compiler/disassembler.hpp" @@ -541,7 +541,7 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file, // The length of the instruction sequence emitted should not depend // on the address of the char buffer so that the size of mach nodes for // scratch emit and normal emit matches. - la(t0, ExternalAddress((address)b)); + la(t0, Address((address)b, external_word_Relocation::spec_for_immediate())); // Call indirectly to solve generation ordering problem ld(t1, RuntimeAddress(StubRoutines::verify_oop_subroutine_entry_address())); @@ -738,7 +738,7 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* f // The length of the instruction sequence emitted should not depend // on the address of the char buffer so that the size of mach nodes for // scratch emit and normal emit matches. - la(t0, ExternalAddress((address)b)); + la(t0, Address((address)b, external_word_Relocation::spec_for_immediate())); // Call indirectly to solve generation ordering problem ld(t1, RuntimeAddress(StubRoutines::verify_oop_subroutine_entry_address())); @@ -2762,6 +2762,184 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, andn(crc, tmp5, crc); } +// Advance buf to the next 8-byte boundary, folding each byte into crc via the +// byte lookup table. tmp1 holds the alignment count, tmp2 the loaded byte. +void MacroAssembler::kernel_crc32c_clmul_align(Register crc, Register buf, Register len, + Register table, Register tmp1, Register tmp2) { + assert_different_registers(crc, buf, len, table, tmp1, tmp2); + Label L_adjust, L_loop, L_done; + + // bytes to next 8-byte boundary: (-buf) & 7 = 8 - (buf & 7) + neg(tmp1, buf); + andi(tmp1, tmp1, 7); + + // tmp1 = min(tmp1, len) + bleu(tmp1, len, L_adjust); + mv(tmp1, len); + bind(L_adjust); + subw(len, len, tmp1); + beqz(tmp1, L_done); + + bind(L_loop); + lbu(tmp2, Address(buf, 0)); + addi(buf, buf, 1); + update_byte_crc32(crc, tmp2, table); + addi(tmp1, tmp1, -1); + bnez(tmp1, L_loop); + bind(L_done); +} + +// Fold 128 bits of input into the 128-bit accumulator (accum_hi:accum_lo). +// With the next 16 input bytes as (data_hi:data_lo) and * = carry-less mul: +// accum_lo' = (accum_lo*k1)[63:0] XOR (accum_hi*k2)[63:0] XOR data_lo +// accum_hi' = (accum_lo*k1)[127:64] XOR (accum_hi*k2)[127:64] XOR data_hi +void MacroAssembler::kernel_crc32c_clmul_fold_128(Register accum_lo, Register accum_hi, + Register k1, Register k2, Register buf, Register tmp1, Register tmp2) { + assert_different_registers(accum_lo, accum_hi, k1, k2, buf, tmp1, tmp2); + + clmul(tmp1, accum_lo, k1); + clmulh(tmp2, accum_lo, k1); + + clmul(accum_lo, accum_hi, k2); + clmulh(accum_hi, accum_hi, k2); + + xorr(accum_lo, accum_lo, tmp1); + ld(tmp1, Address(buf, 0)); // tmp1 = data_lo + xorr(accum_lo, accum_lo, tmp1); + + xorr(accum_hi, accum_hi, tmp2); + ld(tmp1, Address(buf, 8)); // tmp1 = data_hi + xorr(accum_hi, accum_hi, tmp1); +} + +// Reduce the 128-bit accumulator (accum_hi:accum_lo) to 64 bits using the +// ISA-L two-constant method. With rk1 at OFF_REDUCE_HI and rk2 at OFF_REDUCE_LO: +// x = accum_lo +// y0 = accum_hi XOR clmul(x, rk1)[63:0] +// y1 = clmulh(x, rk1)[95:64] +// accum_lo' = clmul(y0[31:0], rk2)[63:0] XOR (y1 : y0[63:32]) +void MacroAssembler::kernel_crc32c_clmul_reduce_128_to_64(Register accum_lo, Register accum_hi, + Register clmul_table, Register k, Register tmp1, Register tmp2) { + assert_different_registers(accum_lo, accum_hi, clmul_table, k, tmp1, tmp2); + + const int OFF_REDUCE_LO = 16; + const int OFF_REDUCE_HI = 24; + + ld(k, Address(clmul_table, OFF_REDUCE_HI)); + clmul(tmp1, accum_lo, k); // tmp1 = clmul(x, rk1)[63:0] + clmulh(tmp2, accum_lo, k); // tmp2 = clmulh(x, rk1) = clmul(x, rk1)[127:64] + + xorr(accum_hi, accum_hi, tmp1); // y0 = accum_hi XOR clmul(x, rk1)[63:0] + + zext(tmp1, accum_hi, 32); // tmp1 = y0[31:0] + srli(accum_hi, accum_hi, 32); // accum_hi = y0[63:32] + + ld(k, Address(clmul_table, OFF_REDUCE_LO)); + clmul(accum_lo, tmp1, k); // accum_lo' = clmul(y0[31:0], rk2)[63:0] + + slli(tmp2, tmp2, 32); // tmp2 = clmul(x, rk1)[95:64] << 32 = y1 : 0 + xorr(tmp2, tmp2, accum_hi); // tmp2 = y1 : y0[63:32] + xorr(accum_lo, accum_lo, tmp2); // accum_lo' XOR= (y1 : y0[63:32]) +} + +// Reduce the 64-bit accumulator accum_lo to a residue mod P (the 33-bit +// CRC32C polynomial) using Barrett reduction, with mu = floor(x^64/P) at +// OFF_BARRETT_MU and poly = P at OFF_BARRETT_POLY: +// q = (accum_lo[31:0] * mu)[31:0] // quotient estimate +// accum_lo XOR= (q * poly)[63:0] // subtract q*P +// The high 32 bits of accum_lo then hold the final CRC. +void MacroAssembler::kernel_crc32c_clmul_barrett_64_to_32(Register accum_lo, Register clmul_table, + Register k, Register tmp) { + assert_different_registers(accum_lo, clmul_table, k, tmp); + + const int OFF_BARRETT_MU = 32; + const int OFF_BARRETT_POLY = 40; + + zext(tmp, accum_lo, 32); // tmp = accum_lo[31:0] + + ld(k, Address(clmul_table, OFF_BARRETT_MU)); + clmul(tmp, tmp, k); + zext(tmp, tmp, 32); // tmp = q = (accum_lo[31:0] * mu)[31:0] + + ld(k, Address(clmul_table, OFF_BARRETT_POLY)); + clmul(tmp, tmp, k); + + xorr(accum_lo, accum_lo, tmp); +} + +void MacroAssembler::kernel_crc32c_clmul_fold(Register crc, Register buf, Register len, + Register byte_table, Register clmul_table, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register tmp6) { + assert_different_registers(crc, buf, len, byte_table, clmul_table, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6); + Label L_fold_loop, L_tail, L_tail_loop, L_exit; + + const int FOLD_THRESHOLD = 64; // fold only for inputs >= 4 FOLD_STEPs + const int FOLD_STEP = 16; + const int OFF_FOLD_K1 = 0; + const int OFF_FOLD_K2 = 8; + + mv(tmp4, FOLD_THRESHOLD); + blt(len, tmp4, L_tail); + + kernel_crc32c_clmul_align(crc, buf, len, byte_table, tmp4, tmp5); + beqz(len, L_exit); + + // fold_end = buf + len - (len mod 16); len = tail + const Register fold_end = tmp6; + add(fold_end, buf, len); + andi(len, len, FOLD_STEP - 1); + sub(fold_end, fold_end, len); + + // accum = (buf[0:8] XOR crc) : buf[8:16] + const Register accum_lo = crc; + const Register accum_hi = tmp1; + ld(tmp4, Address(buf, 0)); + xorr(accum_lo, tmp4, crc); + ld(accum_hi, Address(buf, 8)); + addi(buf, buf, FOLD_STEP); + + ld(tmp2, Address(clmul_table, OFF_FOLD_K1)); + ld(tmp3, Address(clmul_table, OFF_FOLD_K2)); + + bind(L_fold_loop); + kernel_crc32c_clmul_fold_128(accum_lo, accum_hi, tmp2, tmp3, buf, tmp4, tmp5); + addi(buf, buf, 16); + blt(buf, fold_end, L_fold_loop); + + // reduce 128->64 (ISA-L) then 64->32 (Barrett); tmp2 = k; tmp4..tmp5 reused as scratch + kernel_crc32c_clmul_reduce_128_to_64(accum_lo, accum_hi, clmul_table, tmp2, tmp4, tmp5); + kernel_crc32c_clmul_barrett_64_to_32(accum_lo, clmul_table, tmp2, tmp4); + srli(crc, accum_lo, 32); + + bind(L_tail); + add(tmp5, buf, len); // tmp5 = tail_end + bind(L_tail_loop); + bgeu(buf, tmp5, L_exit); + lbu(tmp4, Address(buf, 0)); + addi(buf, buf, 1); + update_byte_crc32(crc, tmp4, byte_table); + j(L_tail_loop); + + bind(L_exit); +} + +void MacroAssembler::kernel_crc32c(Register crc, Register buf, Register len, + Register byte_table, Register clmul_table, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register tmp6) { + assert_different_registers(crc, buf, len, byte_table, clmul_table, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6); + + zext(crc, crc, 32); + + // _crc32c_table is followed by the clmul constants + const int64_t single_table_size = 256; + const ExternalAddress table_addr = StubRoutines::crc32c_table_addr(); + la(byte_table, table_addr); + add(clmul_table, byte_table, 1 * single_table_size * sizeof(juint), tmp4); + + kernel_crc32c_clmul_fold(crc, buf, len, byte_table, clmul_table, + tmp1, tmp2, tmp3, tmp4, tmp5, tmp6); +} + #ifdef COMPILER2 // Push vector registers in the bitset supplied. // Return the number of words pushed @@ -3626,9 +3804,9 @@ void MacroAssembler::mov_metadata(Register dst, Metadata* obj) { movptr(dst, Address((address)obj, rspec)); } -void MacroAssembler::inline_layout_info(Register holder_klass, Register index, Register layout_info) { +void MacroAssembler::value_field_layout_info(Register holder_klass, Register index, Register layout_info) { assert_different_registers(holder_klass, index, layout_info); - InlineLayoutInfo array[2]; + ValueFieldLayoutInfo array[2]; int size = (char*)&array[1] - (char*)&array[0]; // computing size of array elements if (is_power_of_2(size)) { slli(index, index, log2i_exact(size)); // Scale index by power of 2 @@ -3636,28 +3814,28 @@ void MacroAssembler::inline_layout_info(Register holder_klass, Register index, R mv(layout_info, size); mul(index, index, layout_info); // Scale the index to be the entry index * array_element_size } - ld(layout_info, Address(holder_klass, InstanceKlass::inline_layout_info_array_offset())); - add(layout_info, layout_info, Array::base_offset_in_bytes()); + ld(layout_info, Address(holder_klass, InstanceKlass::value_field_layout_info_array_offset())); + add(layout_info, layout_info, Array::base_offset_in_bytes()); add(layout_info, layout_info, index); la(layout_info, Address(layout_info)); } void MacroAssembler::flat_field_copy(DecoratorSet decorators, Register src, Register dst, - Register inline_layout_info) { + Register value_field_layout_info) { BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); - bs->flat_field_copy(this, decorators, src, dst, inline_layout_info); + bs->flat_field_copy(this, decorators, src, dst, value_field_layout_info); } -void MacroAssembler::payload_offset(Register inline_klass, Register offset) { - ld(offset, Address(inline_klass, InlineKlass::adr_members_offset())); - lwu(offset, Address(offset, InlineKlass::payload_offset_offset())); +void MacroAssembler::payload_offset(Register value_klass, Register offset) { + ld(offset, Address(value_klass, ValueKlass::adr_members_offset())); + lwu(offset, Address(offset, ValueKlass::payload_offset_offset())); } -void MacroAssembler::payload_address(Register oop, Register data, Register inline_klass) { +void MacroAssembler::payload_address(Register oop, Register data, Register value_klass) { assert_different_registers(data, t0); // ((address) (void*) o) + vk->payload_offset(); Register offset = (data == oop) ? t0 : data; - payload_offset(inline_klass, offset); + payload_offset(value_klass, offset); if (data == oop) { add(data, data, offset); } else { @@ -3751,14 +3929,14 @@ void MacroAssembler::null_check(Register reg, int offset) { } } -void MacroAssembler::test_field_is_null_free_inline_type(Register flags, Register temp_reg, Label& is_null_free_inline_type) { - test_bit(temp_reg, flags, ResolvedFieldEntry::is_null_free_inline_type_shift); - bnez(temp_reg, is_null_free_inline_type); +void MacroAssembler::test_field_is_null_free_value_type(Register flags, Register temp_reg, Label& is_null_free_value_type) { + test_bit(temp_reg, flags, ResolvedFieldEntry::is_null_free_value_type_shift); + bnez(temp_reg, is_null_free_value_type); } -void MacroAssembler::test_field_is_not_null_free_inline_type(Register flags, Register temp_reg, Label& not_null_free_inline_type) { - test_bit(temp_reg, flags, ResolvedFieldEntry::is_null_free_inline_type_shift); - beqz(temp_reg, not_null_free_inline_type); +void MacroAssembler::test_field_is_not_null_free_value_type(Register flags, Register temp_reg, Label& not_null_free_value_type) { + test_bit(temp_reg, flags, ResolvedFieldEntry::is_null_free_value_type_shift); + beqz(temp_reg, not_null_free_value_type); } void MacroAssembler::test_field_is_flat(Register flags, Register temp_reg, Label& is_flat) { @@ -3766,24 +3944,24 @@ void MacroAssembler::test_field_is_flat(Register flags, Register temp_reg, Label bnez(temp_reg, is_flat); } -void MacroAssembler::test_markword_is_inline_type(Register markword, Label& is_inline_type) { +void MacroAssembler::test_markword_is_value_type(Register markword, Label& is_value_type) { assert_different_registers(markword, t1); - mv(t1, markWord::inline_type_pattern_mask); + mv(t1, markWord::value_type_pattern_mask); andr(markword, markword, t1); - mv(t1, markWord::inline_type_pattern); - beq(markword, t1, is_inline_type); + mv(t1, markWord::value_type_pattern); + beq(markword, t1, is_value_type); } -void MacroAssembler::test_oop_is_not_inline_type(Register object, Register tmp, Label& not_inline_type, bool can_be_null) { +void MacroAssembler::test_oop_is_not_value_type(Register object, Register tmp, Label& not_value_type, bool can_be_null) { assert_different_registers(tmp, t0); if (can_be_null) { - beqz(object, not_inline_type); + beqz(object, not_value_type); } - const int is_inline_type_mask = markWord::inline_type_pattern; + const int is_value_type_mask = markWord::value_type_pattern; ld(tmp, Address(object, oopDesc::mark_offset_in_bytes())); - mv(t0, is_inline_type_mask); + mv(t0, is_value_type_mask); andr(tmp, tmp, t0); - bne(tmp, t0, not_inline_type); + bne(tmp, t0, not_value_type); } void MacroAssembler::test_oop_prototype_bit(Register oop, Register temp_reg, int32_t tst_bit, bool jmp_set, Label& jmp_label) { @@ -5507,26 +5685,26 @@ bool MacroAssembler::move_helper(VMReg from, VMReg to, BasicType bt, RegState re return false; } -// Read all fields from an inline type oop and store the values in registers/stack slots -bool MacroAssembler::unpack_inline_helper(const GrowableArray* sig, int& sig_index, - VMReg from, int& from_index, VMRegPair* to, int to_count, int& to_index, - RegState reg_state[]) { +// Read all fields from a value type oop and store the values in registers/stack slots +bool MacroAssembler::unpack_value_helper(const GrowableArray* sig, int& sig_index, + VMReg from, int& from_index, VMRegPair* to, int to_count, int& to_index, + RegState reg_state[]) { Unimplemented(); return false; } -// Pack fields back into an inline type oop -bool MacroAssembler::pack_inline_helper(const GrowableArray* sig, int& sig_index, int vtarg_index, - VMRegPair* from, int from_count, int& from_index, VMReg to, - RegState reg_state[], Register val_array) { +// Pack fields back into a value type oop +bool MacroAssembler::pack_value_helper(const GrowableArray* sig, int& sig_index, int vtarg_index, + VMRegPair* from, int from_count, int& from_index, VMReg to, + RegState reg_state[], Register val_array) { Unimplemented(); return false; } -// Calculate the extra stack space required for packing or unpacking inline +// Calculate the extra stack space required for packing or unpacking value // args and adjust the stack pointer -int MacroAssembler::extend_stack_for_inline_args(int args_on_stack) { +int MacroAssembler::extend_stack_for_value_args(int args_on_stack) { Unimplemented(); return false; } @@ -7134,8 +7312,8 @@ void MacroAssembler::fast_lock(Register basic_lock, Register obj, Register tmp1, assert(oopDesc::mark_offset_in_bytes() == 0, "required to avoid a la"); ori(mark, mark, markWord::lock_neutral_value); if (Arguments::is_valhalla_enabled()) { - // Mask inline_type bit such that we go to the slow path if object is an inline type - andi(mark, mark, ~((int) markWord::inline_type_bit_in_place)); + // Mask value_type bit such that we go to the slow path if object is a value type + andi(mark, mark, ~((int) markWord::value_type_bit_in_place)); } xori(t, mark, markWord::lock_neutral_value); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index be684c5ec908..fc5bcee88226 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -35,7 +35,7 @@ #include "utilities/powerOfTwo.hpp" #include "runtime/signature.hpp" -class ciInlineKlass; +class ciValueKlass; // MacroAssembler extends Assembler by frequently used macros. // @@ -254,12 +254,12 @@ class MacroAssembler: public Assembler { static bool needs_explicit_null_check(intptr_t offset); static bool uses_implicit_null_check(void* address); - void test_field_is_null_free_inline_type(Register flags, Register temp_reg, Label& is_null_free); - void test_field_is_not_null_free_inline_type(Register flags, Register temp_reg, Label& not_null_free_inline_type); + void test_field_is_null_free_value_type(Register flags, Register temp_reg, Label& is_null_free); + void test_field_is_not_null_free_value_type(Register flags, Register temp_reg, Label& not_null_free_value_type); void test_field_is_flat(Register flags, Register temp_reg, Label& is_flat); - void test_markword_is_inline_type(Register markword, Label& is_inline_type); - void test_oop_is_not_inline_type(Register object, Register tmp, Label& not_inline_type, bool can_be_null = true); + void test_markword_is_value_type(Register markword, Label& is_value_type); + void test_oop_is_not_value_type(Register object, Register tmp, Label& not_value_type, bool can_be_null = true); void test_oop_prototype_bit(Register oop, Register temp_reg, int32_t tst_bit, bool jmp_set, Label& jmp_label); void test_flat_array_oop(Register klass, Register temp_reg, Label& is_flat_array); void test_null_free_array_oop(Register oop, Register temp_reg, Label& is_null_free_array); @@ -269,13 +269,13 @@ class MacroAssembler: public Assembler { // Check array klass layout helper for flat or null-free arrays... void test_flat_array_layout(Register lh, Label& is_flat_array); - void inline_layout_info(Register holder_klass, Register index, Register layout_info); + void value_field_layout_info(Register holder_klass, Register index, Register layout_info); - void flat_field_copy(DecoratorSet decorators, Register src, Register dst, Register inline_layout_info); + void flat_field_copy(DecoratorSet decorators, Register src, Register dst, Register value_field_layout_info); - // inline type data payload offsets... - void payload_offset(Register inline_klass, Register offset); - void payload_address(Register oop, Register data, Register inline_klass); + // value type data payload offsets... + void payload_offset(Register value_klass, Register offset); + void payload_address(Register oop, Register data, Register value_klass); // interface method calling void lookup_interface_method(Register recv_klass, @@ -1405,6 +1405,23 @@ class MacroAssembler: public Assembler { bool upper); void update_byte_crc32(Register crc, Register val, Register table); + // CRC32C code for java.util.zip.CRC32C::updateBytes() intrinsic, + // accelerated with Zbc carry-less multiplication (clmul/clmulh). + void kernel_crc32c(Register crc, Register buf, Register len, + Register byte_table, Register clmul_table, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register tmp6); + void kernel_crc32c_clmul_fold(Register crc, Register buf, Register len, + Register byte_table, Register clmul_table, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register tmp6); + void kernel_crc32c_clmul_align(Register crc, Register buf, Register len, + Register table, Register tmp1, Register tmp2); + void kernel_crc32c_clmul_fold_128(Register accum_lo, Register accum_hi, + Register k1, Register k2, Register buf, Register tmp1, Register tmp2); + void kernel_crc32c_clmul_reduce_128_to_64(Register accum_lo, Register accum_hi, + Register clmul_table, Register k, Register tmp1, Register tmp2); + void kernel_crc32c_clmul_barrett_64_to_32(Register accum_lo, Register clmul_table, + Register k, Register tmp); + #ifdef COMPILER2 void vector_update_crc32(Register crc, Register buf, Register len, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, @@ -1847,7 +1864,7 @@ class MacroAssembler: public Assembler { static void set_membar_kind(address addr, uint32_t order_kind); public: - // Inline type specific methods + // Value type specific methods #include "asm/macroAssembler_common.hpp" }; diff --git a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp index 3f7f4a34f4a0..57444667fd24 100644 --- a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp +++ b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp @@ -166,11 +166,11 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth __ BIND(run_compiled_code); } - // The following jump might pass an inline type argument that was erased to Object as oop to a - // callee that expects inline type arguments to be passed as fields. We need to call the compiled - // value entry (_code->inline_entry_point() or _adapter->c2i_inline_entry()) which will take care + // The following jump might pass a value type argument that was erased to Object as oop to a + // callee that expects value type arguments to be passed as fields. We need to call the compiled + // value entry (_code->value_entry_point() or _adapter->c2i_value_entry()) which will take care // of translating between the calling conventions. - const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_inline_offset() : + const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_value_offset() : Method::from_interpreted_offset(); __ ld(t1, Address(method, entry_offset)); __ jr(t1); diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index f8b9acd18a90..8e42db38cfa9 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1066,6 +1066,11 @@ public: bool is_CAS(int opcode, bool maybe_volatile); +// predicate controlling emit of fence before and after CAS +bool cas_membar_elidable(int opcode); +bool unnecessary_acquire(const Node *barrier); +bool unnecessary_release(const Node *barrier); + // predicate controlling translation of CompareAndSwapX bool needs_acquiring_load_reserved(const Node *load); @@ -1174,6 +1179,138 @@ bool is_CAS(int opcode, bool maybe_volatile) } } +// predicates controlling emit of fence before and after CAS + +// Return true if the leading MemBarRelease and trailing MemBarAcquire around a +// CAS-like LoadStore node may be elided, that is if the node is matched to a +// single AMO instruction carrying both the aq and rl annotations: +// amoswap/amoadd/amocas with .aqrl. +// +// Such an AMO is fully-ordered under RVWMO: PPO rule 5 orders it, including +// its store, before every subsequent memory access, and PPO rule 6 orders +// every preceding access before it. That subsumes both membars. +// +// An LR/SC based CAS is weaker. lr.aq + sc.rl only provides release-acquire, +// not a sequentially consistent read-modify-write: the aq annotation sits on +// the LR, so PPO rule 5 orders the *load* before later accesses, while the rl +// annotation sits on the SC, so PPO rule 6 only orders earlier accesses before +// the *store*. Nothing orders the SC's store before a subsequent load, so that +// store may still be buffered when a load of an unrelated address is +// satisfied. +// +// Emitting the membars does not supply that missing StoreLoad edge either, +// since MemBarAcquire lowers to `fence r,rw`, whose predecessor set holds only +// reads. Java code that needs the edge has to request it explicitly, and code +// which fails to do so can lose a wakeup; see JDK-8387644. Elision is +// nevertheless restricted here to the fully-ordered AMO forms, so that the +// LR/SC path keeps the strength it had before the membars started being +// elided. The leading MemBarRelease on its own would be safe to elide for +// LR/SC too, since the rl annotation on the SC covers it by PPO rule 6, but +// both are gated together to keep the two predicates symmetric. +// +// Whether the aq annotation is actually set is decided per node by +// needs_acquiring_load_reserved(), which selects the *Acq instruct variants. +// It holds for every opcode listed below on the paths reaching the two callers, +// which assert as much. +bool cas_membar_elidable(int opcode) +{ + assert(is_CAS(opcode, true), "expecting a compare and swap"); + + switch (opcode) { + // Always matched to the acquiring variant, hence amoswap/amoadd.aqrl. + case Op_GetAndSetI: + case Op_GetAndSetL: + case Op_GetAndSetP: + case Op_GetAndSetN: + case Op_GetAndAddI: + case Op_GetAndAddL: + return true; + // Matched to amocas.{w|d}.aqrl only when Zacas is available. + case Op_CompareAndSwapI: + case Op_CompareAndSwapL: + case Op_CompareAndSwapP: + case Op_CompareAndSwapN: + case Op_CompareAndExchangeI: + case Op_CompareAndExchangeL: + case Op_CompareAndExchangeP: + case Op_CompareAndExchangeN: + case Op_WeakCompareAndSwapI: + case Op_WeakCompareAndSwapL: + case Op_WeakCompareAndSwapP: + case Op_WeakCompareAndSwapN: + return UseZacas; + // Sub-word forms additionally require Zabha for amocas.{b|h}. Without it + // they are open coded around a narrow lr.w/sc.w or amocas.w, see + // cmpxchg_narrow_value(). The Zacas variant of that sequence can leave + // through its failure path having executed nothing but a plain lw, so it + // carries no ordering at all and its membars must be kept. + case Op_CompareAndSwapB: + case Op_CompareAndSwapS: + case Op_CompareAndExchangeB: + case Op_CompareAndExchangeS: + case Op_WeakCompareAndSwapB: + case Op_WeakCompareAndSwapS: + return UseZacas && UseZabha; + default: + return false; + } +} + +bool unnecessary_acquire(const Node *barrier) +{ + assert(barrier->is_MemBar(), "expecting a membar"); + + MemBarNode* mb = barrier->as_MemBar(); + + if (mb->trailing_load()) { + // A regular RISC-V load cannot provide acquire semantics on its own, so + // the trailing MemBarAcquire must be kept. This may return true when the + // Zalasr extension is supported and the load is matched to l{b|h|w|d}.aq. + return false; + } + + if (mb->trailing_load_store()) { + Node* load_store = mb->in(MemBarNode::Precedent); + assert(load_store->is_LoadStore(), "unexpected graph shape"); + return cas_membar_elidable(load_store->Opcode()); + } + + return false; +} + +bool unnecessary_release(const Node *barrier) +{ + assert((barrier->is_MemBar() && + barrier->Opcode() == Op_MemBarRelease), + "expecting a release membar"); + + MemBarNode *mb = barrier->as_MemBar(); + if (!mb->leading()) { + return false; + } else { + Node* trailing = mb->trailing_membar(); + MemBarNode* trailing_mb = trailing->as_MemBar(); + assert(trailing_mb->trailing(), "Not a trailing membar?"); + assert(trailing_mb->leading_membar() == barrier, "inconsistent leading/trailing membars"); + + Node* mem = trailing_mb->in(MemBarNode::Precedent); + if (mem->is_Store()) { + assert(mem->as_Store()->is_release(), ""); + assert(trailing_mb->Opcode() == Op_MemBarVolatile, ""); + // A regular RISC-V store cannot provide release semantics on its own, + // so the leading MemBarRelease must be kept. This may return true when + // the Zalasr extension is supported and the store is matched to + // s{b|h|w|d}.rl (with the trailing MemBarVolatile handled accordingly). + return false; + } else { + assert(mem->is_LoadStore(), ""); + assert(trailing_mb->Opcode() == Op_MemBarAcquire, ""); + return cas_membar_elidable(mem->Opcode()); + } + } + return false; +} + constexpr uint64_t MAJIK_DWORD = 0xabbaabbaabbaabbaull; // predicate controlling translation of CAS @@ -1181,13 +1318,13 @@ constexpr uint64_t MAJIK_DWORD = 0xabbaabbaabbaabbaull; // returns true if CAS needs to use an acquiring load otherwise false bool needs_acquiring_load_reserved(const Node *n) { - assert(n != nullptr && is_CAS(n->Opcode(), true), "expecting a compare and swap"); + assert(is_CAS(n->Opcode(), true), "expecting a compare and swap"); LoadStoreNode* ldst = n->as_LoadStore(); - if (n != nullptr && is_CAS(n->Opcode(), false)) { - assert(ldst != nullptr && ldst->trailing_membar() != nullptr, "expected trailing membar"); + if (is_CAS(n->Opcode(), false)) { + assert(ldst->trailing_membar() != nullptr, "expected trailing membar"); } else { - return ldst != nullptr && ldst->trailing_membar() != nullptr; + return ldst->trailing_membar() != nullptr; } // so we can just return true here return true; @@ -1898,9 +2035,10 @@ bool Matcher::match_rule_supported(int opcode) { case Op_ReinterpretS2HF: case Op_ReinterpretHF2S: return UseZfh || UseZfhmin; + case Op_FmaHF: + return UseFMA && UseZfh; case Op_AddHF: case Op_DivHF: - case Op_FmaHF: case Op_MaxHF: case Op_MinHF: case Op_MulHF: @@ -2540,15 +2678,9 @@ frame %{ // return address specifies a type (REG or STACK) and a number // representing the register number (i.e. - use a register name) or // stack slot. - // Ret Addr is on stack in slot 0 if no locks or verification or alignment. - // Otherwise, it is above the locks and verification slot and alignment word - // TODO this may well be correct but need to check why that - 2 is there - // ppc port uses 0 but we definitely need to allow for fixed_slots - // which folds in the space used for monitors - return_addr(STACK - 2 + - align_up((Compile::current()->in_preserve_stack_slots() + - Compile::current()->fixed_slots()), - stack_alignment_in_slots())); + // Ret Addr is on stack 2 slots below _old_SP, i.e. in slot 0 if no locks + // or verification or alignment. + return_addr(STACK OptoReg::reg2stack(_old_SP) - 2); // Location of compiled Java return values. Same as C for now. return_value @@ -5241,188 +5373,11 @@ instruct prefetchalloc( memory mem ) %{ // ============================================================================ // Atomic operation instructions // +// CompareAndSwapX, GetAndSetX, and GetAndAddX represent sequentially +// consistent operations. C2 emits a trailing MemBarAcquire for +// these nodes, so their RISC-V implementation always needs acquire semantics. +// Non-acquiring match rules would consequently be unreachable. -// standard CompareAndSwapX when we are using barriers -// these have higher priority than the rules selected by a predicate -instruct compareAndSwapB_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, - iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) -%{ - predicate(!UseZabha || !UseZacas); - - match(Set res (CompareAndSwapB mem (Binary oldval newval))); - - ins_cost(2 * VOLATILE_REF_COST); - - effect(TEMP_DEF res, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); - - format %{ - "cmpxchg $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval\n\t" - "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapB_narrow" - %} - - ins_encode %{ - __ cmpxchg_narrow_value(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int8, - Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register, - true /* result as bool */, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register); - %} - - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) -%{ - predicate(UseZabha && UseZacas); - - match(Set res (CompareAndSwapB mem (Binary oldval newval))); - - ins_cost(2 * VOLATILE_REF_COST); - - format %{ - "cmpxchg $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval\n\t" - "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapB" - %} - - ins_encode %{ - __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int8, - Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register, - true /* result as bool */); - %} - - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapS_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, - iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) -%{ - predicate(!UseZabha || !UseZacas); - - match(Set res (CompareAndSwapS mem (Binary oldval newval))); - - ins_cost(2 * VOLATILE_REF_COST); - - effect(TEMP_DEF res, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); - - format %{ - "cmpxchg $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval\n\t" - "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapS_narrow" - %} - - ins_encode %{ - __ cmpxchg_narrow_value(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int16, - Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register, - true /* result as bool */, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register); - %} - - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) -%{ - predicate(UseZabha && UseZacas); - - match(Set res (CompareAndSwapS mem (Binary oldval newval))); - - ins_cost(2 * VOLATILE_REF_COST); - - format %{ - "cmpxchg $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval\n\t" - "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapS" - %} - - ins_encode %{ - __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int16, - Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register, - true /* result as bool */); - %} - - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) -%{ - match(Set res (CompareAndSwapI mem (Binary oldval newval))); - - ins_cost(2 * VOLATILE_REF_COST); - - format %{ - "cmpxchg $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval\n\t" - "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapI" - %} - - ins_encode %{ - __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int32, - /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, - /*result as bool*/ true); - %} - - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval) -%{ - match(Set res (CompareAndSwapL mem (Binary oldval newval))); - - ins_cost(2 * VOLATILE_REF_COST); - - format %{ - "cmpxchg $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval\n\t" - "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapL" - %} - - ins_encode %{ - __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int64, - /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, - /*result as bool*/ true); - %} - - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval) -%{ - predicate(n->as_LoadStore()->barrier_data() == 0); - - match(Set res (CompareAndSwapP mem (Binary oldval newval))); - - ins_cost(2 * VOLATILE_REF_COST); - - format %{ - "cmpxchg $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval\n\t" - "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapP" - %} - - ins_encode %{ - __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int64, - /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, - /*result as bool*/ true); - %} - - ins_pipe(pipe_slow); -%} - -instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval) -%{ - predicate(n->as_LoadStore()->barrier_data() == 0); - - match(Set res (CompareAndSwapN mem (Binary oldval newval))); - - ins_cost(2 * VOLATILE_REF_COST); - - format %{ - "cmpxchg $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval\n\t" - "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapN" - %} - - ins_encode %{ - __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::uint32, - /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, - /*result as bool*/ true); - %} - - ins_pipe(pipe_slow); -%} - -// alternative CompareAndSwapX when we are eliding barriers instruct compareAndSwapBAcq_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) %{ @@ -5614,7 +5569,7 @@ instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN new instruct compareAndExchangeB_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) %{ - predicate(!UseZabha || !UseZacas); + predicate((!UseZabha || !UseZacas) && !needs_acquiring_load_reserved(n)); match(Set res (CompareAndExchangeB mem (Binary oldval newval))); @@ -5637,7 +5592,7 @@ instruct compareAndExchangeB_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldva instruct compareAndExchangeB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) %{ - predicate(UseZabha && UseZacas); + predicate((UseZabha && UseZacas) && !needs_acquiring_load_reserved(n)); match(Set res (CompareAndExchangeB mem (Binary oldval newval))); @@ -5658,7 +5613,7 @@ instruct compareAndExchangeB(iRegINoSp res, indirect mem, iRegI oldval, iRegI ne instruct compareAndExchangeS_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) %{ - predicate(!UseZabha || !UseZacas); + predicate((!UseZabha || !UseZacas) && !needs_acquiring_load_reserved(n)); match(Set res (CompareAndExchangeS mem (Binary oldval newval))); @@ -5681,7 +5636,7 @@ instruct compareAndExchangeS_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldva instruct compareAndExchangeS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) %{ - predicate(UseZabha && UseZacas); + predicate((UseZabha && UseZacas) && !needs_acquiring_load_reserved(n)); match(Set res (CompareAndExchangeS mem (Binary oldval newval))); @@ -5701,6 +5656,8 @@ instruct compareAndExchangeS(iRegINoSp res, indirect mem, iRegI oldval, iRegI ne instruct compareAndExchangeI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) %{ + predicate(!needs_acquiring_load_reserved(n)); + match(Set res (CompareAndExchangeI mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); @@ -5719,6 +5676,8 @@ instruct compareAndExchangeI(iRegINoSp res, indirect mem, iRegI oldval, iRegI ne instruct compareAndExchangeL(iRegLNoSp res, indirect mem, iRegL oldval, iRegL newval) %{ + predicate(!needs_acquiring_load_reserved(n)); + match(Set res (CompareAndExchangeL mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); @@ -5737,7 +5696,7 @@ instruct compareAndExchangeL(iRegLNoSp res, indirect mem, iRegL oldval, iRegL ne instruct compareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); + predicate(!needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == 0); match(Set res (CompareAndExchangeN mem (Binary oldval newval))); @@ -5757,7 +5716,7 @@ instruct compareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN ne instruct compareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); + predicate(!needs_acquiring_load_reserved(n) && (n->as_LoadStore()->barrier_data() == 0)); match(Set res (CompareAndExchangeP mem (Binary oldval newval))); @@ -5946,7 +5905,7 @@ instruct compareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP instruct weakCompareAndSwapB_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) %{ - predicate(!UseZabha || !UseZacas); + predicate((!UseZabha || !UseZacas) && !needs_acquiring_load_reserved(n)); match(Set res (WeakCompareAndSwapB mem (Binary oldval newval))); @@ -5970,7 +5929,7 @@ instruct weakCompareAndSwapB_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldva instruct weakCompareAndSwapB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) %{ - predicate(UseZabha && UseZacas); + predicate((UseZabha && UseZacas) && !needs_acquiring_load_reserved(n)); match(Set res (WeakCompareAndSwapB mem (Binary oldval newval))); @@ -5992,7 +5951,7 @@ instruct weakCompareAndSwapB(iRegINoSp res, indirect mem, iRegI oldval, iRegI ne instruct weakCompareAndSwapS_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) %{ - predicate(!UseZabha || !UseZacas); + predicate((!UseZabha || !UseZacas) && !needs_acquiring_load_reserved(n)); match(Set res (WeakCompareAndSwapS mem (Binary oldval newval))); @@ -6016,7 +5975,7 @@ instruct weakCompareAndSwapS_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldva instruct weakCompareAndSwapS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) %{ - predicate(UseZabha && UseZacas); + predicate((UseZabha && UseZacas) && !needs_acquiring_load_reserved(n)); match(Set res (WeakCompareAndSwapS mem (Binary oldval newval))); @@ -6037,6 +5996,8 @@ instruct weakCompareAndSwapS(iRegINoSp res, indirect mem, iRegI oldval, iRegI ne instruct weakCompareAndSwapI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) %{ + predicate(!needs_acquiring_load_reserved(n)); + match(Set res (WeakCompareAndSwapI mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); @@ -6056,6 +6017,8 @@ instruct weakCompareAndSwapI(iRegINoSp res, indirect mem, iRegI oldval, iRegI ne instruct weakCompareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval) %{ + predicate(!needs_acquiring_load_reserved(n)); + match(Set res (WeakCompareAndSwapL mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); @@ -6075,7 +6038,7 @@ instruct weakCompareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL ne instruct weakCompareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); + predicate(!needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == 0); match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); @@ -6096,7 +6059,7 @@ instruct weakCompareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN ne instruct weakCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval) %{ - predicate(n->as_LoadStore()->barrier_data() == 0); + predicate(!needs_acquiring_load_reserved(n) && (n->as_LoadStore()->barrier_data() == 0)); match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); @@ -6291,69 +6254,6 @@ instruct weakCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP ins_pipe(pipe_slow); %} -instruct get_and_setI(indirect mem, iRegI newv, iRegINoSp prev) -%{ - match(Set prev (GetAndSetI mem newv)); - - ins_cost(ALU_COST); - - format %{ "atomic_xchgw $prev, $newv, [$mem]\t#@get_and_setI" %} - - ins_encode %{ - __ atomic_xchgw($prev$$Register, $newv$$Register, as_Register($mem$$base)); - %} - - ins_pipe(pipe_serial); -%} - -instruct get_and_setL(indirect mem, iRegL newv, iRegLNoSp prev) -%{ - match(Set prev (GetAndSetL mem newv)); - - ins_cost(ALU_COST); - - format %{ "atomic_xchg $prev, $newv, [$mem]\t#@get_and_setL" %} - - ins_encode %{ - __ atomic_xchg($prev$$Register, $newv$$Register, as_Register($mem$$base)); - %} - - ins_pipe(pipe_serial); -%} - -instruct get_and_setN(indirect mem, iRegN newv, iRegINoSp prev) -%{ - predicate(n->as_LoadStore()->barrier_data() == 0); - - match(Set prev (GetAndSetN mem newv)); - - ins_cost(ALU_COST); - - format %{ "atomic_xchgwu $prev, $newv, [$mem]\t#@get_and_setN" %} - - ins_encode %{ - __ atomic_xchgwu($prev$$Register, $newv$$Register, as_Register($mem$$base)); - %} - - ins_pipe(pipe_serial); -%} - -instruct get_and_setP(indirect mem, iRegP newv, iRegPNoSp prev) -%{ - predicate(n->as_LoadStore()->barrier_data() == 0); - match(Set prev (GetAndSetP mem newv)); - - ins_cost(ALU_COST); - - format %{ "atomic_xchg $prev, $newv, [$mem]\t#@get_and_setP" %} - - ins_encode %{ - __ atomic_xchg($prev$$Register, $newv$$Register, as_Register($mem$$base)); - %} - - ins_pipe(pipe_serial); -%} - instruct get_and_setIAcq(indirect mem, iRegI newv, iRegINoSp prev) %{ predicate(needs_acquiring_load_reserved(n)); @@ -6422,134 +6322,6 @@ instruct get_and_setPAcq(indirect mem, iRegP newv, iRegPNoSp prev) ins_pipe(pipe_serial); %} -instruct get_and_addL(indirect mem, iRegLNoSp newval, iRegL incr) -%{ - match(Set newval (GetAndAddL mem incr)); - - ins_cost(ALU_COST); - - format %{ "get_and_addL $newval, [$mem], $incr\t#@get_and_addL" %} - - ins_encode %{ - __ atomic_add($newval$$Register, $incr$$Register, as_Register($mem$$base)); - %} - - ins_pipe(pipe_serial); -%} - -instruct get_and_addL_no_res(indirect mem, Universe dummy, iRegL incr) -%{ - predicate(n->as_LoadStore()->result_not_used()); - - match(Set dummy (GetAndAddL mem incr)); - - ins_cost(ALU_COST); - - format %{ "get_and_addL [$mem], $incr\t#@get_and_addL_no_res" %} - - ins_encode %{ - __ atomic_add(noreg, $incr$$Register, as_Register($mem$$base)); - %} - - ins_pipe(pipe_serial); -%} - -instruct get_and_addLi(indirect mem, iRegLNoSp newval, immLAdd incr) -%{ - match(Set newval (GetAndAddL mem incr)); - - ins_cost(ALU_COST); - - format %{ "get_and_addL $newval, [$mem], $incr\t#@get_and_addLi" %} - - ins_encode %{ - __ atomic_add($newval$$Register, $incr$$constant, as_Register($mem$$base)); - %} - - ins_pipe(pipe_serial); -%} - -instruct get_and_addLi_no_res(indirect mem, Universe dummy, immLAdd incr) -%{ - predicate(n->as_LoadStore()->result_not_used()); - - match(Set dummy (GetAndAddL mem incr)); - - ins_cost(ALU_COST); - - format %{ "get_and_addL [$mem], $incr\t#@get_and_addLi_no_res" %} - - ins_encode %{ - __ atomic_add(noreg, $incr$$constant, as_Register($mem$$base)); - %} - - ins_pipe(pipe_serial); -%} - -instruct get_and_addI(indirect mem, iRegINoSp newval, iRegIorL2I incr) -%{ - match(Set newval (GetAndAddI mem incr)); - - ins_cost(ALU_COST); - - format %{ "get_and_addI $newval, [$mem], $incr\t#@get_and_addI" %} - - ins_encode %{ - __ atomic_addw($newval$$Register, $incr$$Register, as_Register($mem$$base)); - %} - - ins_pipe(pipe_serial); -%} - -instruct get_and_addI_no_res(indirect mem, Universe dummy, iRegIorL2I incr) -%{ - predicate(n->as_LoadStore()->result_not_used()); - - match(Set dummy (GetAndAddI mem incr)); - - ins_cost(ALU_COST); - - format %{ "get_and_addI [$mem], $incr\t#@get_and_addI_no_res" %} - - ins_encode %{ - __ atomic_addw(noreg, $incr$$Register, as_Register($mem$$base)); - %} - - ins_pipe(pipe_serial); -%} - -instruct get_and_addIi(indirect mem, iRegINoSp newval, immIAdd incr) -%{ - match(Set newval (GetAndAddI mem incr)); - - ins_cost(ALU_COST); - - format %{ "get_and_addI $newval, [$mem], $incr\t#@get_and_addIi" %} - - ins_encode %{ - __ atomic_addw($newval$$Register, $incr$$constant, as_Register($mem$$base)); - %} - - ins_pipe(pipe_serial); -%} - -instruct get_and_addIi_no_res(indirect mem, Universe dummy, immIAdd incr) -%{ - predicate(n->as_LoadStore()->result_not_used()); - - match(Set dummy (GetAndAddI mem incr)); - - ins_cost(ALU_COST); - - format %{ "get_and_addI [$mem], $incr\t#@get_and_addIi_no_res" %} - - ins_encode %{ - __ atomic_addw(noreg, $incr$$constant, as_Register($mem$$base)); - %} - - ins_pipe(pipe_serial); -%} - instruct get_and_addLAcq(indirect mem, iRegLNoSp newval, iRegL incr) %{ predicate(needs_acquiring_load_reserved(n)); @@ -8347,25 +8119,79 @@ instruct membar_full_rvtso() %{ // RVWMO -instruct membar_aqcuire_rvwmo() %{ +instruct load_fence_rvwmo() %{ predicate(!UseZtso); match(LoadFence); + ins_cost(VOLATILE_REF_COST); + + format %{ "#@load_fence_rvwmo\n\t" + "fence r, rw" %} + + ins_encode %{ + __ block_comment("load_fence_rvwmo"); + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + %} + ins_pipe(pipe_serial); +%} + +instruct unnecessary_membar_acquire_rvwmo() %{ + predicate(!UseZtso && unnecessary_acquire(n)); + match(MemBarAcquire); + ins_cost(0); + + size(0); + format %{ "#@unnecessary_membar_acquire_rvwmo (elided)" %} + ins_encode %{ + __ block_comment("unnecessary_membar_acquire_rvwmo (elided)"); + %} + ins_pipe(real_empty); +%} + +instruct membar_acquire_rvwmo() %{ + predicate(!UseZtso); match(MemBarAcquire); ins_cost(VOLATILE_REF_COST); - format %{ "#@membar_aqcuire_rvwmo\n\t" + format %{ "#@membar_acquire_rvwmo\n\t" "fence r, rw" %} ins_encode %{ - __ block_comment("membar_aqcuire_rvwmo"); + __ block_comment("membar_acquire_rvwmo"); __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); %} ins_pipe(pipe_serial); %} -instruct membar_release_rvwmo() %{ +instruct store_fence_rvwmo() %{ predicate(!UseZtso); match(StoreFence); + ins_cost(VOLATILE_REF_COST); + + format %{ "#@store_fence_rvwmo\n\t" + "fence rw, w" %} + + ins_encode %{ + __ block_comment("store_fence_rvwmo"); + __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); + %} + ins_pipe(pipe_serial); +%} + +instruct unnecessary_membar_release_rvwmo() %{ + predicate(!UseZtso && unnecessary_release(n)); + match(MemBarRelease); + ins_cost(0); + + size(0); + format %{ "#@unnecessary_membar_release_rvwmo (elided)" %} + ins_encode %{ + __ block_comment("unnecessary_membar_release_rvwmo (elided)"); + %} + ins_pipe(real_empty); +%} + +instruct membar_release_rvwmo() %{ + predicate(!UseZtso); match(MemBarRelease); ins_cost(VOLATILE_REF_COST); diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index f1bc7fc0d5e3..07d2ba4af0a6 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -390,7 +390,7 @@ int SharedRuntime::java_return_convention(const BasicType *sig_bt, return int_args + fp_args; } -BufferedInlineTypeBlob* SharedRuntime::generate_buffered_inline_type_adapter(const InlineKlass* vk) { +BufferedValueTypeBlob* SharedRuntime::generate_buffered_value_type_adapter(const ValueKlass* vk) { Unimplemented(); return nullptr; } @@ -423,13 +423,13 @@ static void patch_callers_callsite(MacroAssembler *masm) { __ bind(L); } -// For each inline type argument, sig includes the list of fields of -// the inline type. This utility function computes the number of -// arguments for the call if inline types are passed by reference (the +// For each value type argument, sig includes the list of fields of +// the value type. This utility function computes the number of +// arguments for the call if value types are passed by reference (the // calling convention the interpreter expects). static int compute_total_args_passed_int(const GrowableArray* sig_extended) { int total_args_passed = 0; - assert(!InlineTypePassFieldsAsArgs, ""); + assert(!ValueTypePassFieldsAsArgs, ""); total_args_passed = sig_extended->length(); return total_args_passed; } @@ -547,21 +547,21 @@ static void gen_c2i_adapter(MacroAssembler *masm, // Now write the args into the outgoing interpreter space // next_arg_comp is the next argument from the compiler point of - // view (inline type fields are passed in registers/on the stack). In - // sig_extended, an inline type argument starts with: T_METADATA, - // followed by the types of the fields of the inline type and T_VOID - // to mark the end of the inline type. ignored counts the number of - // T_METADATA/T_VOID. next_vt_arg is the next inline type argument: + // view (value type fields are passed in registers/on the stack). In + // sig_extended, a value type argument starts with: T_METADATA, + // followed by the types of the fields of the value type and T_VOID + // to mark the end of the value type. ignored counts the number of + // T_METADATA/T_VOID. next_vt_arg is the next value type argument: // used to get the buffer for that argument from the pool of buffers // we allocated above and want to pass to the // interpreter. next_arg_int is the next argument from the - // interpreter point of view (inline types are passed by reference). + // interpreter point of view (value types are passed by reference). for (int next_arg_comp = 0, ignored = 0, next_vt_arg = 0, next_arg_int = 0; next_arg_comp < sig_extended->length(); next_arg_comp++) { assert(ignored <= next_arg_comp, "shouldn't skip over more slots than there are arguments"); assert(next_arg_int <= total_args_passed, "more arguments for the interpreter than expected?"); BasicType bt = sig_extended->at(next_arg_comp)._bt; - assert(!InlineTypePassFieldsAsArgs, ""); + assert(!ValueTypePassFieldsAsArgs, ""); int st_off = (total_args_passed - next_arg_int - 1) * Interpreter::stackElementSize; int next_off = st_off - Interpreter::stackElementSize; @@ -606,7 +606,7 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, // Will jump to the compiled code just as if compiled code was doing it. // Pre-load the register-jump target early, to schedule it better. - __ ld(t1, Address(xmethod, in_bytes(Method::from_compiled_inline_offset()))); + __ ld(t1, Address(xmethod, in_bytes(Method::from_compiled_value_offset()))); int total_args_passed = sig->length(); @@ -740,7 +740,7 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler* masm, // On exit from the interpreter, the interpreter will restore our SP (lest the // compiled code, which relies solely on SP and not FP, get sick). entry_address[AdapterBlob::C2I_Unverified] = __ pc(); - entry_address[AdapterBlob::C2I_Unverified_Inline] = __ pc(); + entry_address[AdapterBlob::C2I_Unverified_Value] = __ pc(); Label skip_fixup; gen_inline_cache_check(masm, skip_fixup); @@ -751,7 +751,7 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler* masm, // Scalarized c2i adapter with non-scalarized receiver (i.e., don't pack receiver) entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr; - entry_address[AdapterBlob::C2I_Inline_RO] = __ pc(); + entry_address[AdapterBlob::C2I_Value_RO] = __ pc(); if (regs_cc != regs_cc_ro) { // No class init barrier needed because method is guaranteed to be non-static gen_c2i_adapter(masm, sig_cc_ro, regs_cc_ro, /* requires_clinit_barrier = */ false, entry_address[AdapterBlob::C2I_No_Clinit_Check], @@ -760,20 +760,20 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler* masm, } // Scalarized c2i adapter - entry_address[AdapterBlob::C2I] = __ pc(); - entry_address[AdapterBlob::C2I_Inline] = __ pc(); + entry_address[AdapterBlob::C2I] = __ pc(); + entry_address[AdapterBlob::C2I_Value] = __ pc(); gen_c2i_adapter(masm, sig_cc, regs_cc, /* requires_clinit_barrier = */ true, entry_address[AdapterBlob::C2I_No_Clinit_Check], skip_fixup, entry_address[AdapterBlob::I2C], oop_maps, frame_complete, frame_size_in_words, /* alloc_inline_receiver = */ true); // Non-scalarized c2i adapter if (regs != regs_cc) { - entry_address[AdapterBlob::C2I_Unverified_Inline] = __ pc(); - Label inline_entry_skip_fixup; - gen_inline_cache_check(masm, inline_entry_skip_fixup); + entry_address[AdapterBlob::C2I_Unverified_Value] = __ pc(); + Label value_entry_skip_fixup; + gen_inline_cache_check(masm, value_entry_skip_fixup); - entry_address[AdapterBlob::C2I_Inline] = __ pc(); + entry_address[AdapterBlob::C2I_Value] = __ pc(); gen_c2i_adapter(masm, sig, regs, /* requires_clinit_barrier = */ true, entry_address[AdapterBlob::C2I_No_Clinit_Check], - inline_entry_skip_fixup, entry_address[AdapterBlob::I2C], oop_maps, frame_complete, frame_size_in_words, /* alloc_inline_receiver = */ false); + value_entry_skip_fixup, entry_address[AdapterBlob::I2C], oop_maps, frame_complete, frame_size_in_words, /* alloc_inline_receiver = */ false); } // The c2i adapters might safepoint and trigger a GC. The caller must make sure that @@ -1799,10 +1799,9 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ la(c_rarg0, Address(xthread, in_bytes(JavaThread::jni_environment_offset()))); // Now set thread in native - __ la(t1, Address(xthread, JavaThread::thread_state_offset())); - __ mv(t0, _thread_in_native); + __ mv(t1, _thread_in_native); __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); - __ sw(t0, Address(t1)); + __ sw(t1, Address(xthread, JavaThread::thread_state_offset())); // Clobbers t1 __ rt_call(native_func); @@ -2776,7 +2775,7 @@ RuntimeStub* SharedRuntime::generate_throw_exception(StubId id, address runtime_ } // Call here from the interpreter or compiled code to store returned -// values to a newly allocated inline type instance. +// values to a newly allocated value type instance. RuntimeStub* SharedRuntime::generate_return_value_stub(address destination) { Unimplemented(); return nullptr; @@ -2796,6 +2795,13 @@ static void jfr_epilogue(MacroAssembler* masm) { // It returns a jobject handle to the event writer. // The handle is dereferenced and the return value is the event writer oop. RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { + StubId id = StubId::shared_jfr_write_checkpoint_id; + + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::SharedBlob, StubInfo::blob(id)); + if (blob != nullptr) { + return blob->as_runtime_stub(); + } + enum layout { fp_off, fp_off2, @@ -2806,7 +2812,7 @@ RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { int insts_size = 1024; int locs_size = 64; - const char* name = SharedRuntime::stub_name(StubId::shared_jfr_write_checkpoint_id); + const char* name = SharedRuntime::stub_name(id); CodeBuffer code(name, insts_size, locs_size); OopMapSet* oop_maps = new OopMapSet(); MacroAssembler* masm = new MacroAssembler(&code); @@ -2830,11 +2836,19 @@ RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { RuntimeStub::new_runtime_stub(name, &code, frame_complete, (framesize >> (LogBytesPerWord - LogBytesPerInt)), oop_maps, false); + AOTCodeCache::store_code_blob(*stub, AOTCodeEntry::SharedBlob, StubInfo::blob(id)); return stub; } // For c2: call to return a leased buffer. RuntimeStub* SharedRuntime::generate_jfr_return_lease() { + StubId id = StubId::shared_jfr_return_lease_id; + + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::SharedBlob, StubInfo::blob(id)); + if (blob != nullptr) { + return blob->as_runtime_stub(); + } + enum layout { fp_off, fp_off2, @@ -2845,7 +2859,7 @@ RuntimeStub* SharedRuntime::generate_jfr_return_lease() { int insts_size = 1024; int locs_size = 64; - const char* name = SharedRuntime::stub_name(StubId::shared_jfr_return_lease_id); + const char* name = SharedRuntime::stub_name(id); CodeBuffer code(name, insts_size, locs_size); OopMapSet* oop_maps = new OopMapSet(); MacroAssembler* masm = new MacroAssembler(&code); @@ -2868,6 +2882,7 @@ RuntimeStub* SharedRuntime::generate_jfr_return_lease() { RuntimeStub::new_runtime_stub(name, &code, frame_complete, (framesize >> (LogBytesPerWord - LogBytesPerInt)), oop_maps, false); + AOTCodeCache::store_code_blob(*stub, AOTCodeEntry::SharedBlob, StubInfo::blob(id)); return stub; } diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 7cefb1eef2c9..cdbaf577e239 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -2248,10 +2248,10 @@ class StubGenerator: public StubCodeGenerator { __ bne(t1, scratch_src_klass, L_failed); if (Arguments::is_valhalla_enabled()) { - // Check for flat inline type array -> return -1 + // Check for flat value type array -> return -1 __ test_flat_array_oop(src, t1, L_failed); - // Check for null-free (non-flat) inline type array -> handle as object array + // Check for null-free (non-flat) value type array -> handle as object array __ test_null_free_array_oop(src, t1, L_objArray); } @@ -7827,6 +7827,43 @@ static const int64_t right_3_bits = right_n_bits(3); return start; } + address generate_updateBytesCRC32C() { + assert(UseCRC32CIntrinsics, "what are we doing here?"); + StubId stub_id = StubId::stubgen_updateBytesCRC32C_id; + int entry_count = StubInfo::entry_count(stub_id); + assert(entry_count == 1, "sanity check"); + address start = load_archive_data(stub_id); + if (start != nullptr) { + return start; + } + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, stub_id); + + start = __ pc(); + + const Register crc = c_rarg0; // crc + const Register buf = c_rarg1; // source java byte array address + const Register len = c_rarg2; // length + + BLOCK_COMMENT("Entry:"); + __ enter(); // required for proper stackwalking of RuntimeStub frame + + // c_rarg3/c_rarg4 are reused as the two table base pointers; the rest are scratch. + __ kernel_crc32c(crc, buf, len, + c_rarg3, c_rarg4, // byte_table, clmul_table + c_rarg5, c_rarg6, c_rarg7, // accum_hi, k1, k2 + t2, t3, t4); // scratch1, scratch2, fold_end + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(); + + // record the stub entry and end + store_archive_data(stub_id, start, __ pc()); + + return start; + } + // exception handler for upcall stubs address generate_upcall_stub_exception_handler() { StubId stub_id = StubId::stubgen_upcall_stub_exception_handler_id; @@ -7916,6 +7953,10 @@ static const int64_t right_3_bits = right_n_bits(3); StubRoutines::_updateBytesCRC32 = generate_updateBytesCRC32(); } + if (UseCRC32CIntrinsics) { + StubRoutines::_updateBytesCRC32C = generate_updateBytesCRC32C(); + } + if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_float16ToFloat) && vmIntrinsics::is_intrinsic_available(vmIntrinsics::_floatToFloat16)) { StubRoutines::_hf2f = generate_float16ToFloat(); diff --git a/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp b/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp index bedb67fdda6a..b62af9ebf5f0 100644 --- a/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp @@ -58,9 +58,9 @@ bool StubRoutines::riscv::_completed = false; */ address StubRoutines::crc_table_addr() { return (address)StubRoutines::riscv::_crc_table; } -address StubRoutines::crc32c_table_addr() { ShouldNotCallThis(); return nullptr; } +address StubRoutines::crc32c_table_addr() { return (address)StubRoutines::riscv::_crc32c_table; } -ATTRIBUTE_ALIGNED(4096) juint StubRoutines::riscv::_crc_table[] = +ATTRIBUTE_ALIGNED(4096) const juint StubRoutines::riscv::_crc_table[] = { // Table 0 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, @@ -506,6 +506,70 @@ ATTRIBUTE_ALIGNED(4096) juint StubRoutines::riscv::_crc_table[] = 0xccaa009eUL, 0x00000000UL, }; +ATTRIBUTE_ALIGNED(4096) const juint StubRoutines::riscv::_crc32c_table[] = +{ + 0x00000000UL, 0xF26B8303UL, 0xE13B70F7UL, 0x1350F3F4UL, 0xC79A971FUL, + 0x35F1141CUL, 0x26A1E7E8UL, 0xD4CA64EBUL, 0x8AD958CFUL, 0x78B2DBCCUL, + 0x6BE22838UL, 0x9989AB3BUL, 0x4D43CFD0UL, 0xBF284CD3UL, 0xAC78BF27UL, + 0x5E133C24UL, 0x105EC76FUL, 0xE235446CUL, 0xF165B798UL, 0x030E349BUL, + 0xD7C45070UL, 0x25AFD373UL, 0x36FF2087UL, 0xC494A384UL, 0x9A879FA0UL, + 0x68EC1CA3UL, 0x7BBCEF57UL, 0x89D76C54UL, 0x5D1D08BFUL, 0xAF768BBCUL, + 0xBC267848UL, 0x4E4DFB4BUL, 0x20BD8EDEUL, 0xD2D60DDDUL, 0xC186FE29UL, + 0x33ED7D2AUL, 0xE72719C1UL, 0x154C9AC2UL, 0x061C6936UL, 0xF477EA35UL, + 0xAA64D611UL, 0x580F5512UL, 0x4B5FA6E6UL, 0xB93425E5UL, 0x6DFE410EUL, + 0x9F95C20DUL, 0x8CC531F9UL, 0x7EAEB2FAUL, 0x30E349B1UL, 0xC288CAB2UL, + 0xD1D83946UL, 0x23B3BA45UL, 0xF779DEAEUL, 0x05125DADUL, 0x1642AE59UL, + 0xE4292D5AUL, 0xBA3A117EUL, 0x4851927DUL, 0x5B016189UL, 0xA96AE28AUL, + 0x7DA08661UL, 0x8FCB0562UL, 0x9C9BF696UL, 0x6EF07595UL, 0x417B1DBCUL, + 0xB3109EBFUL, 0xA0406D4BUL, 0x522BEE48UL, 0x86E18AA3UL, 0x748A09A0UL, + 0x67DAFA54UL, 0x95B17957UL, 0xCBA24573UL, 0x39C9C670UL, 0x2A993584UL, + 0xD8F2B687UL, 0x0C38D26CUL, 0xFE53516FUL, 0xED03A29BUL, 0x1F682198UL, + 0x5125DAD3UL, 0xA34E59D0UL, 0xB01EAA24UL, 0x42752927UL, 0x96BF4DCCUL, + 0x64D4CECFUL, 0x77843D3BUL, 0x85EFBE38UL, 0xDBFC821CUL, 0x2997011FUL, + 0x3AC7F2EBUL, 0xC8AC71E8UL, 0x1C661503UL, 0xEE0D9600UL, 0xFD5D65F4UL, + 0x0F36E6F7UL, 0x61C69362UL, 0x93AD1061UL, 0x80FDE395UL, 0x72966096UL, + 0xA65C047DUL, 0x5437877EUL, 0x4767748AUL, 0xB50CF789UL, 0xEB1FCBADUL, + 0x197448AEUL, 0x0A24BB5AUL, 0xF84F3859UL, 0x2C855CB2UL, 0xDEEEDFB1UL, + 0xCDBE2C45UL, 0x3FD5AF46UL, 0x7198540DUL, 0x83F3D70EUL, 0x90A324FAUL, + 0x62C8A7F9UL, 0xB602C312UL, 0x44694011UL, 0x5739B3E5UL, 0xA55230E6UL, + 0xFB410CC2UL, 0x092A8FC1UL, 0x1A7A7C35UL, 0xE811FF36UL, 0x3CDB9BDDUL, + 0xCEB018DEUL, 0xDDE0EB2AUL, 0x2F8B6829UL, 0x82F63B78UL, 0x709DB87BUL, + 0x63CD4B8FUL, 0x91A6C88CUL, 0x456CAC67UL, 0xB7072F64UL, 0xA457DC90UL, + 0x563C5F93UL, 0x082F63B7UL, 0xFA44E0B4UL, 0xE9141340UL, 0x1B7F9043UL, + 0xCFB5F4A8UL, 0x3DDE77ABUL, 0x2E8E845FUL, 0xDCE5075CUL, 0x92A8FC17UL, + 0x60C37F14UL, 0x73938CE0UL, 0x81F80FE3UL, 0x55326B08UL, 0xA759E80BUL, + 0xB4091BFFUL, 0x466298FCUL, 0x1871A4D8UL, 0xEA1A27DBUL, 0xF94AD42FUL, + 0x0B21572CUL, 0xDFEB33C7UL, 0x2D80B0C4UL, 0x3ED04330UL, 0xCCBBC033UL, + 0xA24BB5A6UL, 0x502036A5UL, 0x4370C551UL, 0xB11B4652UL, 0x65D122B9UL, + 0x97BAA1BAUL, 0x84EA524EUL, 0x7681D14DUL, 0x2892ED69UL, 0xDAF96E6AUL, + 0xC9A99D9EUL, 0x3BC21E9DUL, 0xEF087A76UL, 0x1D63F975UL, 0x0E330A81UL, + 0xFC588982UL, 0xB21572C9UL, 0x407EF1CAUL, 0x532E023EUL, 0xA145813DUL, + 0x758FE5D6UL, 0x87E466D5UL, 0x94B49521UL, 0x66DF1622UL, 0x38CC2A06UL, + 0xCAA7A905UL, 0xD9F75AF1UL, 0x2B9CD9F2UL, 0xFF56BD19UL, 0x0D3D3E1AUL, + 0x1E6DCDEEUL, 0xEC064EEDUL, 0xC38D26C4UL, 0x31E6A5C7UL, 0x22B65633UL, + 0xD0DDD530UL, 0x0417B1DBUL, 0xF67C32D8UL, 0xE52CC12CUL, 0x1747422FUL, + 0x49547E0BUL, 0xBB3FFD08UL, 0xA86F0EFCUL, 0x5A048DFFUL, 0x8ECEE914UL, + 0x7CA56A17UL, 0x6FF599E3UL, 0x9D9E1AE0UL, 0xD3D3E1ABUL, 0x21B862A8UL, + 0x32E8915CUL, 0xC083125FUL, 0x144976B4UL, 0xE622F5B7UL, 0xF5720643UL, + 0x07198540UL, 0x590AB964UL, 0xAB613A67UL, 0xB831C993UL, 0x4A5A4A90UL, + 0x9E902E7BUL, 0x6CFBAD78UL, 0x7FAB5E8CUL, 0x8DC0DD8FUL, 0xE330A81AUL, + 0x115B2B19UL, 0x020BD8EDUL, 0xF0605BEEUL, 0x24AA3F05UL, 0xD6C1BC06UL, + 0xC5914FF2UL, 0x37FACCF1UL, 0x69E9F0D5UL, 0x9B8273D6UL, 0x88D28022UL, + 0x7AB90321UL, 0xAE7367CAUL, 0x5C18E4C9UL, 0x4F48173DUL, 0xBD23943EUL, + 0xF36E6F75UL, 0x0105EC76UL, 0x12551F82UL, 0xE03E9C81UL, 0x34F4F86AUL, + 0xC69F7B69UL, 0xD5CF889DUL, 0x27A40B9EUL, 0x79B737BAUL, 0x8BDCB4B9UL, + 0x988C474DUL, 0x6AE7C44EUL, 0xBE2DA0A5UL, 0x4C4623A6UL, 0x5F16D052UL, + 0xAD7D5351UL, + + // CRC32C constants for carry-less multiplication implementation + 0xF20C0DFEUL, 0x00000000UL, + 0x493C7D27UL, 0x00000000UL, + 0xDD45AAB8UL, 0x00000000UL, + 0x493C7D27UL, 0x00000000UL, + 0xDEA713F1UL, 0x00000000UL, + 0x05EC76F1UL, 0x00000001UL, +}; + #if INCLUDE_CDS extern void StubGenerator_init_AOTAddressTable(GrowableArray
& external_addresses); @@ -518,6 +582,7 @@ void StubRoutines::init_AOTAddressTable() { // add the relevant addresses, is declared in a source file rather // than in a separately includeable header. StubGenerator_init_AOTAddressTable(external_addresses); + external_addresses.append(crc32c_table_addr()); AOTCodeCache::publish_external_addresses(external_addresses); } #endif // INCLUDE_CDS diff --git a/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp b/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp index b230c2657ded..8f6a53f7b9f3 100644 --- a/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp +++ b/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp @@ -98,7 +98,8 @@ class riscv { } private: - static juint _crc_table[]; + static const juint _crc_table[]; + static const juint _crc32c_table[]; }; #endif // CPU_RISCV_STUBROUTINES_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp index bf552678f965..c8898c0a20ee 100644 --- a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp @@ -939,8 +939,32 @@ address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractI * CRC32C also uses an "end" variable instead of the length variable CRC32 uses */ address TemplateInterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { - // TODO: Unimplemented generate_CRC32C_updateBytes_entry - return nullptr; + assert(UseCRC32CIntrinsics, "this intrinsic is not supported"); + address entry = __ pc(); + + const Register crc = c_rarg0; // initial crc + const Register buf = c_rarg1; // source java byte array address + const Register len = c_rarg2; // len argument to the kernel + const Register off = c_rarg3; // offset + + // Arguments are reversed on the Java expression stack. + __ lwu(len, Address(esp)); // end + __ lwu(off, Address(esp, wordSize)); // offset + __ sub(len, len, off); // end - offset + __ ld(buf, Address(esp, 2 * wordSize)); // byte[] | direct buffer address + __ add(buf, buf, off); + + if (kind == Interpreter::java_util_zip_CRC32C_updateDirectByteBuffer) { + __ lwu(crc, Address(esp, 4 * wordSize)); + } else { + __ addi(buf, buf, arrayOopDesc::base_offset_in_bytes(T_BYTE)); + __ lwu(crc, Address(esp, 3 * wordSize)); + } + + __ andi(sp, x19_sender_sp, -16); // Restore caller's SP. + __ far_jump(RuntimeAddress(StubRoutines::updateBytesCRC32C())); + + return entry; } // Not supported @@ -1180,10 +1204,9 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { #endif // Change state to native - __ la(t1, Address(xthread, JavaThread::thread_state_offset())); - __ mv(t0, _thread_in_native); + __ mv(t1, _thread_in_native); __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); - __ sw(t0, Address(t1)); + __ sw(t1, Address(xthread, JavaThread::thread_state_offset())); __ push_cont_fastpath(); diff --git a/src/hotspot/cpu/riscv/templateTable_riscv.cpp b/src/hotspot/cpu/riscv/templateTable_riscv.cpp index 0d169f35f6b5..4124b6538094 100644 --- a/src/hotspot/cpu/riscv/templateTable_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateTable_riscv.cpp @@ -157,13 +157,10 @@ void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register bc_reg, assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); assert(load_bc_into_bc_reg, "we use bc_reg as temp"); __ load_field_entry(temp_reg, bc_reg); - if (byte_no == f1_byte) { - __ la(temp_reg, Address(temp_reg, in_bytes(ResolvedFieldEntry::get_code_offset()))); - } else { - __ la(temp_reg, Address(temp_reg, in_bytes(ResolvedFieldEntry::put_code_offset()))); - } + int code_offset = (byte_no == f1_byte) ? in_bytes(ResolvedFieldEntry::get_code_offset()) + : in_bytes(ResolvedFieldEntry::put_code_offset()); // Load-acquire the bytecode to match store-release in ResolvedFieldEntry::fill_in() - __ lbu(temp_reg, Address(temp_reg, 0)); + __ lbu(temp_reg, Address(temp_reg, code_offset)); __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); __ mv(bc_reg, bc); __ beqz(temp_reg, L_patch_done); @@ -1912,8 +1909,8 @@ void TemplateTable::if_acmp(Condition cc) { __ profile_acmp(x12, x11, x10, x14); - Register is_inline_type_mask = t1; - __ mv(is_inline_type_mask, markWord::inline_type_pattern); + Register is_value_type_mask = t1; + __ mv(is_value_type_mask, markWord::value_type_pattern); if (Arguments::is_valhalla_enabled()) { // The substitutability test is only necessary if x11 and x10 are not the same... @@ -1934,14 +1931,14 @@ void TemplateTable::if_acmp(Condition cc) { // ...and both are values... __ ld(x12, Address(x11, oopDesc::mark_offset_in_bytes())); - __ andr(x12, x12, is_inline_type_mask); + __ andr(x12, x12, is_value_type_mask); __ ld(x14, Address(x10, oopDesc::mark_offset_in_bytes())); - __ andr(x14, x14, is_inline_type_mask); + __ andr(x14, x14, is_value_type_mask); __ andr(x12, x12, x14); if (cc == equal) { - __ bne(x12, is_inline_type_mask, not_taken); + __ bne(x12, is_value_type_mask, not_taken); } else { - __ bne(x12, is_inline_type_mask, taken); + __ bne(x12, is_value_type_mask, taken); } // ...with the same value klass @@ -2351,13 +2348,10 @@ void TemplateTable::resolve_cache_and_index_for_field(int byte_no, assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); __ load_field_entry(Rcache, index); - if (byte_no == f1_byte) { - __ la(temp, Address(Rcache, in_bytes(ResolvedFieldEntry::get_code_offset()))); - } else { - __ la(temp, Address(Rcache, in_bytes(ResolvedFieldEntry::put_code_offset()))); - } + int code_offset = (byte_no == f1_byte) ? in_bytes(ResolvedFieldEntry::get_code_offset()) + : in_bytes(ResolvedFieldEntry::put_code_offset()); // Load-acquire the bytecode to match store-release in ResolvedFieldEntry::fill_in() - __ lbu(temp, Address(temp, 0)); + __ lbu(temp, Address(Rcache, code_offset)); __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); __ mv(t0, (int) code); // have we resolved this bytecode? @@ -2962,7 +2956,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr __ pop(atos); if (is_static) { Label is_nullable; - __ test_field_is_not_null_free_inline_type(flags, x28, is_nullable); + __ test_field_is_not_null_free_value_type(flags, x28, is_nullable); __ null_check(x10); // FIXME JDK-8341120 __ bind(is_nullable); // field address @@ -2973,7 +2967,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr } else { Label null_free_reference, is_flat, rewrite_inline; __ test_field_is_flat(flags, x28, is_flat); - __ test_field_is_null_free_inline_type(flags, x28, null_free_reference); + __ test_field_is_null_free_value_type(flags, x28, null_free_reference); pop_and_check_object(obj); { __ add(off, obj, off); @@ -2985,7 +2979,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr patch_bytecode(Bytecodes::_fast_aputfield, bc, x9, true, byte_no); } __ j(Done); - // Implementation of the inline type semantic + // Implementation of the value type semantic __ bind(null_free_reference); __ null_check(x10); // FIXME JDK-8341120 pop_and_check_object(obj); @@ -3743,11 +3737,10 @@ void TemplateTable::_new() { // This is done before loading InstanceKlass to be consistent with the order // how Constant Pool is update (see ConstantPool::klass_at_put) const int tags_offset = Array::base_offset_in_bytes(); - __ add(t0, x10, x13); - __ la(t0, Address(t0, tags_offset)); - __ lbu(t0, t0); + __ add(t1, x10, x13); + __ lbu(t1, Address(t1, tags_offset)); __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); - __ subi(t1, t0, (u1)JVM_CONSTANT_Class); + __ subi(t1, t1, (u1)JVM_CONSTANT_Class); __ bnez(t1, slow_case); // get InstanceKlass @@ -4042,9 +4035,9 @@ void TemplateTable::monitorenter() { // check for null object __ null_check(x10); - Label is_inline_type; + Label is_value_type; __ ld(t0, Address(x10, oopDesc::mark_offset_in_bytes())); - __ test_markword_is_inline_type(t0, is_inline_type); + __ test_markword_is_value_type(t0, is_value_type); const Address monitor_block_top( fp, frame::interpreter_frame_monitor_block_top_offset * wordSize); @@ -4146,7 +4139,7 @@ void TemplateTable::monitorenter() { // next instruction. __ dispatch_next(vtos); - __ bind(is_inline_type); + __ bind(is_value_type); __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_identity_exception), x10); __ should_not_reach_here(); @@ -4158,10 +4151,10 @@ void TemplateTable::monitorexit() { // check for null object __ null_check(x10); - const int is_inline_type_mask = markWord::inline_type_pattern; + const int is_value_type_mask = markWord::value_type_pattern; Label has_identity; __ ld(t0, Address(x10, oopDesc::mark_offset_in_bytes())); - __ mv(t1, is_inline_type_mask); + __ mv(t1, is_value_type_mask); __ andr(t0, t0, t1); __ bne(t0, t1, has_identity); __ call_VM(noreg, CAST_FROM_FN_PTR(address, diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index 35fbf2c1c913..955c85b05ee1 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -210,23 +210,29 @@ void VM_Version::common_initialize() { } } else { if (!FLAG_IS_DEFAULT(UseCRC32Intrinsics)) { - warning("CRC32 intrinsic are not available on this CPU."); + warning("CRC32 intrinsic is not available on this CPU."); } FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); } - if (UseCRC32CIntrinsics) { - warning("CRC32C intrinsics are not available on this CPU."); - FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false); + if (UseZbc) { + if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) { + FLAG_SET_DEFAULT(UseCRC32CIntrinsics, true); + } + } else { + if (UseCRC32CIntrinsics) { + warning("CRC32C intrinsic is not available on this CPU."); + FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false); + } } - if (InlineTypePassFieldsAsArgs) { - warning("InlineTypePassFieldsAsArgs is not supported on this CPU"); - FLAG_SET_DEFAULT(InlineTypePassFieldsAsArgs, false); + if (ValueTypePassFieldsAsArgs) { + warning("ValueTypePassFieldsAsArgs is not supported on this CPU"); + FLAG_SET_DEFAULT(ValueTypePassFieldsAsArgs, false); } - if (InlineTypeReturnedAsFields) { - warning("InlineTypeReturnedAsFields is not supported on this CPU"); - FLAG_SET_DEFAULT(InlineTypeReturnedAsFields, false); + if (ValueTypeReturnedAsFields) { + warning("ValueTypeReturnedAsFields is not supported on this CPU"); + FLAG_SET_DEFAULT(ValueTypeReturnedAsFields, false); } } diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.hpp b/src/hotspot/cpu/riscv/vm_version_riscv.hpp index 7a1ec2ba22c3..0d434c87d74d 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.hpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.hpp @@ -44,7 +44,14 @@ class VM_Version : public Abstract_VM_Version { // JEDEC encoded as ((bank - 1) << 7) | (0x7f & JEDEC) enum VendorId { - RIVOS = 0x6cf, // JEDEC: 0x4f, Bank: 14 + RIVOS = 0x6cf, // JEDEC: 0x4f, Bank: 14 + XUANTIE = 0x5b7, // JEDEC: 0x37, Bank: 12 + }; + + enum XuantieArchitectureId : uint64_t { + C925_MARCHID = 0x80000000091c1600ULL, + C930_MARCHID = 0x8000000009201600ULL, + C950_MARCHID = 0x8000000009241600ULL, }; class RVExtFeatures; @@ -249,7 +256,7 @@ class VM_Version : public Abstract_VM_Version { /* Zbb Basic bit-manipulation */ \ decl(Zbb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbb)) \ /* Zbc Carry-less multiplication */ \ - decl(Zbc , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ + decl(Zbc , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbc)) \ /* Bitmanip instructions for Cryptography */ \ decl(Zbkb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbkb)) \ /* Zbs Single-bit instructions */ \ @@ -499,6 +506,7 @@ class VM_Version : public Abstract_VM_Version { static void vendor_features(); // Vendors specific features static void rivos_features(); + static void xuantie_features(); // Determine vector length iff ext_V/UseRVV static uint32_t cpu_vector_length(); diff --git a/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp b/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp index 73948ef6429d..4cfcd39fda64 100644 --- a/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp +++ b/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp @@ -64,8 +64,8 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index, bool caller_is_c1) int slop_delta = 0; ByteSize entry_offset = caller_is_c1 - ? Method::from_compiled_inline_offset() - : Method::from_compiled_inline_ro_offset(); + ? Method::from_compiled_value_offset() + : Method::from_compiled_value_ro_offset(); ResourceMark rm; CodeBuffer cb(s->entry_point(), stub_code_length); @@ -159,8 +159,8 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index, bool caller_is_c1) int slop_delta = 0; ByteSize entry_offset = caller_is_c1 - ? Method::from_compiled_inline_offset() - : Method::from_compiled_inline_ro_offset(); + ? Method::from_compiled_value_offset() + : Method::from_compiled_value_ro_offset(); ResourceMark rm; CodeBuffer cb(s->entry_point(), stub_code_length); diff --git a/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp b/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp index 7b9e48a7e20e..ddb2147fb078 100644 --- a/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp +++ b/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp @@ -131,7 +131,7 @@ LoadFlattenedArrayStub::LoadFlattenedArrayStub(LIR_Opr array, LIR_Opr index, LIR void LoadFlattenedArrayStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); - __ untested("LoadFlattenedArrayStub::emit_code"); + __ z_lgfr(_index->as_register(), _index->as_register()); // int -> long ce->store_parameter(_array->as_register(), 1); ce->store_parameter(_index->as_register(), 0); ce->emit_call_c(Runtime1::entry_for(StubId::c1_load_flat_array_id)); @@ -154,7 +154,10 @@ StoreFlattenedArrayStub::StoreFlattenedArrayStub(LIR_Opr array, LIR_Opr index, L void StoreFlattenedArrayStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); - __ untested("StoreFlattenedArrayStub::emit_code"); + // _index is a T_INT LIR operand; on s390x 32-bit ops leave the upper 32 bits + // of the register undefined. Sign-extend to 64 bits before storing into the + // parameter slot so the runtime stub (which reloads with z_lg) sees a clean value. + __ z_lgfr(_index->as_register(), _index->as_register()); // int -> long ce->store_parameter(_array->as_register(), 2); ce->store_parameter(_index->as_register(), 1); ce->store_parameter(_value->as_register(), 0); @@ -293,12 +296,12 @@ void NewObjectArrayStub::emit_code(LIR_Assembler* ce) { void MonitorEnterStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); if (_throw_ie_stub != nullptr) { - static_assert(markWord::inline_type_pattern <= 0x7FFF, "must fit in simm16 for z_chi"); + static_assert(markWord::value_type_pattern <= 0x7FFF, "must fit in simm16 for z_chi"); // When we come here, _obj_reg has already been checked to be non-null. Register scratch = _scratch_reg->as_register(); __ z_lg(scratch, oopDesc::mark_offset_in_bytes(), _obj_reg->as_register()); - __ z_nilf(scratch, markWord::inline_type_pattern_mask); - __ z_chi(scratch, markWord::inline_type_pattern); + __ z_nilf(scratch, markWord::value_type_pattern_mask); + __ z_chi(scratch, markWord::value_type_pattern); __ branch_optimized(Assembler::bcondEqual, *_throw_ie_stub->entry()); } StubId enter_id; diff --git a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp index 14e72183e90b..90932ba15e50 100644 --- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp @@ -1233,7 +1233,7 @@ void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) { (result->is_single_fpu() && result->as_float_reg() == Z_F0) || (result->is_double_fpu() && result->as_double_reg() == Z_F0), "convention"); - assert(!InlineTypeReturnedAsFields, "unimplemented"); + assert(!ValueTypeReturnedAsFields, "unimplemented"); __ z_lg(Z_R1_scratch, Address(Z_thread, JavaThread::polling_page_offset())); @@ -2061,12 +2061,12 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { return; } - // Handle inline type arrays - if (flags & LIR_OpArrayCopy::src_inlinetype_check) { - arraycopy_inlinetype_check(src, tmp, stub, false, (flags & LIR_OpArrayCopy::src_null_check)); + // Handle value type arrays + if (flags & LIR_OpArrayCopy::src_valuetype_check) { + arraycopy_valuetype_check(src, tmp, stub, false, (flags & LIR_OpArrayCopy::src_null_check)); } - if (flags & LIR_OpArrayCopy::dst_inlinetype_check) { - arraycopy_inlinetype_check(dst, tmp, stub, true, (flags & LIR_OpArrayCopy::dst_null_check)); + if (flags & LIR_OpArrayCopy::dst_valuetype_check) { + arraycopy_valuetype_check(dst, tmp, stub, true, (flags & LIR_OpArrayCopy::dst_null_check)); } assert(default_type != nullptr && default_type->is_array_klass() && default_type->is_loaded(), "must be true at this point"); @@ -2510,10 +2510,14 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L } assert_different_registers(obj, k_RInfo, klass_RInfo); + Register mdo = noreg; + if (op->should_profile()) { + mdo = klass_RInfo; + metadata2reg(md->constant_encoding(), mdo); + } + if (op->need_null_check()) { if (op->should_profile()) { - Register mdo = klass_RInfo; - metadata2reg(md->constant_encoding(), mdo); NearLabel not_null; __ compareU64_and_branch(obj, (intptr_t) 0, Assembler::bcondNotEqual, not_null); // Object is null; update MDO and exit. @@ -2522,15 +2526,17 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L __ or2mem_8(data_addr, header_bits); __ branch_optimized(Assembler::bcondAlways, *obj_is_null); __ bind(not_null); - - Register recv = k_RInfo; - __ load_klass(recv, obj); - type_profile_helper(mdo, md, data, recv, Rtmp1); } else { __ compareU64_and_branch(obj, (intptr_t) 0, Assembler::bcondEqual, *obj_is_null); } } + if (op->should_profile()) { + Register recv = k_RInfo; + __ load_klass(recv, obj); + type_profile_helper(mdo, md, data, recv, Rtmp1); + } + Label *failure_target = failure; Label *success_target = success; @@ -3057,7 +3063,7 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { } } -void LIR_Assembler::emit_profile_inline_type(LIR_OpProfileInlineType* op) { +void LIR_Assembler::emit_profile_value_type(LIR_OpProfileValueType* op) { Register obj = op->obj()->as_register(); Register tmp = op->tmp()->as_pointer_register(); LIR_Address* mdo_addr = op->mdp()->as_address_ptr(); @@ -3067,10 +3073,10 @@ void LIR_Assembler::emit_profile_inline_type(LIR_OpProfileInlineType* op) { bool not_null = op->not_null(); int flag = op->flag(); - Label not_inline_type; - __ test_oop_is_not_inline_type(obj, tmp, not_inline_type, !not_null); + Label not_value_type; + __ test_oop_is_not_value_type(obj, tmp, not_value_type, !not_null); __ z_oiy(Address(mdo_base, mdo_offs), flag); - __ bind(not_inline_type); + __ bind(not_value_type); } void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) { @@ -3094,7 +3100,7 @@ void LIR_Assembler::check_orig_pc() { Unimplemented(); } -int LIR_Assembler::store_inline_type_fields_to_buf(ciInlineKlass* vk) { +int LIR_Assembler::store_value_type_fields_to_buf(ciValueKlass* vk) { Unimplemented(); return 0; } @@ -3132,23 +3138,23 @@ void LIR_Assembler::emit_opSubstitutabilityCheck(LIR_OpSubstitutabilityCheck* op ciKlass* left_klass = op->left_klass(); ciKlass* right_klass = op->right_klass(); - // (2) Inline type check -- if either of the operands is not an inline type, + // (2) Value type check -- if either of the operands is not a value type, // they are not substitutable. We do this only if we are not sure that the - // operands are inline type + // operands are value type if ((left_klass == nullptr || right_klass == nullptr) ||// The klass is still unloaded, or came from a Phi node. - !left_klass->is_inlinetype() || !right_klass->is_inlinetype()) { - static_assert(markWord::inline_type_pattern <= 0x7FFF, "must fit in simm16 for z_chi"); + !left_klass->is_value_klass() || !right_klass->is_value_klass()) { + static_assert(markWord::value_type_pattern <= 0x7FFF, "must fit in simm16 for z_chi"); Register tmp = op->tmp1()->as_register(); - __ z_llill(tmp, markWord::inline_type_pattern); + __ z_llill(tmp, markWord::value_type_pattern); __ z_ng(tmp, Address(left, oopDesc::mark_offset_in_bytes())); __ z_ng(tmp, Address(right, oopDesc::mark_offset_in_bytes())); - __ z_chi(tmp, markWord::inline_type_pattern); + __ z_chi(tmp, markWord::value_type_pattern); __ branch_optimized(Assembler::bcondNotEqual, L_oops_not_equal); } // (3) Same klass check: if the operands are of different klasses, they are not substitutable. - if (left_klass != nullptr && left_klass->is_inlinetype() && left_klass == right_klass) { - // No need to load klass -- the operands are statically known to be the same inline klass. + if (left_klass != nullptr && left_klass->is_value_klass() && left_klass == right_klass) { + // No need to load klass -- the operands are statically known to be the same value klass. __ branch_optimized(Assembler::bcondAlways, *op->stub()->entry()); } else { Register tmp1 = op->tmp1()->as_register(); @@ -3177,7 +3183,7 @@ void LIR_Assembler::emit_opSubstitutabilityCheck(LIR_OpSubstitutabilityCheck* op __ bind(L_end); } -void LIR_Assembler::arraycopy_inlinetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check) { +void LIR_Assembler::arraycopy_valuetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check) { if (null_check) { __ compare64_and_branch(obj, (intptr_t)0, Assembler::bcondEqual, *slow_path->entry()); } diff --git a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.hpp b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.hpp index fbff174d22d2..4a44476a8f1a 100644 --- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.hpp @@ -37,7 +37,7 @@ void move(LIR_Opr src, LIR_Opr dst); - void arraycopy_inlinetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check); + void arraycopy_valuetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check); public: address emit_call_c(address a); diff --git a/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp b/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp index 0cc63d5caf41..5026ccbf7da9 100644 --- a/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp @@ -31,9 +31,9 @@ #include "c1/c1_Runtime1.hpp" #include "c1/c1_ValueStack.hpp" #include "ci/ciArray.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciObjArrayKlass.hpp" #include "ci/ciTypeArrayKlass.hpp" +#include "ci/ciValueKlass.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "vmreg_s390.inline.hpp" @@ -281,7 +281,7 @@ void LIRGenerator::do_MonitorEnter(MonitorEnter* x) { info_for_exception = state_for (x); } CodeStub* throw_ie_stub = - x->maybe_inlinetype() ? + x->maybe_valuetype() ? new SimpleExceptionStub(StubId::c1_throw_identity_exception_id, obj.result(), state_for(x)) : nullptr; @@ -784,7 +784,7 @@ void LIRGenerator::do_NewInstance(NewInstance* x) { LIR_Opr tmp2 = FrameMap::Z_R13_oop_opr; LIR_Opr tmp3 = reg; LIR_Opr tmp4 = LIR_OprFact::illegalOpr; - new_instance(reg, x->klass(), x->is_unresolved(), !x->is_unresolved() && x->klass()->is_inlinetype(), + new_instance(reg, x->klass(), x->is_unresolved(), !x->is_unresolved() && x->klass()->is_value_klass(), tmp1, tmp2, tmp3, tmp4, klass_reg, info); 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 e52ffabf35ed..2ee98f22c3fd 100644 --- a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp @@ -68,7 +68,7 @@ void C1_MacroAssembler::build_frame_helper(int frame_size_in_bytes, int sp_offse void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, bool has_scalarized_args, - Label* verified_inline_entry_label) { + Label* verified_value_entry_label) { assert(bang_size_in_bytes >= frame_size_in_bytes, "stack bang size incorrect"); generate_stack_overflow_check(bang_size_in_bytes); @@ -77,9 +77,9 @@ void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_by BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); bs->nmethod_entry_barrier(this); - if (verified_inline_entry_label != nullptr) { + if (verified_value_entry_label != nullptr) { // Jump here from the scalarized entry points that already created the frame. - bind(*verified_inline_entry_label); + bind(*verified_value_entry_label); } } @@ -87,14 +87,14 @@ void C1_MacroAssembler::verified_entry(bool breakAtEntry) { if (breakAtEntry) z_illtrap(0xC1); } -// Scalarized entry point: buffers inline-type arguments, shuffles them into +// Scalarized entry point: buffers value-type arguments, shuffles them into // the normal ABI layout, then falls through into the verified entry. // // NOTE: the entire body is guarded by ShouldNotCallThis() because -// InlineTypePassFieldsAsArgs is forced off for s390x +// ValueTypePassFieldsAsArgs is forced off for s390x int C1_MacroAssembler::scalarized_entry(const CompiledEntrySignature* ces, int frame_size_in_bytes, int bang_size_in_bytes, - int sp_offset_for_orig_pc, Label& verified_inline_entry_label, bool is_inline_ro_entry) { - assert(InlineTypePassFieldsAsArgs, "sanity"); + int sp_offset_for_orig_pc, Label& verified_value_entry_label, bool is_value_ro_entry) { + assert(ValueTypePassFieldsAsArgs, "sanity"); // Make sure there is enough stack space for this method's activation. assert(bang_size_in_bytes >= frame_size_in_bytes, "stack bang size incorrect"); ShouldNotCallThis(); // poison: remove once validated on s390x @@ -103,13 +103,13 @@ int C1_MacroAssembler::scalarized_entry(const CompiledEntrySignature* ces, int f generate_stack_overflow_check(bang_size_in_bytes); GrowableArray* sig = ces->sig(); - GrowableArray* sig_cc = is_inline_ro_entry ? ces->sig_cc_ro() : ces->sig_cc(); + GrowableArray* sig_cc = is_value_ro_entry ? ces->sig_cc_ro() : ces->sig_cc(); VMRegPair* regs = ces->regs(); - VMRegPair* regs_cc = is_inline_ro_entry ? ces->regs_cc_ro() : ces->regs_cc(); + VMRegPair* regs_cc = is_value_ro_entry ? ces->regs_cc_ro() : ces->regs_cc(); int args_on_stack = ces->args_on_stack(); - int args_on_stack_cc = is_inline_ro_entry ? ces->args_on_stack_cc_ro() : ces->args_on_stack_cc(); + int args_on_stack_cc = is_value_ro_entry ? ces->args_on_stack_cc_ro() : ces->args_on_stack_cc(); - assert(sig->length() <= sig_cc->length(), "Zero-sized inline class not allowed!"); + assert(sig->length() <= sig_cc->length(), "Zero-sized value class not allowed!"); BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, sig_cc->length()); int args_passed = sig->length(); int args_passed_cc = SigEntry::fill_sig_bt(sig_cc, sig_bt); @@ -122,13 +122,13 @@ int C1_MacroAssembler::scalarized_entry(const CompiledEntrySignature* ces, int f BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); bs->nmethod_entry_barrier(this); - // Z_R13 is the method register expected by c1_buffer_inline_args (see - // c1_Runtime1_s390.cpp, StubId::c1_buffer_inline_args_id handler). + // Z_R13 is the method register expected by c1_buffer_value_args (see + // c1_Runtime1_s390.cpp, StubId::c1_buffer_value_args_id handler). load_const_optimized(Z_R13, (intptr_t)(ces->method())); - if (is_inline_ro_entry) { - call_c_opt(Runtime1::entry_for(StubId::c1_buffer_inline_args_no_receiver_id)); + if (is_value_ro_entry) { + call_c_opt(Runtime1::entry_for(StubId::c1_buffer_value_args_no_receiver_id)); } else { - call_c_opt(Runtime1::entry_for(StubId::c1_buffer_inline_args_id)); + call_c_opt(Runtime1::entry_for(StubId::c1_buffer_value_args_id)); } int rt_call_offset = offset(); @@ -140,21 +140,18 @@ int C1_MacroAssembler::scalarized_entry(const CompiledEntrySignature* ces, int f assert(args_on_stack <= args_on_stack_cc, "Sanity check"); - // Z_R14 (the buffered value array) is the val_array argument to - // shuffle_inline_args. On aarch64 a dedicated callee-saved register is - // used because r0 may hold a live argument; on s390x Z_R14 holds the - // return address which has already been restored above, so it is free here. - // TODO (s390x): confirm this register choice is safe across shuffle_inline_args. - shuffle_inline_args(true, is_inline_ro_entry, sig_cc, - args_passed_cc, args_on_stack_cc, regs_cc, // from - args_passed, args_on_stack, regs, // to - 0, Z_R14); + // Z_R2 holds the buffered value array returned by buffer_inline_args[_no_receiver]. + z_lgr(Z_R11, Z_R2); + shuffle_value_args(true, is_value_ro_entry, sig_cc, + args_passed_cc, args_on_stack_cc, regs_cc, // from + args_passed, args_on_stack, regs, // to + 0, Z_R11); // Build the real frame. The jump below skips the stack-bang and frame-setup - // in verified_inline_entry (which uses a different real_frame_size). + // in verified_value_entry (which uses a different real_frame_size). build_frame_helper(frame_size_in_bytes, sp_offset_for_orig_pc, false); - z_brul(verified_inline_entry_label); + z_brul(verified_value_entry_label); return rt_call_offset; } diff --git a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.hpp b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.hpp index e93eff43bd4a..273409291743 100644 --- a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -43,14 +43,14 @@ // locking // Rmark : Used to hold locked markWord to be CASed into obj, contents destroyed. // Roop : Must point to the object to lock, contents preserved. - // Rbox : Must point to the displaced header location, contents preserved. + // Rbox : Must point to the object monitor cache location, contents preserved. // Z_R1_scratch : Used as temp and will be killed void lock_object(Register Rmark, Register Roop, Register Rbox, Label& slow_case); // unlocking // Rmark : Used to hold original markWord to be CASed back into obj, contents destroyed. // Roop : Must point to the object to lock, contents preserved. - // Rbox : Must point to the displaced header location, contents destroyed. + // Rbox : Must point to the object monitor cache location, contents destroyed. // Z_R1_scratch : Used as temp and will be killed void unlock_object(Register Rmark, Register Roop, Register Rbox, Label& slow_case); diff --git a/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp b/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp index f2965e02e8bf..33c7bc584bbb 100644 --- a/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp +++ b/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp @@ -435,12 +435,12 @@ OopMapSet* Runtime1::generate_code_for(StubId id, StubAssembler* sasm) { case StubId::c1_new_object_array_id: __ compare32_and_branch(t0, Klass::_lh_array_tag_ref_value, Assembler::bcondEqual, ok); __ compare32_and_branch(t0, Klass::_lh_array_tag_flat_value, Assembler::bcondEqual, ok); - __ stop("assert(is an object or inline type array klass)"); + __ stop("assert(is an object or value type array klass)"); break; case StubId::c1_new_null_free_array_id: __ compare32_and_branch(t0, Klass::_lh_array_tag_flat_value, Assembler::bcondEqual, ok); __ compare32_and_branch(t0, Klass::_lh_array_tag_ref_value, Assembler::bcondEqual, ok); - __ stop("assert(is an object or inline type array klass)"); + __ stop("assert(is an object or value type array klass)"); break; default: ShouldNotReachHere(); } @@ -487,20 +487,20 @@ OopMapSet* Runtime1::generate_code_for(StubId id, StubAssembler* sasm) { } break; - case StubId::c1_buffer_inline_args_id: - case StubId::c1_buffer_inline_args_no_receiver_id: + case StubId::c1_buffer_value_args_id: + case StubId::c1_buffer_value_args_no_receiver_id: { - __ untested("c1_buffer_inline_args"); - const char* name = (id == StubId::c1_buffer_inline_args_id) ? - "buffer_inline_args" : "buffer_inline_args_no_receiver"; + __ untested("c1_buffer_value_args"); + const char* name = (id == StubId::c1_buffer_value_args_id) ? + "buffer_value_args" : "buffer_value_args_no_receiver"; __ set_info(name, dont_gc_arguments); // This is called from a C1 method's scalarized entry point OopMap* map = save_live_registers(sasm); Register method = Z_R13; // Incoming - address entry = (id == StubId::c1_buffer_inline_args_id) ? - CAST_FROM_FN_PTR(address, buffer_inline_args) : - CAST_FROM_FN_PTR(address, buffer_inline_args_no_receiver); + address entry = (id == StubId::c1_buffer_value_args_id) ? + CAST_FROM_FN_PTR(address, buffer_value_args) : + CAST_FROM_FN_PTR(address, buffer_value_args_no_receiver); int call_offset = __ call_RT(Z_R14, noreg, entry, method); oop_maps = new OopMapSet(); @@ -514,20 +514,18 @@ OopMapSet* Runtime1::generate_code_for(StubId id, StubAssembler* sasm) { case StubId::c1_load_flat_array_id: { - __ untested("c1_load_flat_array"); __ set_info("load_flat_array", dont_gc_arguments); OopMap* map = save_live_registers(sasm); // Called with store_parameter and not C abi - int arg_offset = FrameMap::first_available_sp_in_frame; + // Parameters were stored before save_live_registers pushed a frame, + // so we need to account for the frame size when loading them + const int frame_size = sasm->frame_size() * VMRegImpl::slots_per_word * VMRegImpl::stack_slot_size; + int arg_offset = FrameMap::first_available_sp_in_frame + frame_size; __ z_lg(Z_ARG2, arg_offset + 1 * BytesPerWord, Z_SP); // array __ z_lg(Z_ARG3, arg_offset + 0 * BytesPerWord, Z_SP); // index int call_offset = __ call_RT(Z_R2, noreg, CAST_FROM_FN_PTR(address, load_flat_array), Z_ARG2, Z_ARG3); - // Ensure the stores that initialize the buffer are visible - // before many subsequent store that publishes this reference. - __ z_fence(); - oop_maps = new OopMapSet(); oop_maps->add_gc_map(call_offset, map); restore_live_registers_except_r2(sasm); @@ -540,12 +538,14 @@ OopMapSet* Runtime1::generate_code_for(StubId id, StubAssembler* sasm) { case StubId::c1_store_flat_array_id: { - __ untested("c1_store_flat_array"); __ set_info("store_flat_array", dont_gc_arguments); OopMap* map = save_live_registers(sasm); // Called with store_parameter and not C abi - int arg_offset = FrameMap::first_available_sp_in_frame; + // Parameters were stored before save_live_registers pushed a frame, + // so we need to account for the frame size when loading them + const int frame_size = sasm->frame_size() * VMRegImpl::slots_per_word * VMRegImpl::stack_slot_size; + int arg_offset = FrameMap::first_available_sp_in_frame + frame_size; __ z_lg(Z_ARG2, arg_offset + 2 * BytesPerWord, Z_SP); // array __ z_lg(Z_ARG3, arg_offset + 1 * BytesPerWord, Z_SP); // index __ z_lg(Z_ARG4, arg_offset + 0 * BytesPerWord, Z_SP); // value @@ -553,7 +553,7 @@ OopMapSet* Runtime1::generate_code_for(StubId id, StubAssembler* sasm) { oop_maps = new OopMapSet(); oop_maps->add_gc_map(call_offset, map); - restore_live_registers_except_r2(sasm); + restore_live_registers(sasm); __ z_br(Z_R14); } break; diff --git a/src/hotspot/cpu/s390/frame_s390.inline.hpp b/src/hotspot/cpu/s390/frame_s390.inline.hpp index 024771fa48df..5d0756b35586 100644 --- a/src/hotspot/cpu/s390/frame_s390.inline.hpp +++ b/src/hotspot/cpu/s390/frame_s390.inline.hpp @@ -421,7 +421,7 @@ inline frame frame::sender_for_compiled_frame(RegisterMap *map) const { #ifdef COMPILER1 DEBUG_ONLY(nmethod* nm = _cb->as_nmethod_or_null()); assert(nm == nullptr || !nm->is_compiled_by_c1() || !nm->method()->has_scalarized_args() || - pc() >= nm->verified_inline_entry_point(), "unsupported"); + pc() >= nm->verified_value_entry_point(), "unsupported"); #endif if (!_cb->is_nmethod()) { // compiled frames do not use callee-saved registers map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread())); diff --git a/src/hotspot/cpu/s390/gc/g1/g1_s390.ad b/src/hotspot/cpu/s390/gc/g1/g1_s390.ad index 26727a448c96..0371a6fdf4a9 100644 --- a/src/hotspot/cpu/s390/gc/g1/g1_s390.ad +++ b/src/hotspot/cpu/s390/gc/g1/g1_s390.ad @@ -95,8 +95,9 @@ instruct g1StoreLSpecialOneOopOff0(indirect mem, iRegL src, immI_0 off, iRegL tm __ z_stg($src$$Register, Address($mem$$Register, 0)); - // Extract the narrow oop field value - __ z_llgfr($tmp1$$Register, $src$$Register); + // Extract the narrow oop at offset 0: on big-endian s390x the field at + // memory offset 0 occupies the HIGH 32 bits of the 64-bit register. + __ z_srlg($tmp1$$Register, $src$$Register, 32); __ oop_decoder($tmp1$$Register, $tmp1$$Register, true /* maybe_null */); write_barrier_post(masm, this, $mem$$Register /* store_addr */, @@ -127,7 +128,9 @@ instruct g1StoreLSpecialOneOopOff4(indirect mem, iRegL src, immI_4 off, iRegL tm __ z_stg($src$$Register, Address($mem$$Register, 0)); - __ z_srlg($tmp2$$Register, $src$$Register, 32); + // Extract the narrow oop at offset 4: on big-endian s390x the field at + // memory offset 4 occupies the LOW 32 bits of the 64-bit register. + __ z_llgfr($tmp2$$Register, $src$$Register); __ oop_decoder($tmp2$$Register, $tmp2$$Register, true /* maybe_null */); write_barrier_post(masm, this, $tmp1$$Register /* store_addr */, @@ -163,18 +166,20 @@ instruct g1StoreLSpecialTwoOops(indirect mem, iRegL src, iRegL tmp1, iRegL tmp2, __ z_stg($src$$Register, Address($mem$$Register, 0)); + // Oop at offset 0: high 32 bits of register -> memory address mem+0. __ z_srlg($tmp1$$Register, $src$$Register, 32); __ oop_decoder($tmp1$$Register, $tmp1$$Register, true /* maybe_null */); write_barrier_post(masm, this, - $tmp4$$Register /* store_addr */, + $mem$$Register /* store_addr */, $tmp1$$Register /* new_val */, $tmp2$$Register /* tmp1 */, $tmp3$$Register /* tmp2 */); + // Oop at offset 4: low 32 bits of register -> memory address mem+4. __ z_llgfr($tmp1$$Register, $src$$Register); __ oop_decoder($tmp1$$Register, $tmp1$$Register, true /* maybe_null */); write_barrier_post(masm, this, - $mem$$Register /* store_addr */, + $tmp4$$Register /* store_addr */, $tmp1$$Register /* new_val */, $tmp2$$Register /* tmp1 */, $tmp3$$Register /* tmp2 */); diff --git a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp index a850ac753c38..3544d72a2c7d 100644 --- a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp @@ -113,15 +113,15 @@ void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators // Generic implementation. GCs can provide an optimized one. void BarrierSetAssembler::flat_field_copy(MacroAssembler* masm, DecoratorSet decorators, - Register src, Register dst, Register inline_layout_info) { + Register src, Register dst, Register value_field_layout_info) { // flat_field_copy implementation is fairly complex, and there are not any // "short-cuts" to be made from asm. What there is, appears to have the same // cost in C++, so just "call_VM_leaf" for now rather than maintain hundreds // of hand-rolled instructions... if (decorators & IS_DEST_UNINITIALIZED) { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetRuntime::value_copy_is_dest_uninitialized), src, dst, inline_layout_info); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetRuntime::value_copy_is_dest_uninitialized), src, dst, value_field_layout_info); } else { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetRuntime::value_copy), src, dst, inline_layout_info); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetRuntime::value_copy), src, dst, value_field_layout_info); } } diff --git a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp index c1b174f5f79a..0654eaec30a0 100644 --- a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp @@ -53,7 +53,7 @@ class BarrierSetAssembler: public CHeapObj { const Address& addr, Register val, Register tmp1, Register tmp2, Register tmp3); virtual void flat_field_copy(MacroAssembler* masm, DecoratorSet decorators, - Register src, Register dst, Register inline_layout_info); + Register src, Register dst, Register value_field_layout_info); virtual void resolve_jobject(MacroAssembler* masm, Register value, Register tmp1, Register tmp2); virtual void resolve_global_jobject(MacroAssembler* masm, Register value, Register tmp1, Register tmp2); diff --git a/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp b/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp index da27cfc63048..5ac2e7cd0e8c 100644 --- a/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp +++ b/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp @@ -135,9 +135,9 @@ static void set_guard_value_impl(nmethod* nm, int value, int bit_mask) { if (!nm->is_osr_method() && nm->method()->has_scalarized_args()) { assert(false, "untested code"); // nmethods with scalarized arguments have multiple entry points that each have an own nmethod entry barrier - assert(nm->verified_entry_point() != nm->verified_inline_entry_point(), "scalarized entry point not found"); - address method_body = nm->is_compiled_by_c1() ? nm->verified_inline_entry_point() : nm->verified_entry_point(); - address entry_point2 = nm->is_compiled_by_c1() ? nm->verified_entry_point() : nm->verified_inline_entry_point(); + assert(nm->verified_entry_point() != nm->verified_value_entry_point(), "scalarized entry point not found"); + address method_body = nm->is_compiled_by_c1() ? nm->verified_value_entry_point() : nm->verified_entry_point(); + address entry_point2 = nm->is_compiled_by_c1() ? nm->verified_entry_point() : nm->verified_value_entry_point(); int barrier_offset = reinterpret_cast
(barrier1) - method_body; NativeMethodBarrier* barrier2 = reinterpret_cast(entry_point2 + barrier_offset); @@ -145,8 +145,8 @@ static void set_guard_value_impl(nmethod* nm, int value, int bit_mask) { DEBUG_ONLY(barrier2->verify()); barrier2->set_guard_value(value, bit_mask); - if (method_body != nm->verified_inline_ro_entry_point() && entry_point2 != nm->verified_inline_ro_entry_point()) { - NativeMethodBarrier* barrier3 = reinterpret_cast(nm->verified_inline_ro_entry_point() + barrier_offset); + if (method_body != nm->verified_value_ro_entry_point() && entry_point2 != nm->verified_value_ro_entry_point()) { + NativeMethodBarrier* barrier3 = reinterpret_cast(nm->verified_value_ro_entry_point() + barrier_offset); assert(barrier1 != barrier3 && barrier2 != barrier3, "sanity"); DEBUG_ONLY(barrier3->verify()); barrier3->set_guard_value(value, bit_mask); diff --git a/src/hotspot/cpu/s390/globals_s390.hpp b/src/hotspot/cpu/s390/globals_s390.hpp index 9a273204654f..aeaf14df2a77 100644 --- a/src/hotspot/cpu/s390/globals_s390.hpp +++ b/src/hotspot/cpu/s390/globals_s390.hpp @@ -78,8 +78,8 @@ define_pd_global(bool, CompactStrings, true); // 8146801 (Short Array Allocation): No performance work done here yet. define_pd_global(intx, InitArrayShortSize, 1*BytesPerLong); -define_pd_global(bool, InlineTypePassFieldsAsArgs, false); -define_pd_global(bool, InlineTypeReturnedAsFields, false); +define_pd_global(bool, ValueTypePassFieldsAsArgs, false); +define_pd_global(bool, ValueTypeReturnedAsFields, false); #define ARCH_FLAGS(develop, \ product, \ diff --git a/src/hotspot/cpu/s390/interp_masm_s390.cpp b/src/hotspot/cpu/s390/interp_masm_s390.cpp index e7a8e5fea1c5..30812eff42ea 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.cpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp @@ -1087,10 +1087,6 @@ void InterpreterMacroAssembler::remove_activation(TosState state, // Save result (push state before jvmti call and pop it afterwards) and notify jvmti. notify_method_exit(false, state, notify_jvmti ? NotifyJVMTI : SkipNotifyJVMTI); - if (UseArrayFlattening) { - stop("implement function InterpreterMacroAssembler::remove_activation #2"); - } - if (StackReservedPages > 0) { BLOCK_COMMENT("reserved_stack_check:"); // Test if reserved zone needs to be enabled. @@ -1118,7 +1114,7 @@ void InterpreterMacroAssembler::remove_activation(TosState state, bind(no_reserved_zone_enabling); } - if (state == atos && InlineTypeReturnedAsFields) { + if (state == atos && ValueTypeReturnedAsFields) { stop("implement function InterpreterMacroAssembler::remove_activation"); } @@ -1363,17 +1359,17 @@ void InterpreterMacroAssembler::profile_acmp(Register mdp, profile_obj_type(left, Address(mdp, in_bytes(ACmpData::left_offset())), tmp); - Label left_not_inline_type; - test_oop_is_not_inline_type(left, tmp, left_not_inline_type); - set_mdp_flag_at(mdp, ACmpData::left_inline_type_byte_constant()); - bind(left_not_inline_type); + Label left_not_value_type; + test_oop_is_not_value_type(left, tmp, left_not_value_type); + set_mdp_flag_at(mdp, ACmpData::left_value_type_byte_constant()); + bind(left_not_value_type); profile_obj_type(right, Address(mdp, in_bytes(ACmpData::right_offset())), tmp); - Label right_not_inline_type; - test_oop_is_not_inline_type(right, tmp, right_not_inline_type); - set_mdp_flag_at(mdp, ACmpData::right_inline_type_byte_constant()); - bind(right_not_inline_type); + Label right_not_value_type; + test_oop_is_not_value_type(right, tmp, right_not_value_type); + set_mdp_flag_at(mdp, ACmpData::right_value_type_byte_constant()); + bind(right_not_value_type); bind(profile_continue); } @@ -2199,7 +2195,7 @@ void InterpreterMacroAssembler::pop_interpreter_frame(Register return_pc, Regist } //------------------------------------- -// Valhalla inline type support +// Valhalla value type support //------------------------------------- void InterpreterMacroAssembler::read_flat_field(Register entry, Register obj) { @@ -2214,9 +2210,9 @@ void InterpreterMacroAssembler::write_flat_field(Register entry, Register field_ assert_different_registers(entry, field_offset, tmp1, tmp2, obj); Label slow_path, done; - // Load flags and check if field is null-free inline type. + // Load flags and check if field is null-free value type. load_sized_value(tmp1, Address(entry, in_bytes(ResolvedFieldEntry::flags_offset())), sizeof(u1), false); - test_field_is_not_null_free_inline_type(tmp1, slow_path); + test_field_is_not_null_free_value_type(tmp1, slow_path); // Null check the value being stored (Z_tos holds the value oop). null_check(Z_tos); // FIXME JDK-8341120 @@ -2229,13 +2225,13 @@ void InterpreterMacroAssembler::write_flat_field(Register entry, Register field_ load_klass(tmp1, Z_tos); payload_addr(Z_tos, Z_tos, tmp1); - // Load the InlineLayoutInfo for this field: + // Load the ValueFieldLayoutInfo for this field: // field_index (u2) from the entry, holder klass pointer from the entry. // Reuse field_offset as the layout_info register from here on. Register layout_info = field_offset; load_sized_value(tmp1, Address(entry, in_bytes(ResolvedFieldEntry::field_index_offset())), sizeof(u2), false); load_sized_value(tmp2, Address(entry, in_bytes(ResolvedFieldEntry::field_holder_offset())), sizeof(void*), false); - inline_layout_info(tmp2, tmp1, layout_info); + value_field_layout_info(tmp2, tmp1, layout_info); // Inline byte-copy of the value's payload into the flat field slot. flat_field_copy(IN_HEAP, Z_tos, obj, layout_info); diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index bb4a10a5f80b..097e29666248 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -26,7 +26,7 @@ #include "asm/codeBuffer.hpp" #include "asm/macroAssembler.inline.hpp" -#include "ci/ciInlineKlass.hpp" +#include "ci/ciValueKlass.hpp" #include "code/compiledIC.hpp" #include "compiler/disassembler.hpp" #include "gc/shared/barrierSet.hpp" @@ -3921,35 +3921,35 @@ void MacroAssembler::null_check(Register reg, Register tmp, int64_t offset) { } //------------------------------------- -// Valhalla inline type support +// Valhalla value type support //------------------------------------- -void MacroAssembler::test_markword_is_inline_type(Register markword, Label& is_inline_type) { - static_assert(markWord::inline_type_pattern <= 0x7FFF, "must fit in simm16 for z_chi"); - z_nilf(markword, markWord::inline_type_pattern_mask); - z_chi(markword, markWord::inline_type_pattern); - branch_optimized(bcondEqual, is_inline_type); +void MacroAssembler::test_markword_is_value_type(Register markword, Label& is_value_type) { + static_assert(markWord::value_type_pattern <= 0x7FFF, "must fit in simm16 for z_chi"); + z_nilf(markword, markWord::value_type_pattern_mask); + z_chi(markword, markWord::value_type_pattern); + branch_optimized(bcondEqual, is_value_type); } -void MacroAssembler::test_oop_is_not_inline_type(Register object, Register tmp, Label& not_inline_type, bool can_be_null) { +void MacroAssembler::test_oop_is_not_value_type(Register object, Register tmp, Label& not_value_type, bool can_be_null) { if (can_be_null) { z_ltgr(object, object); - branch_optimized(bcondEqual, not_inline_type); + branch_optimized(bcondEqual, not_value_type); } z_lg(tmp, oopDesc::mark_offset_in_bytes(), object); - z_nilf(tmp, markWord::inline_type_pattern_mask); - z_chi(tmp, markWord::inline_type_pattern); - branch_optimized(bcondNotEqual, not_inline_type); + z_nilf(tmp, markWord::value_type_pattern_mask); + z_chi(tmp, markWord::value_type_pattern); + branch_optimized(bcondNotEqual, not_value_type); } -void MacroAssembler::test_field_is_null_free_inline_type(Register flags, Label& is_null_free) { - testbit(flags, ResolvedFieldEntry::is_null_free_inline_type_shift); +void MacroAssembler::test_field_is_null_free_value_type(Register flags, Label& is_null_free) { + testbit(flags, ResolvedFieldEntry::is_null_free_value_type_shift); z_brc(Assembler::bcondAllOne, is_null_free); } -void MacroAssembler::test_field_is_not_null_free_inline_type(Register flags, Label& not_null_free_inline_type) { - testbit(flags, ResolvedFieldEntry::is_null_free_inline_type_shift); - z_brc(Assembler::bcondAllZero, not_null_free_inline_type); +void MacroAssembler::test_field_is_not_null_free_value_type(Register flags, Label& not_null_free_value_type) { + testbit(flags, ResolvedFieldEntry::is_null_free_value_type_shift); + z_brc(Assembler::bcondAllZero, not_null_free_value_type); } void MacroAssembler::test_field_is_flat(Register flags, Label& is_flat) { @@ -4286,26 +4286,26 @@ void MacroAssembler::test_flat_array_layout(Register lh, Label& is_flat_array) { z_brnaz(is_flat_array); } -void MacroAssembler::inline_layout_info(Register holder_klass, Register index, Register layout_info) { +void MacroAssembler::value_field_layout_info(Register holder_klass, Register index, Register layout_info) { assert_different_registers(holder_klass, index, layout_info); - z_lg(layout_info, Address(holder_klass, InstanceKlass::inline_layout_info_array_offset())); + z_lg(layout_info, Address(holder_klass, InstanceKlass::value_field_layout_info_array_offset())); #ifdef ASSERT { Label done; z_ltgr(layout_info, layout_info); z_brne(done); - stop("inline_layout_info_array is null"); + stop("value_field_layout_info_array is null"); bind(done); } #endif - InlineLayoutInfo array[2]; + ValueFieldLayoutInfo array[2]; int size = (char*)&array[1] - (char*)&array[0]; // computing size of array elements if (is_power_of_2(size)) { z_sllg(index, index, log2i_exact(size)); // Scale index by power of 2 } else { z_msgfi(index, size); // Scale the index to be the entry index * array_element_size } - z_lay(layout_info, Address(layout_info, index, Array::base_offset_in_bytes())); + z_lay(layout_info, Address(layout_info, index, Array::base_offset_in_bytes())); } // Compare klass ptr in memory against klass ptr in register. @@ -4552,24 +4552,24 @@ void MacroAssembler::store_heap_oop(Register Roop, const Address &a, } void MacroAssembler::flat_field_copy(DecoratorSet decorators, Register src, Register dst, - Register inline_layout_info) { + Register value_field_layout_info) { BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); - bs->flat_field_copy(this, decorators, src, dst, inline_layout_info); + bs->flat_field_copy(this, decorators, src, dst, value_field_layout_info); } -void MacroAssembler::payload_offset(Register inline_klass, Register offset) { - z_lg(offset, Address(inline_klass, InlineKlass::adr_members_offset())); - z_llgf(offset, Address(offset, InlineKlass::payload_offset_offset())); +void MacroAssembler::payload_offset(Register value_klass, Register offset) { + z_lg(offset, Address(value_klass, ValueKlass::adr_members_offset())); + z_llgf(offset, Address(offset, ValueKlass::payload_offset_offset())); } -void MacroAssembler::payload_addr(Register oop, Register data, Register inline_klass) { +void MacroAssembler::payload_addr(Register oop, Register data, Register value_klass) { // ((address) (void*) o) + vk->payload_offset(); // - // oop must differ from inline_klass: payload_offset() overwrites inline_klass + // oop must differ from value_klass: payload_offset() overwrites value_klass // with the payload offset integer before we add it back to oop. - assert_different_registers(oop, inline_klass); + assert_different_registers(oop, value_klass); Register offset = (data == oop) ? Z_R1_scratch : data; - payload_offset(inline_klass, offset); + payload_offset(value_klass, offset); if (data == oop) { z_agr(data, offset); } else { @@ -6374,10 +6374,10 @@ void MacroAssembler::fast_lock(Register basic_lock, Register obj, Register temp1 const Register locked_obj = top; z_oill(mark, markWord::lock_neutral_value); if (Arguments::is_valhalla_enabled()) { - static_assert((uint32_t)markWord::inline_type_bit_in_place <= 0x7FFFFFFF, - "inline_type_bit_in_place must fit in low 32 bits for z_nilf"); - // Mask inline_type bit so CAS fails (-> slow) if object is an inline type. - z_nilf(mark, ~((uint32_t)markWord::inline_type_bit_in_place)); + static_assert((uint32_t)markWord::value_type_bit_in_place <= 0x7FFFFFFF, + "value_type_bit_in_place must fit in low 32 bits for z_nilf"); + // Mask value_type bit so CAS fails (-> slow) if object is a value type. + z_nilf(mark, ~((uint32_t)markWord::value_type_bit_in_place)); } z_lgr(locked_obj, mark); // Clear lock-bits from locked_obj (locked state) @@ -6535,10 +6535,10 @@ void MacroAssembler::compiler_fast_lock_object(Register obj, Register box, Regis const Register locked_obj = top; z_oill(mark, markWord::lock_neutral_value); if (Arguments::is_valhalla_enabled()) { - static_assert((uint32_t)markWord::inline_type_bit_in_place <= 0x7FFFFFFF, - "inline_type_bit_in_place must fit in low 32 bits for z_nilf"); - // Mask inline_type bit so CAS fails (-> slow) if object is an inline type. - z_nilf(mark, ~((uint32_t)markWord::inline_type_bit_in_place)); + static_assert((uint32_t)markWord::value_type_bit_in_place <= 0x7FFFFFFF, + "value_type_bit_in_place must fit in low 32 bits for z_nilf"); + // Mask value_type bit so CAS fails (-> slow) if object is a value type. + z_nilf(mark, ~((uint32_t)markWord::value_type_bit_in_place)); } z_lgr(locked_obj, mark); // Clear lock-bits from locked_obj (locked state) @@ -7149,8 +7149,8 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_ add2mem_64(Address(offset), DataLayout::counter_increment, r0_tmp); } -// Unimplemented methods for inline types. -int MacroAssembler::store_inline_type_fields_to_buf(ciInlineKlass* vk, bool from_interpreter) { +// Unimplemented methods for value types. +int MacroAssembler::store_value_type_fields_to_buf(ciValueKlass* vk, bool from_interpreter) { Unimplemented(); return 0; } @@ -7159,19 +7159,19 @@ bool MacroAssembler::move_helper(VMReg from, VMReg to, BasicType bt, RegState re Unimplemented(); } -bool MacroAssembler::unpack_inline_helper(const GrowableArray* sig, int& sig_index, +bool MacroAssembler::unpack_value_helper(const GrowableArray* sig, int& sig_index, VMReg from, int& from_index, VMRegPair* to, int to_count, int& to_index, RegState reg_state[]) { Unimplemented(); } -bool MacroAssembler::pack_inline_helper(const GrowableArray* sig, int& sig_index, int vtarg_index, +bool MacroAssembler::pack_value_helper(const GrowableArray* sig, int& sig_index, int vtarg_index, VMRegPair* from, int from_count, int& from_index, VMReg to, RegState reg_state[], Register val_array) { Unimplemented(); } -int MacroAssembler::extend_stack_for_inline_args(int args_on_stack) { +int MacroAssembler::extend_stack_for_value_args(int args_on_stack) { Unimplemented(); } diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.hpp b/src/hotspot/cpu/s390/macroAssembler_s390.hpp index 2b831d1a49cf..faafa21b6de2 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp @@ -30,7 +30,7 @@ #include "asm/assembler.hpp" #include "oops/accessDecorators.hpp" -class ciInlineKlass; +class ciValueKlass; class SigEntry; class VMRegPair; @@ -846,14 +846,14 @@ class MacroAssembler: public Assembler { static bool uses_implicit_null_check(void* address); // markWord tests, kills markWord reg - void test_markword_is_inline_type(Register markword, Label& is_inline_type); + void test_markword_is_value_type(Register markword, Label& is_value_type); - // inlineKlass queries, kills temp_reg - void test_oop_is_not_inline_type(Register object, Register tmp, Label& not_inline_type, bool can_be_null = true); + // ValueKlass queries, kills temp_reg + void test_oop_is_not_value_type(Register object, Register tmp, Label& not_value_type, bool can_be_null = true); - // Valhalla support for inline types - void test_field_is_null_free_inline_type(Register flags, Label& is_null_free); - void test_field_is_not_null_free_inline_type(Register flags, Label& not_null_free_inline_type); + // Valhalla support for value types + void test_field_is_null_free_value_type(Register flags, Label& is_null_free); + void test_field_is_not_null_free_value_type(Register flags, Label& not_null_free_value_type); void test_field_is_flat(Register flags, Label& is_flat); // Klass oop manipulations if compressed. @@ -880,7 +880,7 @@ class MacroAssembler: public Assembler { void test_null_free_array_oop(Register oop, Register temp_reg, Label& is_null_free_array); void test_non_null_free_array_oop(Register oop, Register temp_reg, Label& is_non_null_free_array); void test_flat_array_layout(Register lh, Label& is_flat_array); - void inline_layout_info(Register holder_klass, Register index, Register layout_info); + void value_field_layout_info(Register holder_klass, Register index, Register layout_info); // This function calculates the size of the code generated by // decode_klass_not_null(register dst) @@ -905,11 +905,11 @@ class MacroAssembler: public Assembler { const Address& addr, Register dst, Register tmp1, Register tmp2, Label *is_null = nullptr); - void flat_field_copy(DecoratorSet decorators, Register src, Register dst, Register inline_layout_info); + void flat_field_copy(DecoratorSet decorators, Register src, Register dst, Register value_field_layout_info); - // inline type data payload offsets - void payload_offset(Register inline_klass, Register offset); - void payload_addr(Register oop, Register data, Register inline_klass); + // value type data payload offsets + void payload_offset(Register value_klass, Register offset); + void payload_addr(Register oop, Register data, Register value_klass); public: // tmp1 and tmp2 are used with decorators ON_PHANTOM_OOP_REF or ON_WEAK_OOP_REF. @@ -1159,7 +1159,7 @@ class MacroAssembler: public Assembler { void profile_receiver_type(Register recv, Register mdp, int mdp_offset, Register tmp1); - // Inline type specific methods + // Value type specific methods #include "asm/macroAssembler_common.hpp" }; diff --git a/src/hotspot/cpu/s390/methodHandles_s390.cpp b/src/hotspot/cpu/s390/methodHandles_s390.cpp index 418895bbfb5b..aab0e64dddc1 100644 --- a/src/hotspot/cpu/s390/methodHandles_s390.cpp +++ b/src/hotspot/cpu/s390/methodHandles_s390.cpp @@ -168,7 +168,7 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth __ z_bre(L_no_such_method); ByteSize offset = for_compiler_entry ? - Method::from_compiled_inline_offset() : Method::from_interpreted_offset(); + Method::from_compiled_value_offset() : Method::from_interpreted_offset(); Address method_from(method, offset); __ z_lg(target, method_from); diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index 9600eba394d1..f8e0d35646b1 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -5360,12 +5360,12 @@ instruct castN2X(iRegL dst, iRegN src) %{ ins_pipe(pipe_class_dummy); %} -// Cast Integer to Narrow Pointer for inline types. +// Cast Integer to Narrow Pointer for value types. instruct castI2N(iRegN dst, iRegI src) %{ match(Set dst (CastI2N src)); - size(2); // LR is 2 bytes - format %{ "LR $dst,$src\t # CastI2N" %} - ins_encode %{ __ lr_if_needed($dst$$Register, $src$$Register); %} + size(4); // LLGFR is 4 bytes + format %{ "LLGFR $dst,$src\t # CastI2N" %} + ins_encode %{ __ z_llgfr($dst$$Register, $src$$Register); %} ins_pipe(pipe_class_dummy); %} diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index aad194900450..16ade81a8200 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -775,9 +775,6 @@ void SharedRuntime::restore_native_result(MacroAssembler *masm, int SharedRuntime::java_calling_convention(const BasicType *sig_bt, VMRegPair *regs, int total_args_passed) { - if (UseArrayFlattening) { - fatal("implement function SharedRuntime::java_calling_convention"); - } // c2c calling conventions for compiled-compiled calls. // An int/float occupies 1 slot here. @@ -1011,26 +1008,26 @@ static void patch_callers_callsite(MacroAssembler *masm, int adapter_size, int t __ bind(L); } -// For each inline type argument, sig includes the list of fields of -// the inline type. This utility function computes the number of -// arguments for the call if inline types are passed by reference (the +// For each value type argument, sig includes the list of fields of +// the value type. This utility function computes the number of +// arguments for the call if value types are passed by reference (the // calling convention the interpreter expects). static int compute_total_args_passed_int(const GrowableArray* sig_extended) { int total_args_passed = 0; - if (InlineTypePassFieldsAsArgs) { + if (ValueTypePassFieldsAsArgs) { assert(false, "untested: compute_total_args_passed_int"); for (int i = 0; i < sig_extended->length(); i++) { BasicType bt = sig_extended->at(i)._bt; if (bt == T_METADATA) { - // In sig_extended, an inline type argument starts with: + // In sig_extended, a value type argument starts with: // T_METADATA, followed by the types of the fields of the - // inline type and T_VOID to mark the end of the value - // type. Inline types are flattened so, for instance, in the - // case of an inline type with an int field and an inline type + // value type and T_VOID to mark the end of the value + // type. Value types are flattened so, for instance, in the + // case of a value type with an int field and a value type // field that itself has 2 fields, an int and a long: // T_METADATA T_INT T_METADATA T_INT T_LONG T_VOID (second - // slot for the T_LONG) T_VOID (inner inline type) T_VOID - // (outer inline type) + // slot for the T_LONG) T_VOID (inner value type) T_VOID + // (outer value type) total_args_passed++; int vt = 1; do { @@ -1111,19 +1108,19 @@ static void gen_c2i_adapter(MacroAssembler *masm, __ bind(skip_fixup); // Name some registers to be used in the following code - Register buf_array = Z_R11; // Array of buffered inline types - Register buf_oop = Z_R12; // Buffered inline type oop + Register buf_array = Z_R11; // Array of buffered value types + Register buf_oop = Z_R12; // Buffered value type oop Register tmp1 = Z_R0_scratch; Register tmp2 = Z_R1_scratch; - if (InlineTypePassFieldsAsArgs) { - __ untested("InlineTypePassFieldsAsArgs sharedRuntime"); - // Is there an inline type argument? - bool has_inline_argument = false; - for (int i = 0; i < sig_extended->length() && !has_inline_argument; i++) { - has_inline_argument = (sig_extended->at(i)._bt == T_METADATA); + if (ValueTypePassFieldsAsArgs) { + __ untested("ValueTypePassFieldsAsArgs sharedRuntime"); + // Is there a value type argument? + bool has_value_argument = false; + for (int i = 0; i < sig_extended->length() && !has_value_argument; i++) { + has_value_argument = (sig_extended->at(i)._bt == T_METADATA); } - if (has_inline_argument) { + if (has_value_argument) { // There is at least a value type argument: we're coming from // compiled code so we may not have buffers to back the value // objects. Allocate the buffers here with a runtime call. @@ -1136,7 +1133,7 @@ static void gen_c2i_adapter(MacroAssembler *masm, __ z_lgr(Z_ARG1, Z_thread); __ z_lgr(Z_ARG2, Z_method); __ load_const_optimized(Z_ARG3, (intptr_t)alloc_inline_receiver); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::allocate_inline_types), Z_ARG1, Z_ARG2, Z_ARG3); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::allocate_value_types), Z_ARG1, Z_ARG2, Z_ARG3); // TODO: use blob-relative offset, matching the pattern in the rest of // sharedRuntime_s390.cpp ("offset() - start_off") @@ -1186,7 +1183,7 @@ static void gen_c2i_adapter(MacroAssembler *masm, assert(next_arg_int <= total_args_passed, "more arguments for the interpreter than expected?"); BasicType bt = sig_extended->at(next_arg_comp)._bt; - if (!InlineTypePassFieldsAsArgs || bt != T_METADATA) { + if (!ValueTypePassFieldsAsArgs || bt != T_METADATA) { const VMRegPair reg_pair = regs[next_arg_comp - ignored]; VMReg r_1 = reg_pair.first(); @@ -1249,7 +1246,7 @@ static void gen_c2i_adapter(MacroAssembler *masm, st_off -= wordSize; next_arg_int++; } else { - // Handle inline type arguments + // Handle value type arguments ignored++; next_arg_int++; int vt = 1; @@ -1284,7 +1281,7 @@ static void gen_c2i_adapter(MacroAssembler *masm, } else { int off = sig_extended->at(next_arg_comp)._offset; if (off == -1) { - // Nullable inline type argument + // Nullable value type argument VMReg reg = regs[next_arg_comp - ignored].first(); Label L_notNull; if (reg->is_stack()) { @@ -1394,9 +1391,6 @@ static void gen_special_dispatch(MacroAssembler *masm, vmIntrinsics::ID special_dispatch, const BasicType *sig_bt, const VMRegPair *regs) { - if (UseArrayFlattening) { - __ stop("implement function gen_special_dispatch"); - } verify_oop_args(masm, total_args_passed, sig_bt, regs); // Now write the args into the outgoing interpreter space. @@ -3076,9 +3070,9 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, // Jump to the compiled code just as if compiled code was doing it. // load target address from method: - if (InlineTypePassFieldsAsArgs) { + if (ValueTypePassFieldsAsArgs) { fatal("implement function SharedRuntime::gen_i2c_adapter"); - __ z_lg(Z_R1_scratch, Address(Z_method, Method::from_compiled_inline_offset())); + __ z_lg(Z_R1_scratch, Address(Z_method, Method::from_compiled_value_offset())); } else { __ z_lg(Z_R1_scratch, Address(Z_method, Method::from_compiled_offset())); } @@ -3143,7 +3137,7 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler* masm, // compiled code, which relies solely on SP and not FP, get sick). entry_address[AdapterBlob::C2I_Unverified] = __ pc(); - entry_address[AdapterBlob::C2I_Unverified_Inline] = __ pc(); + entry_address[AdapterBlob::C2I_Unverified_Value] = __ pc(); Label skip_fixup; @@ -3155,10 +3149,10 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler* masm, // Scalarized c2i adapter with non-scalarized receiver (i.e., don't pack receiver) entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr; - entry_address[AdapterBlob::C2I_Inline_RO] = __ pc(); + entry_address[AdapterBlob::C2I_Value_RO] = __ pc(); if (regs_cc != regs_cc_ro) { - __ unimplemented("C2I_Inline_RO"); + __ unimplemented("C2I_Value_RO"); // No class init barrier needed because method is guaranteed to be non-static gen_c2i_adapter(masm, sig_cc_ro, regs_cc_ro, /* requires_clinit_barrier = */ false, entry_address[AdapterBlob::C2I_No_Clinit_Check], skip_fixup, entry_address[AdapterBlob::I2C], oop_maps, frame_complete, frame_size_in_words, /* alloc_inline_receiver = */ false); @@ -3166,22 +3160,22 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler* masm, } // Scalarized c2i adapter - entry_address[AdapterBlob::C2I] = __ pc(); - entry_address[AdapterBlob::C2I_Inline] = __ pc(); + entry_address[AdapterBlob::C2I] = __ pc(); + entry_address[AdapterBlob::C2I_Value] = __ pc(); gen_c2i_adapter(masm, sig_cc, regs_cc, /* requires_clinit_barrier = */ true, entry_address[AdapterBlob::C2I_No_Clinit_Check], skip_fixup, entry_address[AdapterBlob::I2C], oop_maps, frame_complete, frame_size_in_words, /* alloc_inline_receiver = */ true); // Non-scalarized c2i adapter if (regs != regs_cc) { - entry_address[AdapterBlob::C2I_Unverified_Inline] = __ pc(); - Label inline_entry_skip_fixup; - __ unimplemented("C2I_Unverified_Inline"); - gen_inline_cache_check(masm, inline_entry_skip_fixup); + entry_address[AdapterBlob::C2I_Unverified_Value] = __ pc(); + Label value_entry_skip_fixup; + __ unimplemented("C2I_Unverified_Value"); + gen_inline_cache_check(masm, value_entry_skip_fixup); - entry_address[AdapterBlob::C2I_Inline] = __ pc(); - __ unimplemented("C2I_Inline2"); + entry_address[AdapterBlob::C2I_Value] = __ pc(); + __ unimplemented("C2I_Value2"); gen_c2i_adapter(masm, sig, regs, /* requires_clinit_barrier = */ true, entry_address[AdapterBlob::C2I_No_Clinit_Check], - inline_entry_skip_fixup, entry_address[AdapterBlob::I2C], oop_maps, frame_complete, frame_size_in_words, /* alloc_inline_receiver = */ false); + value_entry_skip_fixup, entry_address[AdapterBlob::I2C], oop_maps, frame_complete, frame_size_in_words, /* alloc_inline_receiver = */ false); } // The c2i adapters might safepoint and trigger a GC. The caller must make sure that @@ -4350,13 +4344,13 @@ int SharedRuntime::java_return_convention(const BasicType *sig_bt, VMRegPair *re return int_args + fp_args; } -BufferedInlineTypeBlob* SharedRuntime::generate_buffered_inline_type_adapter(const InlineKlass* vk) { +BufferedValueTypeBlob* SharedRuntime::generate_buffered_value_type_adapter(const ValueKlass* vk) { Unimplemented(); return nullptr; } // Call here from the interpreter or compiled code to store returned -// values to a newly allocated inline type instance. +// values to a newly allocated value type instance. RuntimeStub* SharedRuntime::generate_return_value_stub(address destination) { Unimplemented(); return nullptr; diff --git a/src/hotspot/cpu/s390/stubGenerator_s390.cpp b/src/hotspot/cpu/s390/stubGenerator_s390.cpp index ee0e4004ba6b..ebe04d8afd82 100644 --- a/src/hotspot/cpu/s390/stubGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/stubGenerator_s390.cpp @@ -33,7 +33,7 @@ #include "interpreter/interp_masm.hpp" #include "memory/universe.hpp" #include "nativeInst_s390.hpp" -#include "oops/inlineKlass.hpp" +#include "oops/valueKlass.hpp" #include "oops/instanceOop.hpp" #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" @@ -126,7 +126,7 @@ class StubGenerator: public StubCodeGenerator { StubCodeMark mark(this, stub_id); address start = __ pc(); - if (InlineTypeReturnedAsFields) { + if (ValueTypeReturnedAsFields) { __ stop("fix T_OBJECT"); } diff --git a/src/hotspot/cpu/s390/templateTable_s390.cpp b/src/hotspot/cpu/s390/templateTable_s390.cpp index 556271b6a71f..e9deac670dc2 100644 --- a/src/hotspot/cpu/s390/templateTable_s390.cpp +++ b/src/hotspot/cpu/s390/templateTable_s390.cpp @@ -868,7 +868,22 @@ void TemplateTable::aaload() { __ profile_array_type(/*array=*/Z_tmp_1, Z_tmp_2, Z_ARG2); if (UseArrayFlattening) { - __ stop("implement function TemplateTable::aaload"); + NearLabel is_flat_array, done; + + __ test_flat_array_oop(Z_tmp_1, Z_tmp_2, is_flat_array); + // Non-flat path: normal oop load. + do_oop_load(_masm, Address(Z_tmp_1, index, arrayOopDesc::base_offset_in_bytes(T_OBJECT)), Z_tos, + Z_tmp_2, Z_tmp_3, IS_ARRAY); + __ verify_oop(Z_tos); + __ z_bru(done); + + __ bind(is_flat_array); + // Flat path: delegate to runtime; result returned in Z_tos (= Z_RET). + // Note: index is already shifted, need to pass unshifted index to runtime + __ z_srag(Z_ARG3, index, shift); // Unshift index back to original value + __ call_VM(Z_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::flat_array_load), + Z_tmp_1, Z_ARG3); + __ bind(done); } else { // Now load array element. do_oop_load(_masm, Address(Z_tmp_1, index, arrayOopDesc::base_offset_in_bytes(T_OBJECT)), Z_tos, @@ -1169,30 +1184,45 @@ void TemplateTable::dastore() { } void TemplateTable::aastore() { + // stack: ..., array, index, value + // + // -- Register allocation -------------------------------------------------- + // + // Rvalue Z_tos Z_R2 value oop (stack slot 0) + // Rarray Z_ARG2 Z_R3 array oop (stack slot 2) + // Rindex Z_ARG3 Z_R4 byte-scaled index (live until the LEA below) + // Rstore_addr Z_ARG3 Z_R4 element address (same physical reg; live after LEA) + // Rarray_klass Z_ARG4 Z_R5 array/element klass (written by profiling; always reloaded) + // Rsub_klass Z_ARG5 Z_R6 value klass; free scratch on the null path + // Rscratch Z_tmp_1 Z_R10 shared scratch / tmp1 for barriers + // Rscratch2 Z_tmp_2 Z_R11 shared scratch / tmp2 for barriers + + const Register Rvalue = Z_tos; // Z_R2 + const Register Rarray = Z_ARG2; // Z_R3 + const Register Rindex = Z_ARG3; // Z_R4 (live until LEA) + const Register Rstore_addr = Z_ARG3; // Z_R4 (live after LEA, same register) + const Register Rarray_klass = Z_ARG4; // Z_R5 + const Register Rsub_klass = Z_ARG5; // Z_R6 + const Register Rscratch = Z_tmp_1; // Z_R10 + const Register Rscratch2 = Z_tmp_2; // Z_R11 + NearLabel is_null, is_flat_array, ok_is_subtype, done; transition(vtos, vtos); - // stack: ..., array, index, value - Register Rvalue = Z_tos; - Register Rarray = Z_ARG2; - Register Rindex = Z_ARG3; // Convention for index_check(). - __ load_ptr(0, Rvalue); - __ z_l(Rindex, Address(Z_esp, Interpreter::expr_offset_in_bytes(1))); + __ z_lgf(Rindex, Address(Z_esp, Interpreter::expr_offset_in_bytes(1))); __ load_ptr(2, Rarray); - unsigned const int shift = LogBytesPerHeapOop; - index_check(Rarray, Rindex, shift); // side effect: Rindex = Rindex << shift - Register Rstore_addr = Rindex; - // Address where the store goes to, i.e. &(Rarray[index]) - __ load_address(Rstore_addr, Address(Rarray, Rindex, arrayOopDesc::base_offset_in_bytes(T_OBJECT))); + index_check(Rarray, Rindex, LogBytesPerHeapOop); - Register Rscratch = Z_tmp_1; - Register Rscratch2 = Z_tmp_2; - Register Rarray_klass = Z_ARG4; + // (*) LEA: compute element address in-place. Rindex is dead after this. + __ load_address(Rstore_addr, Address(Rarray, Rindex, arrayOopDesc::base_offset_in_bytes(T_OBJECT))); + // profile_multiple_element_types uses Rarray_klass as tmp3 scratch - it clobbers it. __ profile_array_type(Rarray, Rscratch, Rscratch2); - __ profile_multiple_element_types(Z_tos, Rscratch, Rscratch2, Rarray_klass); + __ profile_multiple_element_types(Rvalue, Rscratch, Rscratch2, Rarray_klass); + + __ compareU64_and_branch(Rvalue, (intptr_t)0, Assembler::bcondEqual, is_null); if (UseArrayFlattening) { __ load_klass(Rarray_klass, Rarray); @@ -1200,76 +1230,66 @@ void TemplateTable::aastore() { __ test_flat_array_layout(Rscratch, is_flat_array); } - // do array store check - check for null value first. - __ compareU64_and_branch(Rvalue, (intptr_t)0, Assembler::bcondEqual, is_null); - - // Rindex is dead after this point - Register Rscratch3 = Rindex; - - if (!UseArrayFlattening) { - __ load_klass(Rarray_klass, Rarray); // haven't done this above - } - - Register Rsub_klass = Z_ARG5; - Register Rsuper_klass = Rarray_klass; // Reuse Rarray_klass for superklass - + // Rarray_klass was clobbered by profiling; reload it unconditionally + // (also handles the !UseArrayFlattening path where it was never loaded). + __ load_klass(Rarray_klass, Rarray); __ load_klass(Rsub_klass, Rvalue); - // Load array element superklass into Rsuper_klass (which is Rarray_klass) - __ z_lg(Rsuper_klass, Address(Rsuper_klass, ObjArrayKlass::element_klass_offset())); - - // Generate a fast subtype check. Branch to ok_is_subtype if no failure. - // Throw if failure. - Register tmp1 = Z_tmp_1; - Register tmp2 = Z_tmp_2; - __ gen_subtype_check(Rsub_klass, Rsuper_klass, tmp1, tmp2, ok_is_subtype, false); - - // Fall through on failure. - // Object is in Rvalue == Z_tos. - assert(Rvalue == Z_tos, "that's the expected location"); - __ load_absolute_address(tmp1, Interpreter::_throw_ArrayStoreException_entry); - __ z_br(tmp1); + __ z_lg(Rarray_klass, Address(Rarray_klass, ObjArrayKlass::element_klass_offset())); + __ gen_subtype_check(Rsub_klass, Rarray_klass, Rscratch, Rscratch2, ok_is_subtype, false); - if (UseArrayFlattening) { - __ bind(is_flat_array); // Store non-null value to flat - __ load_ptr(0, Rvalue); // value - __ z_l(Rindex, Address(Z_esp, Interpreter::expr_offset_in_bytes(1))); // index - __ load_ptr(2, Rarray); // array - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::flat_array_store), Rvalue, Rarray, Rindex); - __ z_bru(done); - } + // Fall through on subtype-check failure. + assert(Rvalue == Z_tos, "must be"); + __ load_absolute_address(Rscratch, Interpreter::_throw_ArrayStoreException_entry); + __ z_br(Rscratch); + // Null path __ bind(is_null); - NearLabel is_null_into_value_array_npe; if (Arguments::is_valhalla_enabled()) { - // No way to store null in a null-free array - __ test_null_free_array_oop(Rarray, Rscratch, is_null_into_value_array_npe); + // A nullable flat array (NULLABLE_ATOMIC_FLAT) is flat but not null-free: + // storing null must go through flat_array_store to write the null marker + // into the payload. Route all flat arrays there first, before the + // null-free check below. + if (UseArrayFlattening) { + __ load_klass(Rarray_klass, Rarray); + __ z_l(Rscratch, Address(Rarray_klass, Klass::layout_helper_offset())); + __ test_flat_array_layout(Rscratch, is_flat_array); + } + // Non-flat null-free array: throw NullPointerException. + // test_non_null_free_array_oop branches to store_null when NOT null-free; + // falls through when null-free -> NPE. + NearLabel store_null; + __ test_non_null_free_array_oop(Rarray, Rscratch, store_null); + __ load_absolute_address(Rscratch, Interpreter::_throw_NullPointerException_entry); + __ z_br(Rscratch); + __ bind(store_null); } - - // Store a null - Register tmp3 = Rsub_klass; + // Rsub_klass (Z_R6) is free scratch - value is null so its klass was never loaded. do_oop_store(_masm, Address(Rstore_addr, (intptr_t)0), noreg, - tmp3, tmp2, tmp1, IS_ARRAY); + Rsub_klass, Rscratch2, Rscratch, IS_ARRAY); __ z_bru(done); - if (Arguments::is_valhalla_enabled()) { - __ bind(is_null_into_value_array_npe); - __ load_absolute_address(tmp1, Interpreter::_throw_NullPointerException_entry); - __ z_br(tmp1); - } - - // Come here on success. + // Subtype-check success path __ bind(ok_is_subtype); - - // Now store using the appropriate barrier. + // Rvalue (Z_R2) and Rstore_addr (Z_R4) survived gen_subtype_check intact. do_oop_store(_masm, Address(Rstore_addr, (intptr_t)0), Rvalue, - tmp3, tmp2, tmp1, IS_ARRAY | IS_NOT_NULL); + Rsub_klass, Rscratch2, Rscratch, IS_ARRAY | IS_NOT_NULL); + __ z_bru(done); + + // Flat-array path (non-null and null into nullable flat) + if (UseArrayFlattening) { + __ bind(is_flat_array); + __ load_ptr(0, Rvalue); + __ load_ptr(2, Rscratch); // array + __ z_lgf(Rscratch2, Address(Z_esp, Interpreter::expr_offset_in_bytes(1))); // raw index (int) + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::flat_array_store), + Rvalue, Rscratch, Rscratch2); + // fall through to done + } - // Pop stack arguments. __ bind(done); __ add2reg(Z_esp, 3 * Interpreter::stackElementSize); } - void TemplateTable::bastore() { transition(itos, vtos); @@ -2107,10 +2127,10 @@ void TemplateTable::if_acmp(Condition cc) { __ z_ltgr(Z_ARG5, Z_ARG5); __ z_brc(Assembler::bcondEqual, (cc == equal) ? not_taken : taken); - __ z_llill(Z_ARG3, markWord::inline_type_pattern); + __ z_llill(Z_ARG3, markWord::value_type_pattern); __ z_ng(Z_ARG3, Address(Z_tos, oopDesc::mark_offset_in_bytes())); __ z_ng(Z_ARG3, Address(Z_ARG5, oopDesc::mark_offset_in_bytes())); - __ z_chi(Z_ARG3, markWord::inline_type_pattern); + __ z_chi(Z_ARG3, markWord::value_type_pattern); __ branch_optimized(Assembler::bcondNotEqual, (cc == equal) ? not_taken : taken); __ load_metadata(Z_ARG3, Z_tos); @@ -3322,7 +3342,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr __ pop(atos); if (is_static) { Label is_nullable; - __ z_tmll(flags, 1 << ResolvedFieldEntry::is_null_free_inline_type_shift); + __ z_tmll(flags, 1 << ResolvedFieldEntry::is_null_free_value_type_shift); __ branch_optimized(Assembler::bcondAllZero, is_nullable); __ null_check(Z_tos); // FIXME JDK-8341120 __ bind(is_nullable); @@ -3333,7 +3353,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr Label null_free_reference, is_flat, rewrite_inline, done_valhalla; __ z_tmll(flags, 1 << ResolvedFieldEntry::is_flat_shift); __ branch_optimized(Assembler::bcondAllOne, is_flat); - __ z_tmll(flags, 1 << ResolvedFieldEntry::is_null_free_inline_type_shift); + __ z_tmll(flags, 1 << ResolvedFieldEntry::is_null_free_value_type_shift); __ branch_optimized(Assembler::bcondAllOne, null_free_reference); pop_and_check_object(obj); __ z_agr(fieldAddr, obj); @@ -3344,7 +3364,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr patch_bytecode(Bytecodes::_fast_aputfield, bc_reg, patch_tmp, true, byte_no); } __ z_bru(done_valhalla); - // Implementation of the inline type semantic + // Implementation of the value type semantic __ bind(null_free_reference); __ null_check(Z_tos); // FIXME JDK-8341120 pop_and_check_object(obj); @@ -4489,10 +4509,10 @@ void TemplateTable::monitorenter() { // Check for null object. __ null_check(Z_tos); - // Check for inline type (Valhalla feature) - NearLabel is_inline_type; + // Check for value type (Valhalla feature) + NearLabel is_value_type; __ z_lg(Z_R1_scratch, Address(Z_tos, oopDesc::mark_offset_in_bytes())); - __ test_markword_is_inline_type(Z_R1_scratch, is_inline_type); + __ test_markword_is_value_type(Z_R1_scratch, is_value_type); const int entry_size = frame::interpreter_frame_monitor_size_in_bytes(); NearLabel allocated; // Initialize entry pointer. @@ -4571,8 +4591,8 @@ void TemplateTable::monitorenter() { // next instruction. __ dispatch_next(vtos); - // Handle inline type exception (Valhalla feature) - __ bind(is_inline_type); + // Handle value type exception (Valhalla feature) + __ bind(is_value_type); __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_identity_exception), Z_tos); __ should_not_reach_here(); @@ -4589,12 +4609,12 @@ void TemplateTable::monitorexit() { // Check for null object. __ null_check(Z_tos); - // Check for inline type (Valhalla feature) - NearLabel is_inline_type, has_identity; + // Check for value type (Valhalla feature) + NearLabel is_value_type, has_identity; __ z_lg(Z_R1_scratch, Address(Z_tos, oopDesc::mark_offset_in_bytes())); - __ test_markword_is_inline_type(Z_R1_scratch, is_inline_type); + __ test_markword_is_value_type(Z_R1_scratch, is_value_type); __ z_bru(has_identity); - __ bind(is_inline_type); + __ bind(is_value_type); __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception)); __ should_not_reach_here(); diff --git a/src/hotspot/cpu/s390/vm_version_s390.cpp b/src/hotspot/cpu/s390/vm_version_s390.cpp index eb0a5a63223e..e0e0b2a1d54f 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.cpp +++ b/src/hotspot/cpu/s390/vm_version_s390.cpp @@ -329,32 +329,13 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseUnalignedAccesses, true); } - if (InlineTypePassFieldsAsArgs) { - warning("InlineTypePassFieldsAsArgs not supported on this CPU."); - FLAG_SET_DEFAULT(InlineTypePassFieldsAsArgs, false); + if (ValueTypePassFieldsAsArgs) { + warning("ValueTypePassFieldsAsArgs not supported on this CPU."); + FLAG_SET_DEFAULT(ValueTypePassFieldsAsArgs, false); } - if (InlineTypeReturnedAsFields) { - warning("InlineTypeReturnedAsFields not supported on this CPU."); - FLAG_SET_DEFAULT(InlineTypeReturnedAsFields, false); - } - // TODO: Valhalla optimizations - if (UseArrayFlattening) { - FLAG_SET_DEFAULT(UseArrayFlattening, false); - } - if (UseFieldFlattening) { - FLAG_SET_DEFAULT(UseFieldFlattening, false); - } - if (UseNullFreeNonAtomicValueFlattening) { - FLAG_SET_DEFAULT(UseNullFreeNonAtomicValueFlattening, false); - } - if (UseNullableAtomicValueFlattening) { - FLAG_SET_DEFAULT(UseNullableAtomicValueFlattening, false); - } - if (UseNullFreeAtomicValueFlattening) { - FLAG_SET_DEFAULT(UseNullFreeAtomicValueFlattening, false); - } - if (UseNullableNonAtomicValueFlattening) { - FLAG_SET_DEFAULT(UseNullableNonAtomicValueFlattening, false); + if (ValueTypeReturnedAsFields) { + warning("ValueTypeReturnedAsFields not supported on this CPU."); + FLAG_SET_DEFAULT(ValueTypeReturnedAsFields, false); } } diff --git a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp index d0b23777ae91..76889c169684 100644 --- a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp +++ b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp @@ -272,7 +272,7 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); if (_throw_ie_stub != nullptr) { // When we come here, _obj_reg has already been checked to be non-null. - const int is_value_mask = markWord::inline_type_pattern; + const int is_value_mask = markWord::value_type_pattern; Register mark = _scratch_reg->as_register(); __ movptr(mark, Address(_obj_reg->as_register(), oopDesc::mark_offset_in_bytes())); __ andptr(mark, is_value_mask); diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index 23a457913e5a..96300e612089 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -31,16 +31,16 @@ #include "c1/c1_Runtime1.hpp" #include "c1/c1_ValueStack.hpp" #include "ci/ciArrayKlass.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciInstance.hpp" #include "ci/ciObjArrayKlass.hpp" +#include "ci/ciValueKlass.hpp" #include "code/aotCodeCache.hpp" #include "compiler/oopMap.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/gc_globals.hpp" #include "nativeInst_x86.hpp" -#include "oops/oop.inline.hpp" #include "oops/objArrayKlass.hpp" +#include "oops/oop.inline.hpp" #include "runtime/frame.inline.hpp" #include "runtime/safepointMechanism.hpp" #include "runtime/sharedRuntime.hpp" @@ -471,14 +471,14 @@ void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) { if (!result->is_illegal() && result->is_float_kind() && !result->is_xmm_register()) { assert(result->fpu() == 0, "result must already be on TOS"); } - if (InlineTypeReturnedAsFields) { + if (ValueTypeReturnedAsFields) { #ifndef _LP64 Unimplemented(); #endif - // Check if we are returning a non-null inline type and load its fields into registers + // Check if we are returning a non-null value type and load its fields into registers ciType* return_type = compilation()->method()->return_type(); - if (return_type->is_inlinetype()) { - ciInlineKlass* vk = return_type->as_inline_klass(); + if (return_type->is_value_klass()) { + ciValueKlass* vk = return_type->as_value_klass(); if (vk->can_be_returned_as_fields()) { address unpack_handler = vk->unpack_handler(); assert(unpack_handler != nullptr, "must be"); @@ -498,14 +498,14 @@ void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) { __ jmp(skip); __ bind(not_null); - // Check if we are returning a non-null inline type and load its fields into registers - __ test_oop_is_not_inline_type(rax, rscratch1, skip, /* can_be_null= */ false); + // Check if we are returning a non-null value type and load its fields into registers + __ test_oop_is_not_value_type(rax, rscratch1, skip, /* can_be_null= */ false); - // Load fields from a buffered value with an inline class specific handler + // Load fields from a buffered value with a value class specific handler __ load_klass(rdi, rax, rscratch1); - __ movptr(rdi, Address(rdi, InlineKlass::adr_members_offset())); - __ movptr(rdi, Address(rdi, InlineKlass::unpack_handler_offset())); - // Unpack handler can be null if inline type is not scalarizable in returns + __ movptr(rdi, Address(rdi, ValueKlass::adr_members_offset())); + __ movptr(rdi, Address(rdi, ValueKlass::unpack_handler_offset())); + // Unpack handler can be null if value type is not scalarizable in returns __ testptr(rdi, rdi); __ jcc(Assembler::zero, skip); __ call(rdi); @@ -533,8 +533,8 @@ void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) { } -int LIR_Assembler::store_inline_type_fields_to_buf(ciInlineKlass* vk) { - return (__ store_inline_type_fields_to_buf(vk, false)); +int LIR_Assembler::store_value_type_fields_to_buf(ciValueKlass* vk) { + return (__ store_value_type_fields_to_buf(vk, false)); } int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) { @@ -1373,12 +1373,16 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L assert_different_registers(obj, k_RInfo, klass_RInfo); + Register mdo = noreg; + if (op->should_profile()) { + mdo = klass_RInfo; + __ mov_metadata(mdo, md->constant_encoding()); + } + if (op->need_null_check()) { __ testptr(obj, obj); if (op->should_profile()) { Label not_null; - Register mdo = klass_RInfo; - __ mov_metadata(mdo, md->constant_encoding()); __ jccb(Assembler::notEqual, not_null); // Object is null; update MDO and exit Address data_addr(mdo, md->byte_offset_of_slot(data, DataLayout::flags_offset())); @@ -1386,13 +1390,15 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L __ orb(data_addr, header_bits); __ jmp(*obj_is_null); __ bind(not_null); + } else { + __ jcc(Assembler::equal, *obj_is_null); + } + } + if (op->should_profile()) { Register recv = k_RInfo; __ load_klass(recv, obj, tmp_load_klass); type_profile_helper(mdo, md, data, recv); - } else { - __ jcc(Assembler::equal, *obj_is_null); - } } if (!k->is_loaded()) { @@ -1601,22 +1607,22 @@ void LIR_Assembler::emit_opSubstitutabilityCheck(LIR_OpSubstitutabilityCheck* op ciKlass* left_klass = op->left_klass(); ciKlass* right_klass = op->right_klass(); - // (2) Inline type check -- if either of the operands is not an inline type, + // (2) Value type check -- if either of the operands is not a value type, // they are not substitutable. We do this only if we are not sure that the - // operands are inline type + // operands are value type if ((left_klass == nullptr || right_klass == nullptr) ||// The klass is still unloaded, or came from a Phi node. - !left_klass->is_inlinetype() || !right_klass->is_inlinetype()) { + !left_klass->is_value_klass() || !right_klass->is_value_klass()) { Register tmp = op->tmp1()->as_register(); - __ movptr(tmp, (intptr_t)markWord::inline_type_pattern); + __ movptr(tmp, (intptr_t)markWord::value_type_pattern); __ andptr(tmp, Address(left, oopDesc::mark_offset_in_bytes())); __ andptr(tmp, Address(right, oopDesc::mark_offset_in_bytes())); - __ cmpptr(tmp, (intptr_t)markWord::inline_type_pattern); + __ cmpptr(tmp, (intptr_t)markWord::value_type_pattern); __ jcc(Assembler::notEqual, L_oops_not_equal); } // (3) Same klass check: if the operands are of different klasses, they are not substitutable. - if (left_klass != nullptr && left_klass->is_inlinetype() && left_klass == right_klass) { - // No need to load klass -- the operands are statically known to be the same inline klass. + if (left_klass != nullptr && left_klass->is_value_klass() && left_klass == right_klass) { + // No need to load klass -- the operands are statically known to be the same value klass. __ jmp(*op->stub()->entry()); } else { Register tmp1 = op->tmp1()->as_register(); @@ -2486,7 +2492,7 @@ void LIR_Assembler::store_parameter(Metadata* m, int offset_from_rsp_in_words) { } -void LIR_Assembler::arraycopy_inlinetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check) { +void LIR_Assembler::arraycopy_valuetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check) { if (null_check) { __ testptr(obj, obj); __ jcc(Assembler::zero, *slow_path->entry()); @@ -2601,12 +2607,12 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { return; } - // Handle inline type arrays - if (flags & LIR_OpArrayCopy::src_inlinetype_check) { - arraycopy_inlinetype_check(src, tmp, stub, false, (flags & LIR_OpArrayCopy::src_null_check)); + // Handle value type arrays + if (flags & LIR_OpArrayCopy::src_valuetype_check) { + arraycopy_valuetype_check(src, tmp, stub, false, (flags & LIR_OpArrayCopy::src_null_check)); } - if (flags & LIR_OpArrayCopy::dst_inlinetype_check) { - arraycopy_inlinetype_check(dst, tmp, stub, true, (flags & LIR_OpArrayCopy::dst_null_check)); + if (flags & LIR_OpArrayCopy::dst_valuetype_check) { + arraycopy_valuetype_check(dst, tmp, stub, true, (flags & LIR_OpArrayCopy::dst_null_check)); } assert(default_type != nullptr && default_type->is_array_klass() && default_type->is_loaded(), "must be true at this point"); @@ -3145,24 +3151,24 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { __ bind(next); } -void LIR_Assembler::emit_profile_inline_type(LIR_OpProfileInlineType* op) { +void LIR_Assembler::emit_profile_value_type(LIR_OpProfileValueType* op) { Register obj = op->obj()->as_register(); Register tmp = op->tmp()->as_pointer_register(); Address mdo_addr = as_Address(op->mdp()->as_address_ptr()); bool not_null = op->not_null(); int flag = op->flag(); - Label not_inline_type; + Label not_value_type; if (!not_null) { __ testptr(obj, obj); - __ jccb(Assembler::zero, not_inline_type); + __ jccb(Assembler::zero, not_value_type); } - __ test_oop_is_not_inline_type(obj, tmp, not_inline_type); + __ test_oop_is_not_value_type(obj, tmp, not_value_type); __ orb(mdo_addr, flag); - __ bind(not_inline_type); + __ bind(not_value_type); } diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp index ed9105fabc00..ef697d6a258e 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp @@ -51,7 +51,7 @@ _deopt_handler_size = 7 }; - void arraycopy_inlinetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check); + void arraycopy_valuetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check); void move(LIR_Opr src, LIR_Opr dst); public: diff --git a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp index 2642372bc373..cb0a73e62f6e 100644 --- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp @@ -30,9 +30,9 @@ #include "c1/c1_Runtime1.hpp" #include "c1/c1_ValueStack.hpp" #include "ci/ciArray.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciObjArrayKlass.hpp" #include "ci/ciTypeArrayKlass.hpp" +#include "ci/ciValueKlass.hpp" #include "gc/shared/c1/barrierSetC1.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" @@ -288,7 +288,7 @@ void LIRGenerator::do_MonitorEnter(MonitorEnter* x) { info_for_exception = state_for(x); } - CodeStub* throw_ie_stub = x->maybe_inlinetype() ? + CodeStub* throw_ie_stub = x->maybe_valuetype() ? new SimpleExceptionStub(StubId::c1_throw_identity_exception_id, obj.result(), state_for(x)) : nullptr; @@ -1138,7 +1138,7 @@ void LIRGenerator::do_NewInstance(NewInstance* x) { CodeEmitInfo* info = state_for(x, x->needs_state_before() ? x->state_before() : x->state()); LIR_Opr reg = result_register_for(x->type()); new_instance(reg, x->klass(), x->is_unresolved(), - !x->is_unresolved() && x->klass()->is_inlinetype(), + !x->is_unresolved() && x->klass()->is_value_klass(), FrameMap::rcx_oop_opr, FrameMap::rdi_oop_opr, FrameMap::rsi_oop_opr, diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp index 4332e8a957d7..777e9587918b 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp @@ -246,7 +246,7 @@ void C1_MacroAssembler::build_frame_helper(int frame_size_in_bytes, int sp_offse void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, bool has_scalarized_args, - Label* verified_inline_entry_label) { + Label* verified_value_entry_label) { // Make sure there is enough stack space for this method's activation. // Note that we do this before doing an enter(). This matches the // ordering of C2's stack overflow check / rsp decrement and allows @@ -261,9 +261,9 @@ void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_by // C1 code is not hot enough to micro optimize the nmethod entry barrier with an out-of-line stub bs->nmethod_entry_barrier(this, nullptr /* slow_path */, nullptr /* continuation */); - if (verified_inline_entry_label != nullptr) { + if (verified_value_entry_label != nullptr) { // Jump here from the scalarized entry points that already created the frame. - bind(*verified_inline_entry_label); + bind(*verified_value_entry_label); } } @@ -273,20 +273,20 @@ void C1_MacroAssembler::verified_entry(bool breakAtEntry) { // build frame } -int C1_MacroAssembler::scalarized_entry(const CompiledEntrySignature* ces, int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, Label& verified_inline_entry_label, bool is_inline_ro_entry) { - assert(InlineTypePassFieldsAsArgs, "sanity"); +int C1_MacroAssembler::scalarized_entry(const CompiledEntrySignature* ces, int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, Label& verified_value_entry_label, bool is_value_ro_entry) { + assert(ValueTypePassFieldsAsArgs, "sanity"); // Make sure there is enough stack space for this method's activation. assert(bang_size_in_bytes >= frame_size_in_bytes, "stack bang size incorrect"); generate_stack_overflow_check(bang_size_in_bytes); GrowableArray* sig = ces->sig(); - GrowableArray* sig_cc = is_inline_ro_entry ? ces->sig_cc_ro() : ces->sig_cc(); + GrowableArray* sig_cc = is_value_ro_entry ? ces->sig_cc_ro() : ces->sig_cc(); VMRegPair* regs = ces->regs(); - VMRegPair* regs_cc = is_inline_ro_entry ? ces->regs_cc_ro() : ces->regs_cc(); + VMRegPair* regs_cc = is_value_ro_entry ? ces->regs_cc_ro() : ces->regs_cc(); int args_on_stack = ces->args_on_stack(); - int args_on_stack_cc = is_inline_ro_entry ? ces->args_on_stack_cc_ro() : ces->args_on_stack_cc(); + int args_on_stack_cc = is_value_ro_entry ? ces->args_on_stack_cc_ro() : ces->args_on_stack_cc(); - assert(sig->length() <= sig_cc->length(), "Zero-sized inline class not allowed!"); + assert(sig->length() <= sig_cc->length(), "Zero-sized value class not allowed!"); BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, sig_cc->length()); int args_passed = sig->length(); int args_passed_cc = SigEntry::fill_sig_bt(sig_cc, sig_bt); @@ -300,10 +300,10 @@ int C1_MacroAssembler::scalarized_entry(const CompiledEntrySignature* ces, int f bs->nmethod_entry_barrier(this, nullptr /* slow_path */, nullptr /* continuation */); movptr(rbx, (intptr_t)(ces->method())); - if (is_inline_ro_entry) { - call(RuntimeAddress(Runtime1::entry_for(StubId::c1_buffer_inline_args_no_receiver_id))); + if (is_value_ro_entry) { + call(RuntimeAddress(Runtime1::entry_for(StubId::c1_buffer_value_args_no_receiver_id))); } else { - call(RuntimeAddress(Runtime1::entry_for(StubId::c1_buffer_inline_args_id))); + call(RuntimeAddress(Runtime1::entry_for(StubId::c1_buffer_value_args_id))); } int rt_call_offset = offset(); @@ -313,16 +313,16 @@ int C1_MacroAssembler::scalarized_entry(const CompiledEntrySignature* ces, int f assert(args_on_stack <= args_on_stack_cc, "Sanity check"); - shuffle_inline_args(true, is_inline_ro_entry, sig_cc, - args_passed_cc, args_on_stack_cc, regs_cc, // from - args_passed, args_on_stack, regs, // to - 0, rax); + shuffle_value_args(true, is_value_ro_entry, sig_cc, + args_passed_cc, args_on_stack_cc, regs_cc, // from + args_passed, args_on_stack, regs, // to + 0, rax); // Create the real frame. Below jump will then skip over the stack banging and frame - // setup code in the verified_inline_entry (which has a different real_frame_size). + // setup code in the verified_value_entry (which has a different real_frame_size). build_frame_helper(frame_size_in_bytes, sp_offset_for_orig_pc, false); - jmp(verified_inline_entry_label); + jmp(verified_value_entry_label); return rt_call_offset; } diff --git a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp index ecb997e878ac..a1459a34f52e 100644 --- a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp +++ b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp @@ -913,14 +913,14 @@ OopMapSet* Runtime1::generate_code_for(StubId id, StubAssembler* sasm) { __ jcc(Assembler::equal, ok); __ cmpl(t0, Klass::_lh_array_tag_flat_value); // new "[LVT;" __ jcc(Assembler::equal, ok); - __ stop("assert(is an object or inline type array klass)"); + __ stop("assert(is an object or value type array klass)"); break; case StubId::c1_new_null_free_array_id: __ cmpl(t0, Klass::_lh_array_tag_flat_value); // the array can be a flat array. __ jcc(Assembler::equal, ok); __ cmpl(t0, (Klass::_lh_array_tag_ref_value)); // the array cannot be a flat array (due to InlineArrayElementMaxFlatSize, etc) __ jcc(Assembler::equal, ok); - __ stop("assert(is an object or inline type array klass)"); + __ stop("assert(is an object or value type array klass)"); break; default: ShouldNotReachHere(); } @@ -1028,17 +1028,17 @@ OopMapSet* Runtime1::generate_code_for(StubId id, StubAssembler* sasm) { break; - case StubId::c1_buffer_inline_args_id: - case StubId::c1_buffer_inline_args_no_receiver_id: + case StubId::c1_buffer_value_args_id: + case StubId::c1_buffer_value_args_no_receiver_id: { - const char* name = (id == StubId::c1_buffer_inline_args_id) ? - "buffer_inline_args" : "buffer_inline_args_no_receiver"; + const char* name = (id == StubId::c1_buffer_value_args_id) ? + "buffer_value_args" : "buffer_value_args_no_receiver"; StubFrame f(sasm, name, dont_gc_arguments); OopMap* map = save_live_registers(sasm, 2); Register method = rbx; - address entry = (id == StubId::c1_buffer_inline_args_id) ? - CAST_FROM_FN_PTR(address, buffer_inline_args) : - CAST_FROM_FN_PTR(address, buffer_inline_args_no_receiver); + address entry = (id == StubId::c1_buffer_value_args_id) ? + CAST_FROM_FN_PTR(address, buffer_value_args) : + CAST_FROM_FN_PTR(address, buffer_value_args_no_receiver); int call_offset = __ call_RT(rax, noreg, entry, method); oop_maps = new OopMapSet(); oop_maps->add_gc_map(call_offset, map); diff --git a/src/hotspot/cpu/x86/c2_stubGenerator_x86_64_string.cpp b/src/hotspot/cpu/x86/c2_stubGenerator_x86_64_string.cpp index 6585b60f8a0b..b022d4dadf5b 100644 --- a/src/hotspot/cpu/x86/c2_stubGenerator_x86_64_string.cpp +++ b/src/hotspot/cpu/x86/c2_stubGenerator_x86_64_string.cpp @@ -211,7 +211,7 @@ static void generate_string_indexof_stubs(StubGenerator *stubgen, address *fnptr // Addresses of the two jump tables used for small needle processing address *big_jump_table = StubRoutines::x86::big_jump_table_base(ae); - address *small_jump_table = StubRoutines::x86::big_jump_table_base(ae); + address *small_jump_table = StubRoutines::x86::small_jump_table_base(ae); // If the stub has been cached we can retrieve the stub entry. The // target addresses we need to install into the jump tables will diff --git a/src/hotspot/cpu/x86/frame_x86.cpp b/src/hotspot/cpu/x86/frame_x86.cpp index d7ebd9c1a91a..a13f0b44c3e1 100644 --- a/src/hotspot/cpu/x86/frame_x86.cpp +++ b/src/hotspot/cpu/x86/frame_x86.cpp @@ -151,7 +151,7 @@ bool frame::safe_for_sender(JavaThread *thread) { intptr_t** saved_fp_addr = (intptr_t**) (sender_sp - frame::sender_sp_offset); saved_fp = *saved_fp_addr; - // Repair the sender sp if this is a method with scalarized inline type args + // Repair the sender sp if this is a method with scalarized value type args sender_sp = repair_sender_sp(sender_sp, saved_fp_addr); sender_unextended_sp = sender_sp; } diff --git a/src/hotspot/cpu/x86/frame_x86.hpp b/src/hotspot/cpu/x86/frame_x86.hpp index 425469ea10a1..b6e2acd715c1 100644 --- a/src/hotspot/cpu/x86/frame_x86.hpp +++ b/src/hotspot/cpu/x86/frame_x86.hpp @@ -137,7 +137,7 @@ } public: - // Support for scalarized inline type calling convention + // Support for scalarized value type calling convention ALWAYSINLINE intptr_t* repair_sender_sp(intptr_t* sender_sp, intptr_t** saved_fp_addr) const; struct CompiledFramePointers { intptr_t* sender_sp; // The top of the stack of the sender diff --git a/src/hotspot/cpu/x86/frame_x86.inline.hpp b/src/hotspot/cpu/x86/frame_x86.inline.hpp index f6596236532d..e29c75b679e0 100644 --- a/src/hotspot/cpu/x86/frame_x86.inline.hpp +++ b/src/hotspot/cpu/x86/frame_x86.inline.hpp @@ -428,7 +428,7 @@ ALWAYSINLINE frame frame::sender_raw(RegisterMap* map) const { return frame(sender_sp(), link(), sender_pc()); } -// Check for a method with scalarized inline type arguments that needs +// Check for a method with scalarized value type arguments that needs // a stack repair and return the repaired sender stack pointer. ALWAYSINLINE intptr_t* frame::repair_sender_sp(intptr_t* sender_sp, intptr_t** saved_fp_addr) const { nmethod* nm = _cb->as_nmethod_or_null(); @@ -475,16 +475,16 @@ ALWAYSINLINE frame frame::sender_for_compiled_frame(RegisterMap* map) const { #ifdef COMPILER1 nmethod* nm = _cb->as_nmethod_or_null(); if (nm != nullptr && nm->is_compiled_by_c1() && nm->method()->has_scalarized_args() && - pc() < nm->verified_inline_entry_point()) { - // The VEP and VIEP(RO) of C1-compiled methods call buffer_inline_args_xxx + pc() < nm->verified_value_entry_point()) { + // The VEP and VIEP(RO) of C1-compiled methods call buffer_value_args_xxx // before doing any argument shuffling, so we need to scan the oops // as the caller passes them. c1_buffering = true; #ifdef ASSERT NativeCall* call = nativeCall_before(pc()); address dest = call->destination(); - assert(dest == Runtime1::entry_for(StubId::c1_buffer_inline_args_no_receiver_id) || - dest == Runtime1::entry_for(StubId::c1_buffer_inline_args_id), "unexpected safepoint in entry point"); + assert(dest == Runtime1::entry_for(StubId::c1_buffer_value_args_no_receiver_id) || + dest == Runtime1::entry_for(StubId::c1_buffer_value_args_id), "unexpected safepoint in entry point"); #endif } #endif diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp index eb0ce3141559..fdae86bf7de5 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp @@ -165,15 +165,15 @@ void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators } void BarrierSetAssembler::flat_field_copy(MacroAssembler* masm, DecoratorSet decorators, - Register src, Register dst, Register inline_layout_info) { + Register src, Register dst, Register value_field_layout_info) { // flat_field_copy implementation is fairly complex, and there are not any // "short-cuts" to be made from asm. What there is, appears to have the same // cost in C++, so just "call_VM_leaf" for now rather than maintain hundreds // of hand-rolled instructions... if (decorators & IS_DEST_UNINITIALIZED) { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetRuntime::value_copy_is_dest_uninitialized), src, dst, inline_layout_info); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetRuntime::value_copy_is_dest_uninitialized), src, dst, value_field_layout_info); } else { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetRuntime::value_copy), src, dst, inline_layout_info); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetRuntime::value_copy), src, dst, value_field_layout_info); } } diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp index 7f7f65992b3d..5879c74963bd 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp @@ -49,7 +49,7 @@ class BarrierSetAssembler: public CHeapObj { Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); virtual void flat_field_copy(MacroAssembler* masm, DecoratorSet decorators, - Register src, Register dst, Register inline_layout_info); + Register src, Register dst, Register value_field_layout_info); // The copy_[load/store]_at functions are used by arraycopy stubs. Be careful to only use // r10 (aka rscratch1) in a context where restore_arg_regs_using_thread has been used instead diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp b/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp index 6dd4e02dbab2..46750b7f0c43 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp @@ -176,9 +176,9 @@ static void set_immediate(nmethod* nm, jint val, int bit_mask) { if (!nm->is_osr_method() && nm->method()->has_scalarized_args()) { // nmethods with scalarized arguments have multiple entry points that each have an own nmethod entry barrier - assert(nm->verified_entry_point() != nm->verified_inline_entry_point(), "scalarized entry point not found"); - address method_body = nm->is_compiled_by_c1() ? nm->verified_inline_entry_point() : nm->verified_entry_point(); - address entry_point2 = nm->is_compiled_by_c1() ? nm->verified_entry_point() : nm->verified_inline_entry_point(); + assert(nm->verified_entry_point() != nm->verified_value_entry_point(), "scalarized entry point not found"); + address method_body = nm->is_compiled_by_c1() ? nm->verified_value_entry_point() : nm->verified_entry_point(); + address entry_point2 = nm->is_compiled_by_c1() ? nm->verified_entry_point() : nm->verified_value_entry_point(); int barrier_offset = reinterpret_cast
(cmp1) - method_body; NativeNMethodCmpBarrier* cmp2 = reinterpret_cast(entry_point2 + barrier_offset); @@ -186,8 +186,8 @@ static void set_immediate(nmethod* nm, jint val, int bit_mask) { DEBUG_ONLY(cmp2->verify()); cmp2->set_immediate(val, bit_mask); - if (method_body != nm->verified_inline_ro_entry_point() && entry_point2 != nm->verified_inline_ro_entry_point()) { - NativeNMethodCmpBarrier* cmp3 = reinterpret_cast(nm->verified_inline_ro_entry_point() + barrier_offset); + if (method_body != nm->verified_value_ro_entry_point() && entry_point2 != nm->verified_value_ro_entry_point()) { + NativeNMethodCmpBarrier* cmp3 = reinterpret_cast(nm->verified_value_ro_entry_point() + barrier_offset); assert(cmp1 != cmp3 && cmp2 != cmp3, "sanity"); DEBUG_ONLY(cmp3->verify()); cmp3->set_immediate(val, bit_mask); diff --git a/src/hotspot/cpu/x86/globals_x86.hpp b/src/hotspot/cpu/x86/globals_x86.hpp index 66ed3abd0cc7..5a7c8d310ec3 100644 --- a/src/hotspot/cpu/x86/globals_x86.hpp +++ b/src/hotspot/cpu/x86/globals_x86.hpp @@ -86,8 +86,8 @@ define_pd_global(bool, PreserveFramePointer, false); define_pd_global(intx, InitArrayShortSize, 8*BytesPerLong); -define_pd_global(bool, InlineTypePassFieldsAsArgs, true); -define_pd_global(bool, InlineTypeReturnedAsFields, true); +define_pd_global(bool, ValueTypePassFieldsAsArgs, true); +define_pd_global(bool, ValueTypeReturnedAsFields, true); #define ARCH_FLAGS(develop, \ product, \ diff --git a/src/hotspot/cpu/x86/interp_masm_x86.cpp b/src/hotspot/cpu/x86/interp_masm_x86.cpp index 90f24a364e51..9c2c73ee2c72 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.cpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp @@ -32,10 +32,10 @@ #include "oops/markWord.hpp" #include "oops/methodData.hpp" #include "oops/method.hpp" -#include "oops/inlineKlass.hpp" #include "oops/resolvedFieldEntry.hpp" #include "oops/resolvedIndyEntry.hpp" #include "oops/resolvedMethodEntry.hpp" +#include "oops/valueKlass.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiThreadState.hpp" #include "runtime/basicLock.hpp" @@ -1054,7 +1054,7 @@ void InterpreterMacroAssembler::remove_activation(TosState state, bind(no_reserved_zone_enabling); } - if (state == atos && InlineTypeReturnedAsFields) { + if (state == atos && ValueTypeReturnedAsFields) { Label skip; Label not_null; testptr(rax, rax); @@ -1068,14 +1068,14 @@ void InterpreterMacroAssembler::remove_activation(TosState state, jmp(skip); bind(not_null); - // Check if we are returning a non-null inline type and load its fields into registers - test_oop_is_not_inline_type(rax, rscratch1, skip, /* can_be_null= */ false); + // Check if we are returning a non-null value type and load its fields into registers + test_oop_is_not_value_type(rax, rscratch1, skip, /* can_be_null= */ false); - // Load fields from a buffered value with an inline class specific handler + // Load fields from a buffered value with a value class specific handler load_klass(rdi, rax, rscratch1); - movptr(rdi, Address(rdi, InlineKlass::adr_members_offset())); - movptr(rdi, Address(rdi, InlineKlass::unpack_handler_offset())); - // Unpack handler can be null if inline type is not scalarizable in returns + movptr(rdi, Address(rdi, ValueKlass::adr_members_offset())); + movptr(rdi, Address(rdi, ValueKlass::unpack_handler_offset())); + // Unpack handler can be null if value type is not scalarizable in returns testptr(rdi, rdi); jcc(Assembler::zero, skip); call(rdi); @@ -1132,7 +1132,7 @@ void InterpreterMacroAssembler::write_flat_field(Register entry, Register tmp1, Label slow_path, done; load_unsigned_byte(tmp2, Address(entry, in_bytes(ResolvedFieldEntry::flags_offset()))); - test_field_is_not_null_free_inline_type(tmp2, tmp1, slow_path); + test_field_is_not_null_free_value_type(tmp2, tmp1, slow_path); null_check(value); // FIXME JDK-8341120 @@ -1146,7 +1146,7 @@ void InterpreterMacroAssembler::write_flat_field(Register entry, Register tmp1, movptr(tmp2, Address(entry, in_bytes(ResolvedFieldEntry::field_holder_offset()))); Register layout_info = off; - inline_layout_info(tmp2, idx, layout_info); + value_field_layout_info(tmp2, idx, layout_info); flat_field_copy(IN_HEAP, value, obj, layout_info); jmp(done); @@ -1708,18 +1708,18 @@ void InterpreterMacroAssembler::profile_acmp(Register mdp, mov(tmp, left); profile_obj_type(tmp, Address(mdp, in_bytes(ACmpData::left_offset()))); - Label left_not_inline_type; - test_oop_is_not_inline_type(left, tmp, left_not_inline_type); - set_mdp_flag_at(mdp, ACmpData::left_inline_type_byte_constant()); - bind(left_not_inline_type); + Label left_not_value_type; + test_oop_is_not_value_type(left, tmp, left_not_value_type); + set_mdp_flag_at(mdp, ACmpData::left_value_type_byte_constant()); + bind(left_not_value_type); mov(tmp, right); profile_obj_type(tmp, Address(mdp, in_bytes(ACmpData::right_offset()))); - Label right_not_inline_type; - test_oop_is_not_inline_type(right, tmp, right_not_inline_type); - set_mdp_flag_at(mdp, ACmpData::right_inline_type_byte_constant()); - bind(right_not_inline_type); + Label right_not_value_type; + test_oop_is_not_value_type(right, tmp, right_not_value_type); + set_mdp_flag_at(mdp, ACmpData::right_value_type_byte_constant()); + bind(right_not_value_type); bind(profile_continue); } diff --git a/src/hotspot/cpu/x86/interp_masm_x86.hpp b/src/hotspot/cpu/x86/interp_masm_x86.hpp index ed4b8003ed41..d4bfb9ba89fd 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.hpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.hpp @@ -215,7 +215,7 @@ class InterpreterMacroAssembler: public MacroAssembler { bool notify_jvmdi = true); void get_method_counters(Register method, Register mcs, Label& skip); - // Allocate instance in "obj" and read in the content of the inline field + // Allocate instance in "obj" and read in the content of the value field // NOTES: // - input holder object via "obj", which must be rax, // will return new instance via the same reg diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 20ca09968b89..55be1645e2d8 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -24,11 +24,11 @@ #include "asm/assembler.hpp" #include "asm/assembler.inline.hpp" +#include "ci/ciValueKlass.hpp" #include "code/aotCodeCache.hpp" #include "code/compiledIC.hpp" #include "compiler/compiler_globals.hpp" #include "compiler/disassembler.hpp" -#include "ci/ciInlineKlass.hpp" #include "crc32c.h" #include "gc/shared/barrierSet.hpp" #include "gc/shared/barrierSetAssembler.hpp" @@ -2405,34 +2405,34 @@ void MacroAssembler::null_check(Register reg, int offset) { } } -void MacroAssembler::test_markword_is_inline_type(Register markword, Label& is_inline_type) { - andptr(markword, markWord::inline_type_pattern_mask); - cmpptr(markword, markWord::inline_type_pattern); - jcc(Assembler::equal, is_inline_type); +void MacroAssembler::test_markword_is_value_type(Register markword, Label& is_value_type) { + andptr(markword, markWord::value_type_pattern_mask); + cmpptr(markword, markWord::value_type_pattern); + jcc(Assembler::equal, is_value_type); } -void MacroAssembler::test_oop_is_not_inline_type(Register object, Register tmp, Label& not_inline_type, bool can_be_null) { +void MacroAssembler::test_oop_is_not_value_type(Register object, Register tmp, Label& not_value_type, bool can_be_null) { if (can_be_null) { testptr(object, object); - jcc(Assembler::zero, not_inline_type); + jcc(Assembler::zero, not_value_type); } - const int is_inline_type_mask = markWord::inline_type_pattern; + const int is_value_type_mask = markWord::value_type_pattern; movptr(tmp, Address(object, oopDesc::mark_offset_in_bytes())); - andptr(tmp, is_inline_type_mask); - cmpptr(tmp, is_inline_type_mask); - jcc(Assembler::notEqual, not_inline_type); + andptr(tmp, is_value_type_mask); + cmpptr(tmp, is_value_type_mask); + jcc(Assembler::notEqual, not_value_type); } -void MacroAssembler::test_field_is_null_free_inline_type(Register flags, Register temp_reg, Label& is_null_free_inline_type) { +void MacroAssembler::test_field_is_null_free_value_type(Register flags, Register temp_reg, Label& is_null_free_value_type) { movl(temp_reg, flags); - testl(temp_reg, 1 << ResolvedFieldEntry::is_null_free_inline_type_shift); - jcc(Assembler::notEqual, is_null_free_inline_type); + testl(temp_reg, 1 << ResolvedFieldEntry::is_null_free_value_type_shift); + jcc(Assembler::notEqual, is_null_free_value_type); } -void MacroAssembler::test_field_is_not_null_free_inline_type(Register flags, Register temp_reg, Label& not_null_free_inline_type) { +void MacroAssembler::test_field_is_not_null_free_value_type(Register flags, Register temp_reg, Label& not_null_free_value_type) { movl(temp_reg, flags); - testl(temp_reg, 1 << ResolvedFieldEntry::is_null_free_inline_type_shift); - jcc(Assembler::equal, not_null_free_inline_type); + testl(temp_reg, 1 << ResolvedFieldEntry::is_null_free_value_type_shift); + jcc(Assembler::equal, not_null_free_value_type); } void MacroAssembler::test_field_is_flat(Register flags, Register temp_reg, Label& is_flat) { @@ -3811,26 +3811,26 @@ void MacroAssembler::zero_memory(Register address, Register length_in_bytes, int bind(done); } -void MacroAssembler::inline_layout_info(Register holder_klass, Register index, Register layout_info) { - movptr(layout_info, Address(holder_klass, InstanceKlass::inline_layout_info_array_offset())); +void MacroAssembler::value_field_layout_info(Register holder_klass, Register index, Register layout_info) { + movptr(layout_info, Address(holder_klass, InstanceKlass::value_field_layout_info_array_offset())); #ifdef ASSERT { Label done; cmpptr(layout_info, 0); jcc(Assembler::notEqual, done); - stop("inline_layout_info_array is null"); + stop("value_field_layout_info_array is null"); bind(done); } #endif - InlineLayoutInfo array[2]; + ValueFieldLayoutInfo array[2]; int size = (char*)&array[1] - (char*)&array[0]; // computing size of array elements if (is_power_of_2(size)) { shll(index, log2i_exact(size)); // Scale index by power of 2 } else { imull(index, index, size); // Scale the index to be the entry index * array_element_size } - lea(layout_info, Address(layout_info, index, Address::times_1, Array::base_offset_in_bytes())); + lea(layout_info, Address(layout_info, index, Address::times_1, Array::base_offset_in_bytes())); } // Look up the method for a megamorphic invokeinterface call. @@ -5639,20 +5639,20 @@ void MacroAssembler::access_store_at(BasicType type, DecoratorSet decorators, Ad } void MacroAssembler::flat_field_copy(DecoratorSet decorators, Register src, Register dst, - Register inline_layout_info) { + Register value_field_layout_info) { BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); - bs->flat_field_copy(this, decorators, src, dst, inline_layout_info); + bs->flat_field_copy(this, decorators, src, dst, value_field_layout_info); } -void MacroAssembler::payload_offset(Register inline_klass, Register offset) { - movptr(offset, Address(inline_klass, InlineKlass::adr_members_offset())); - movl(offset, Address(offset, InlineKlass::payload_offset_offset())); +void MacroAssembler::payload_offset(Register value_klass, Register offset) { + movptr(offset, Address(value_klass, ValueKlass::adr_members_offset())); + movl(offset, Address(offset, ValueKlass::payload_offset_offset())); } -void MacroAssembler::payload_addr(Register oop, Register data, Register inline_klass) { +void MacroAssembler::payload_addr(Register oop, Register data, Register value_klass) { // ((address) (void*) o) + vk->payload_offset(); Register offset = (data == oop) ? rscratch1 : data; - payload_offset(inline_klass, offset); + payload_offset(value_klass, offset); if (data == oop) { addptr(data, offset); } else { @@ -6022,13 +6022,13 @@ void MacroAssembler::reinit_heapbase() { } } -int MacroAssembler::store_inline_type_fields_to_buf(ciInlineKlass* vk, bool from_interpreter) { - assert(InlineTypeReturnedAsFields, "Inline types should never be returned as fields"); - // An inline type might be returned. If fields are in registers we - // need to allocate an inline type instance and initialize it with +int MacroAssembler::store_value_type_fields_to_buf(ciValueKlass* vk, bool from_interpreter) { + assert(ValueTypeReturnedAsFields, "Value types should never be returned as fields"); + // A value type might be returned. If fields are in registers we + // need to allocate a value type instance and initialize it with // the value of the fields. Label skip; - // We only need a new buffered inline type if a new one is not returned + // We only need a new buffered value type if a new one is not returned testptr(rax, 1); jcc(Assembler::zero, skip); int call_offset = -1; @@ -6037,20 +6037,20 @@ int MacroAssembler::store_inline_type_fields_to_buf(ciInlineKlass* vk, bool from // e.g. object size is always not zero, sometimes it's constant; storing klass ptr after // allocating is not necessary if vk != nullptr, etc. Label slow_case; - // 1. Try to allocate a new buffered inline instance either from TLAB or eden space + // 1. Try to allocate a new buffered value instance either from TLAB or eden space mov(rscratch1, rax); // save rax for slow_case since *_allocate may corrupt it when allocation failed if (vk != nullptr) { // Called from C1, where the return type is statically known. - movptr(rbx, (intptr_t)vk->get_InlineKlass()); + movptr(rbx, (intptr_t)vk->get_ValueKlass()); jint lh = vk->layout_helper(); - assert(lh != Klass::_lh_neutral_value, "inline class in return type must have been resolved"); + assert(lh != Klass::_lh_neutral_value, "value class in return type must have been resolved"); if (UseTLAB && !Klass::layout_helper_needs_slow_path(lh)) { tlab_allocate(rax, noreg, lh, r13, r14, slow_case); } else { jmp(slow_case); } } else { - // Call from interpreter. RAX contains ((the InlineKlass* of the return type) | 0x01) + // Call from interpreter. RAX contains ((the ValueKlass* of the return type) | 0x01) mov(rbx, rax); andptr(rbx, -2); if (UseTLAB) { @@ -6063,7 +6063,7 @@ int MacroAssembler::store_inline_type_fields_to_buf(ciInlineKlass* vk, bool from } } if (UseTLAB) { - // 2. Initialize buffered inline instance header + // 2. Initialize buffered value instance header Register buffer_obj = rax; Register klass = rbx; if (UseCompactObjectHeaders) { @@ -6071,7 +6071,7 @@ int MacroAssembler::store_inline_type_fields_to_buf(ciInlineKlass* vk, bool from movptr(mark_word, Address(klass, Klass::prototype_header_offset())); movptr(Address(buffer_obj, oopDesc::mark_offset_in_bytes()), mark_word); } else { - movptr(Address(buffer_obj, oopDesc::mark_offset_in_bytes()), (intptr_t)markWord::inline_type_prototype().value()); + movptr(Address(buffer_obj, oopDesc::mark_offset_in_bytes()), (intptr_t)markWord::value_type_prototype().value()); xorl(r13, r13); store_klass_gap(buffer_obj, r13); if (vk == nullptr) { @@ -6081,27 +6081,27 @@ int MacroAssembler::store_inline_type_fields_to_buf(ciInlineKlass* vk, bool from store_klass(buffer_obj, klass, rscratch1); klass = r13; } - // 3. Initialize its fields with an inline class specific handler + // 3. Initialize its fields with a value class specific handler if (vk != nullptr) { call(RuntimeAddress(vk->pack_handler())); // no need for call info as this will not safepoint. } else { - movptr(rbx, Address(klass, InlineKlass::adr_members_offset())); - movptr(rbx, Address(rbx, InlineKlass::pack_handler_offset())); + movptr(rbx, Address(klass, ValueKlass::adr_members_offset())); + movptr(rbx, Address(rbx, ValueKlass::pack_handler_offset())); call(rbx); } jmp(skip); } bind(slow_case); - // We failed to allocate a new inline type, fall back to a runtime + // We failed to allocate a new value type, fall back to a runtime // call. Some oop field may be live in some registers but we can't // tell. That runtime call will take care of preserving them // across a GC if there's one. mov(rax, rscratch1); if (from_interpreter) { - super_call_VM_leaf(SharedRuntime::store_inline_type_fields_to_buf_entry()); + super_call_VM_leaf(SharedRuntime::store_value_type_fields_to_buf_entry()); } else { - call(RuntimeAddress(SharedRuntime::store_inline_type_fields_to_buf_entry())); + call(RuntimeAddress(SharedRuntime::store_value_type_fields_to_buf_entry())); call_offset = offset(); } @@ -6171,9 +6171,9 @@ bool MacroAssembler::move_helper(VMReg from, VMReg to, BasicType bt, RegState re return true; } -// Calculate the extra stack space required for packing or unpacking inline +// Calculate the extra stack space required for packing or unpacking value // args and adjust the stack pointer (see MacroAssembler::remove_frame). -int MacroAssembler::extend_stack_for_inline_args(int args_on_stack) { +int MacroAssembler::extend_stack_for_value_args(int args_on_stack) { int sp_inc = args_on_stack * VMRegImpl::stack_slot_size; sp_inc = align_up(sp_inc, StackAlignmentInBytes); assert(sp_inc > 0, "sanity"); @@ -6189,10 +6189,10 @@ int MacroAssembler::extend_stack_for_inline_args(int args_on_stack) { return sp_inc + wordSize; // account for rbp space } -// Read all fields from an inline type buffer and store the field values in registers/stack slots. -bool MacroAssembler::unpack_inline_helper(const GrowableArray* sig, int& sig_index, - VMReg from, int& from_index, VMRegPair* to, int to_count, int& to_index, - RegState reg_state[]) { +// Read all fields from a value type buffer and store the field values in registers/stack slots. +bool MacroAssembler::unpack_value_helper(const GrowableArray* sig, int& sig_index, + VMReg from, int& from_index, VMRegPair* to, int to_count, int& to_index, + RegState reg_state[]) { assert(sig->at(sig_index)._bt == T_VOID, "should be at end delimiter"); assert(from->is_valid(), "source must be valid"); bool progress = false; @@ -6205,7 +6205,7 @@ bool MacroAssembler::unpack_inline_helper(const GrowableArray* sig, in Register tmp1 = r10; Register tmp2 = r13; Register fromReg = noreg; - ScalarizedInlineArgsStream stream(sig, sig_index, to, to_count, to_index, true); + ScalarizedValueArgsStream stream(sig, sig_index, to, to_count, to_index, true); bool done = true; bool mark_done = true; VMReg toReg; @@ -6245,7 +6245,7 @@ bool MacroAssembler::unpack_inline_helper(const GrowableArray* sig, in fromReg = tmp1; } if (null_check) { - // Nullable inline type argument, emit null check + // Nullable value type argument, emit null check testptr(fromReg, fromReg); jcc(Assembler::zero, L_null); } @@ -6327,9 +6327,9 @@ bool MacroAssembler::unpack_inline_helper(const GrowableArray* sig, in return done; } -bool MacroAssembler::pack_inline_helper(const GrowableArray* sig, int& sig_index, int vtarg_index, - VMRegPair* from, int from_count, int& from_index, VMReg to, - RegState reg_state[], Register val_array) { +bool MacroAssembler::pack_value_helper(const GrowableArray* sig, int& sig_index, int vtarg_index, + VMRegPair* from, int from_count, int& from_index, VMReg to, + RegState reg_state[], Register val_array) { assert(sig->at(sig_index)._bt == T_METADATA, "should be at delimiter"); assert(to->is_valid(), "destination must be valid"); @@ -6356,7 +6356,7 @@ bool MacroAssembler::pack_inline_helper(const GrowableArray* sig, int& val_obj = val_obj_tmp; } - ScalarizedInlineArgsStream stream(sig, sig_index, from, from_count, from_index); + ScalarizedValueArgsStream stream(sig, sig_index, from, from_count, from_index); VMReg fromReg; BasicType bt; Label L_null; @@ -6366,7 +6366,7 @@ bool MacroAssembler::pack_inline_helper(const GrowableArray* sig, int& int off = sig->at(stream.sig_index())._offset; if (off == -1) { - // Nullable inline type argument, emit null check + // Nullable value type argument, emit null check Label L_notNull; if (fromReg->is_stack()) { int ld_off = fromReg->reg2stack() * VMRegImpl::stack_slot_size + wordSize; @@ -10624,8 +10624,8 @@ void MacroAssembler::fast_lock(Register basic_lock, Register obj, Register reg_r andptr(tmp, ~(int32_t)markWord::lock_neutral_value); orptr(reg_rax, markWord::lock_neutral_value); if (Arguments::is_valhalla_enabled()) { - // Mask inline_type bit such that we go to the slow path if object is an inline type - andptr(reg_rax, ~((int) markWord::inline_type_bit_in_place)); + // Mask value_type bit such that we go to the slow path if object is a value type + andptr(reg_rax, ~((int) markWord::value_type_bit_in_place)); } lock(); cmpxchgptr(tmp, Address(obj, oopDesc::mark_offset_in_bytes())); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index b7c6b379c022..714efb5e7c0d 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -34,7 +34,7 @@ #include "runtime/vm_version.hpp" #include "utilities/checkedCast.hpp" -class ciInlineKlass; +class ciValueKlass; // MacroAssembler extends Assembler by frequently used macros. // @@ -98,13 +98,13 @@ class MacroAssembler: public Assembler { static bool uses_implicit_null_check(void* address); // markWord tests, kills markWord reg - void test_markword_is_inline_type(Register markword, Label& is_inline_type); + void test_markword_is_value_type(Register markword, Label& is_value_type); - // inlineKlass queries, kills temp_reg - void test_oop_is_not_inline_type(Register object, Register tmp, Label& not_inline_type, bool can_be_null = true); + // ValueKlass queries, kills temp_reg + void test_oop_is_not_value_type(Register object, Register tmp, Label& not_value_type, bool can_be_null = true); - void test_field_is_null_free_inline_type(Register flags, Register temp_reg, Label& is_null_free); - void test_field_is_not_null_free_inline_type(Register flags, Register temp_reg, Label& not_null_free); + void test_field_is_null_free_value_type(Register flags, Register temp_reg, Label& is_null_free); + void test_field_is_not_null_free_value_type(Register flags, Register temp_reg, Label& not_null_free); void test_field_is_flat(Register flags, Register temp_reg, Label& is_flat); // Check oops for special arrays, i.e. flat arrays and/or null-free arrays @@ -392,11 +392,11 @@ class MacroAssembler: public Assembler { void access_store_at(BasicType type, DecoratorSet decorators, Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); - void flat_field_copy(DecoratorSet decorators, Register src, Register dst, Register inline_layout_info); + void flat_field_copy(DecoratorSet decorators, Register src, Register dst, Register value_field_layout_info); - // inline type data payload offsets... - void payload_offset(Register inline_klass, Register offset); - void payload_addr(Register oop, Register data, Register inline_klass); + // value type data payload offsets... + void payload_offset(Register value_klass, Register offset); + void payload_addr(Register oop, Register data, Register value_klass); void load_heap_oop(Register dst, Address src, Register tmp1 = noreg, DecoratorSet decorators = 0); void load_heap_oop_not_null(Register dst, Address src, Register tmp1 = noreg, DecoratorSet decorators = 0); @@ -554,7 +554,7 @@ class MacroAssembler: public Assembler { ); void zero_memory(Register address, Register length_in_bytes, int offset_in_bytes, Register temp); - void inline_layout_info(Register klass, Register index, Register layout_info); + void value_field_layout_info(Register klass, Register index, Register layout_info); void population_count(Register dst, Register src, Register scratch1, Register scratch2); @@ -1965,7 +1965,7 @@ class MacroAssembler: public Assembler { public: - // Inline type specific methods + // Value type specific methods #include "asm/macroAssembler_common.hpp" // Clear or fill 'cnt' qwords starting at 'base'. If 'requires_word_fill' is diff --git a/src/hotspot/cpu/x86/methodHandles_x86.cpp b/src/hotspot/cpu/x86/methodHandles_x86.cpp index 9c8dd0dd0ba2..46d90ce9fcc0 100644 --- a/src/hotspot/cpu/x86/methodHandles_x86.cpp +++ b/src/hotspot/cpu/x86/methodHandles_x86.cpp @@ -193,11 +193,11 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth __ BIND(run_compiled_code); } - // The following jump might pass an inline type argument that was erased to Object as oop to a - // callee that expects inline type arguments to be passed as fields. We need to call the compiled - // value entry (_code->inline_entry_point() or _adapter->c2i_inline_entry()) which will take care + // The following jump might pass a value type argument that was erased to Object as oop to a + // callee that expects value type arguments to be passed as fields. We need to call the compiled + // value entry (_code->value_entry_point() or _adapter->c2i_value_entry()) which will take care // of translating between the calling conventions. - const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_inline_offset() : + const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_value_offset() : Method::from_interpreted_offset(); __ jmp(Address(method, entry_offset)); diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index 0eb629f6ee8e..f6a9155d5adc 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -755,25 +755,25 @@ static void patch_callers_callsite(MacroAssembler *masm) { __ bind(L); } -// For each inline type argument, sig includes the list of fields of -// the inline type. This utility function computes the number of -// arguments for the call if inline types are passed by reference (the +// For each value type argument, sig includes the list of fields of +// the value type. This utility function computes the number of +// arguments for the call if value types are passed by reference (the // calling convention the interpreter expects). static int compute_total_args_passed_int(const GrowableArray* sig_extended) { int total_args_passed = 0; - if (InlineTypePassFieldsAsArgs) { + if (ValueTypePassFieldsAsArgs) { for (int i = 0; i < sig_extended->length(); i++) { BasicType bt = sig_extended->at(i)._bt; if (bt == T_METADATA) { - // In sig_extended, an inline type argument starts with: + // In sig_extended, a value type argument starts with: // T_METADATA, followed by the types of the fields of the - // inline type and T_VOID to mark the end of the value - // type. Inline types are flattened so, for instance, in the - // case of an inline type with an int field and an inline type + // value type and T_VOID to mark the end of the value + // type. Value types are flattened so, for instance, in the + // case of a value type with an int field and a value type // field that itself has 2 fields, an int and a long: // T_METADATA T_INT T_METADATA T_INT T_LONG T_VOID (second - // slot for the T_LONG) T_VOID (inner inline type) T_VOID - // (outer inline type) + // slot for the T_LONG) T_VOID (inner value type) T_VOID + // (outer value type) total_args_passed++; int vt = 1; do { @@ -909,13 +909,13 @@ static void gen_c2i_adapter(MacroAssembler *masm, __ bind(skip_fixup); - if (InlineTypePassFieldsAsArgs) { - // Is there an inline type argument? - bool has_inline_argument = false; - for (int i = 0; i < sig_extended->length() && !has_inline_argument; i++) { - has_inline_argument = (sig_extended->at(i)._bt == T_METADATA); + if (ValueTypePassFieldsAsArgs) { + // Is there a value type argument? + bool has_value_argument = false; + for (int i = 0; i < sig_extended->length() && !has_value_argument; i++) { + has_value_argument = (sig_extended->at(i)._bt == T_METADATA); } - if (has_inline_argument) { + if (has_value_argument) { // There is at least a value type argument: we're coming from // compiled code so we may not have buffers to back the value // objects. Allocate the buffers here with a runtime call for @@ -929,7 +929,7 @@ static void gen_c2i_adapter(MacroAssembler *masm, __ mov(c_rarg0, r15_thread); __ mov(c_rarg1, rbx); __ mov64(c_rarg2, (int64_t)alloc_inline_receiver); - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::allocate_inline_types))); + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::allocate_value_types))); oop_maps->add_gc_map((int)(__ pc() - start), map); __ reset_last_Java_frame(false); @@ -990,22 +990,22 @@ static void gen_c2i_adapter(MacroAssembler *masm, // Now write the args into the outgoing interpreter space // next_arg_comp is the next argument from the compiler point of - // view (inline type fields are passed in registers/on the stack). In - // sig_extended, an inline type argument starts with: T_METADATA, - // followed by the types of the fields of the inline type and T_VOID - // to mark the end of the inline type. ignored counts the number of - // T_METADATA/T_VOID. next_vt_arg is the next inline type argument: + // view (value type fields are passed in registers/on the stack). In + // sig_extended, a value type argument starts with: T_METADATA, + // followed by the types of the fields of the value type and T_VOID + // to mark the end of the value type. ignored counts the number of + // T_METADATA/T_VOID. next_vt_arg is the next value type argument: // used to get the buffer for that argument from the pool of buffers // we allocated above and want to pass to the // interpreter. next_arg_int is the next argument from the - // interpreter point of view (inline types are passed by reference). + // interpreter point of view (value types are passed by reference). for (int next_arg_comp = 0, ignored = 0, next_vt_arg = 0, next_arg_int = 0; next_arg_comp < sig_extended->length(); next_arg_comp++) { assert(ignored <= next_arg_comp, "shouldn't skip over more slots than there are arguments"); assert(next_arg_int <= total_args_passed, "more arguments for the interpreter than expected?"); BasicType bt = sig_extended->at(next_arg_comp)._bt; int st_off = (total_args_passed - next_arg_int) * Interpreter::stackElementSize; - if (!InlineTypePassFieldsAsArgs || bt != T_METADATA) { + if (!ValueTypePassFieldsAsArgs || bt != T_METADATA) { int next_off = st_off - Interpreter::stackElementSize; const int offset = (bt == T_LONG || bt == T_DOUBLE) ? next_off : st_off; const VMRegPair reg_pair = regs[next_arg_comp-ignored]; @@ -1025,10 +1025,10 @@ static void gen_c2i_adapter(MacroAssembler *masm, next_arg_int++; int vt = 1; // write fields we get from compiled code in registers/stack - // slots to the buffer: we know we are done with that inline type + // slots to the buffer: we know we are done with that value type // argument when we hit the T_VOID that acts as an end of inline - // type delimiter for this inline type. Inline types are flattened - // so we might encounter embedded inline types. Each entry in + // type delimiter for this value type. Value types are flattened + // so we might encounter embedded value types. Each entry in // sig_extended contains a field offset in the buffer. Label L_null; Label not_null_buffer; @@ -1062,7 +1062,7 @@ static void gen_c2i_adapter(MacroAssembler *masm, } else { int off = sig_extended->at(next_arg_comp)._offset; if (off == -1) { - // Nullable inline type argument, emit null check + // Nullable value type argument, emit null check VMReg reg = regs[next_arg_comp-ignored].first(); Label L_notNull; if (reg->is_stack()) { @@ -1154,7 +1154,7 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, // Will jump to the compiled code just as if compiled code was doing it. // Pre-load the register-jump target early, to schedule it better. - __ movptr(r11, Address(rbx, in_bytes(Method::from_compiled_inline_offset()))); + __ movptr(r11, Address(rbx, in_bytes(Method::from_compiled_value_offset()))); int total_args_passed = sig->length(); @@ -1300,7 +1300,7 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler* masm, // compiled code, which relies solely on SP and not RBP, get sick). entry_address[AdapterBlob::C2I_Unverified] = __ pc(); - entry_address[AdapterBlob::C2I_Unverified_Inline] = __ pc(); + entry_address[AdapterBlob::C2I_Unverified_Value] = __ pc(); Label skip_fixup; gen_inline_cache_check(masm, skip_fixup); @@ -1311,7 +1311,7 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler* masm, // Scalarized c2i adapter with non-scalarized receiver (i.e., don't pack receiver) entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr; - entry_address[AdapterBlob::C2I_Inline_RO] = __ pc(); + entry_address[AdapterBlob::C2I_Value_RO] = __ pc(); if (regs_cc != regs_cc_ro) { // No class init barrier needed because method is guaranteed to be non-static gen_c2i_adapter(masm, sig_cc_ro, regs_cc_ro, /* requires_clinit_barrier = */ false, entry_address[AdapterBlob::C2I_No_Clinit_Check], @@ -1320,20 +1320,20 @@ void SharedRuntime::generate_i2c2i_adapters(MacroAssembler* masm, } // Scalarized c2i adapter - entry_address[AdapterBlob::C2I] = __ pc(); - entry_address[AdapterBlob::C2I_Inline] = __ pc(); + entry_address[AdapterBlob::C2I] = __ pc(); + entry_address[AdapterBlob::C2I_Value] = __ pc(); gen_c2i_adapter(masm, sig_cc, regs_cc, /* requires_clinit_barrier = */ true, entry_address[AdapterBlob::C2I_No_Clinit_Check], skip_fixup, entry_address[AdapterBlob::I2C], oop_maps, frame_complete, frame_size_in_words, /* alloc_inline_receiver = */ true); // Non-scalarized c2i adapter if (regs != regs_cc) { - entry_address[AdapterBlob::C2I_Unverified_Inline] = __ pc(); - Label inline_entry_skip_fixup; - gen_inline_cache_check(masm, inline_entry_skip_fixup); + entry_address[AdapterBlob::C2I_Unverified_Value] = __ pc(); + Label value_entry_skip_fixup; + gen_inline_cache_check(masm, value_entry_skip_fixup); - entry_address[AdapterBlob::C2I_Inline] = __ pc(); + entry_address[AdapterBlob::C2I_Value] = __ pc(); gen_c2i_adapter(masm, sig, regs, /* requires_clinit_barrier = */ true, entry_address[AdapterBlob::C2I_No_Clinit_Check], - inline_entry_skip_fixup, entry_address[AdapterBlob::I2C], oop_maps, frame_complete, frame_size_in_words, /* alloc_inline_receiver = */ false); + value_entry_skip_fixup, entry_address[AdapterBlob::I2C], oop_maps, frame_complete, frame_size_in_words, /* alloc_inline_receiver = */ false); } // The c2i adapters might safepoint and trigger a GC. The caller must make sure that @@ -3717,8 +3717,8 @@ void SharedRuntime::montgomery_square(jint *a_ints, jint *n_ints, reverse_words(m, (julong *)m_ints, longwords); } -BufferedInlineTypeBlob* SharedRuntime::generate_buffered_inline_type_adapter(const InlineKlass* vk) { - CodeBuffer buffer("inline types pack/unpack", 16 * K, 0); +BufferedValueTypeBlob* SharedRuntime::generate_buffered_value_type_adapter(const ValueKlass* vk) { + CodeBuffer buffer("value types pack/unpack", 16 * K, 0); if (buffer.blob() == nullptr) { return nullptr; } @@ -3860,17 +3860,17 @@ BufferedInlineTypeBlob* SharedRuntime::generate_buffered_inline_type_adapter(con // Code will be copied. No ICache sync required. - return BufferedInlineTypeBlob::create(&buffer, pack_fields_off, pack_fields_jobject_off, unpack_fields_off); + return BufferedValueTypeBlob::create(&buffer, pack_fields_off, pack_fields_jobject_off, unpack_fields_off); } // Call here from the interpreter or compiled code to store returned -// values to a newly allocated inline type instance. +// values to a newly allocated value type instance. // Register is a class, but it would be assigned numerical value. // "0" is assigned for xmm0. Thus we need to ignore -Wnonnull. PRAGMA_DIAG_PUSH PRAGMA_NONNULL_IGNORED RuntimeStub* SharedRuntime::generate_return_value_stub(address destination) { - StubId id = StubId::shared_store_inline_type_fields_to_buf_id; + StubId id = StubId::shared_store_value_type_fields_to_buf_id; const char* name = SharedRuntime::stub_name(id); CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::SharedBlob, StubInfo::blob(id)); @@ -3995,15 +3995,15 @@ RuntimeStub* SharedRuntime::generate_return_value_stub(address destination) { __ cmpptr(Address(r15_thread, Thread::pending_exception_offset()), (int32_t)NULL_WORD); __ jcc(Assembler::notEqual, pending); - // We just called SharedRuntime::store_inline_type_fields_to_buf. Check if we still - // need to initialize the buffer and if so, call the inline class specific pack handler. + // We just called SharedRuntime::store_value_type_fields_to_buf. Check if we still + // need to initialize the buffer and if so, call the value class specific pack handler. Label skip_pack; __ get_vm_result_oop(rax); __ get_vm_result_metadata(rscratch1); __ testptr(rscratch1, rscratch1); __ jcc(Assembler::zero, skip_pack); - __ movptr(rscratch1, Address(rscratch1, InlineKlass::adr_members_offset())); - __ movptr(rscratch1, Address(rscratch1, InlineKlass::pack_handler_offset())); + __ movptr(rscratch1, Address(rscratch1, ValueKlass::adr_members_offset())); + __ movptr(rscratch1, Address(rscratch1, ValueKlass::pack_handler_offset())); __ call(rscratch1); __ membar(Assembler::StoreStore); __ bind(skip_pack); @@ -4028,6 +4028,13 @@ RuntimeStub* SharedRuntime::generate_return_value_stub(address destination) { // It returns a jobject handle to the event writer. // The handle is dereferenced and the return value is the event writer oop. RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { + StubId id = StubId::shared_jfr_write_checkpoint_id; + + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::SharedBlob, StubInfo::blob(id)); + if (blob != nullptr) { + return blob->as_runtime_stub(); + } + enum layout { rbp_off, rbpH_off, @@ -4036,7 +4043,7 @@ RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { framesize // inclusive of return address }; - const char* name = SharedRuntime::stub_name(StubId::shared_jfr_write_checkpoint_id); + const char* name = SharedRuntime::stub_name(id); CodeBuffer code(name, 1024 + (UseAPX ? 1024 : 0), 64); MacroAssembler* masm = new MacroAssembler(&code); address start = __ pc(); @@ -4068,11 +4075,20 @@ RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { (framesize >> (LogBytesPerWord - LogBytesPerInt)), oop_maps, false); + AOTCodeCache::store_code_blob(*stub, AOTCodeEntry::SharedBlob, StubInfo::blob(id)); + return stub; } // For c2: call to return a leased buffer. RuntimeStub* SharedRuntime::generate_jfr_return_lease() { + StubId id = StubId::shared_jfr_return_lease_id; + + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::SharedBlob, StubInfo::blob(id)); + if (blob != nullptr) { + return blob->as_runtime_stub(); + } + enum layout { rbp_off, rbpH_off, @@ -4081,7 +4097,7 @@ RuntimeStub* SharedRuntime::generate_jfr_return_lease() { framesize // inclusive of return address }; - const char* name = SharedRuntime::stub_name(StubId::shared_jfr_return_lease_id); + const char* name = SharedRuntime::stub_name(id); CodeBuffer code(name, 1024, 64); MacroAssembler* masm = new MacroAssembler(&code); address start = __ pc(); @@ -4110,6 +4126,8 @@ RuntimeStub* SharedRuntime::generate_jfr_return_lease() { (framesize >> (LogBytesPerWord - LogBytesPerInt)), oop_maps, false); + AOTCodeCache::store_code_blob(*stub, AOTCodeEntry::SharedBlob, StubInfo::blob(id)); + return stub; } diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index 7e3addb752dd..506d1f13f361 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -32,7 +32,7 @@ #include "gc/shared/barrierSetNMethod.hpp" #include "gc/shared/gc_globals.hpp" #include "memory/universe.hpp" -#include "oops/inlineKlass.hpp" +#include "oops/valueKlass.hpp" #include "prims/jvmtiExport.hpp" #include "prims/upcallLinker.hpp" #include "runtime/arguments.hpp" @@ -311,7 +311,7 @@ address StubGenerator::generate_call_stub(address& return_address) { return_address = __ pc(); entries.append(return_address); - // All of j_rargN + rax may be used to return inline type fields so be careful + // All of j_rargN + rax may be used to return value type fields so be careful // not to clobber those. See SharedRuntime::java_return_convention(). // store result depending on type (everything that is not @@ -398,14 +398,14 @@ address StubGenerator::generate_call_stub(address& return_address) { // handle return types different from T_INT __ BIND(check_prim); - if (InlineTypeReturnedAsFields) { + if (ValueTypeReturnedAsFields) { // Check for scalarized return value __ testptr(rax, 1); __ jcc(Assembler::zero, is_long); // Load pack handler address __ andptr(rax, -2); - __ movptr(rax, Address(rax, InlineKlass::adr_members_offset())); - __ movptr(rbx, Address(rax, InlineKlass::pack_handler_jobject_offset())); + __ movptr(rax, Address(rax, ValueKlass::adr_members_offset())); + __ movptr(rbx, Address(rax, ValueKlass::pack_handler_jobject_offset())); // Call pack handler to initialize the buffer __ call(rbx); __ jmp(exit); @@ -4487,7 +4487,7 @@ address StubGenerator::generate_floatToFloat16() { static void save_return_registers(MacroAssembler* masm) { masm->push_ppx(rax); - if (InlineTypeReturnedAsFields) { + if (ValueTypeReturnedAsFields) { masm->push(rdi); masm->push(rsi); masm->push(rdx); @@ -4496,7 +4496,7 @@ static void save_return_registers(MacroAssembler* masm) { masm->push(r9); } masm->push_d(xmm0); - if (InlineTypeReturnedAsFields) { + if (ValueTypeReturnedAsFields) { masm->push_d(xmm1); masm->push_d(xmm2); masm->push_d(xmm3); @@ -4525,7 +4525,7 @@ static void save_return_registers(MacroAssembler* masm) { } static void restore_return_registers(MacroAssembler* masm) { - if (InlineTypeReturnedAsFields) { + if (ValueTypeReturnedAsFields) { masm->pop_d(xmm7); masm->pop_d(xmm6); masm->pop_d(xmm5); @@ -4535,7 +4535,7 @@ static void restore_return_registers(MacroAssembler* masm) { masm->pop_d(xmm1); } masm->pop_d(xmm0); - if (InlineTypeReturnedAsFields) { + if (ValueTypeReturnedAsFields) { masm->pop(r9); masm->pop(r8); masm->pop(rcx); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp index c2db4a69b233..3e84023ef0db 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp @@ -3601,10 +3601,10 @@ address StubGenerator::generate_generic_copy(address byte_copy_entry, address sh __ jcc(Assembler::notEqual, L_failed); if (Arguments::is_valhalla_enabled()) { - // Check for flat inline type array -> return -1 + // Check for flat value type array -> return -1 __ test_flat_array_oop(src, rax, L_failed); - // Check for null-free (non-flat) inline type array -> handle as object array + // Check for null-free (non-flat) value type array -> handle as object array __ test_null_free_array_oop(src, rax, L_objArray); } diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp index 38dfe1e171b0..47e28cf94700 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp @@ -38,9 +38,9 @@ #include "oops/methodData.hpp" #include "oops/method.hpp" #include "oops/oop.inline.hpp" -#include "oops/inlineKlass.hpp" #include "oops/resolvedIndyEntry.hpp" #include "oops/resolvedMethodEntry.hpp" +#include "oops/valueKlass.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiThreadState.hpp" #include "runtime/continuation.hpp" @@ -182,8 +182,8 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, // and null it as marker that esp is now tos until next java call __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), NULL_WORD); - if (state == atos && InlineTypeReturnedAsFields) { - __ store_inline_type_fields_to_buf(nullptr); + if (state == atos && ValueTypeReturnedAsFields) { + __ store_value_type_fields_to_buf(nullptr); } __ restore_bcp(); diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp index 4c1ccde0e526..0d945d5b554f 100644 --- a/src/hotspot/cpu/x86/templateTable_x86.cpp +++ b/src/hotspot/cpu/x86/templateTable_x86.cpp @@ -36,10 +36,10 @@ #include "oops/methodData.hpp" #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" -#include "oops/inlineKlass.hpp" #include "oops/resolvedFieldEntry.hpp" #include "oops/resolvedIndyEntry.hpp" #include "oops/resolvedMethodEntry.hpp" +#include "oops/valueKlass.hpp" #include "prims/jvmtiExport.hpp" #include "prims/methodHandles.hpp" #include "runtime/arguments.hpp" @@ -1957,7 +1957,7 @@ void TemplateTable::if_acmp(Condition cc) { __ profile_acmp(rbx, rdx, rax, rcx); - const int is_inline_type_mask = markWord::inline_type_pattern; + const int is_value_type_mask = markWord::value_type_pattern; if (Arguments::is_valhalla_enabled()) { __ cmpoop(rdx, rax); __ jcc(Assembler::equal, (cc == equal) ? taken : not_taken); @@ -1971,8 +1971,8 @@ void TemplateTable::if_acmp(Condition cc) { // and both are values ? __ movptr(rbx, Address(rdx, oopDesc::mark_offset_in_bytes())); __ andptr(rbx, Address(rax, oopDesc::mark_offset_in_bytes())); - __ andptr(rbx, is_inline_type_mask); - __ cmpptr(rbx, is_inline_type_mask); + __ andptr(rbx, is_value_type_mask); + __ cmpptr(rbx, is_value_type_mask); __ jcc(Assembler::notEqual, (cc == equal) ? not_taken : taken); // same value klass ? @@ -2972,7 +2972,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri __ pop(atos); if (is_static) { Label is_nullable; - __ test_field_is_not_null_free_inline_type(flags, rscratch1, is_nullable); + __ test_field_is_not_null_free_value_type(flags, rscratch1, is_nullable); __ null_check(rax); // FIXME JDK-8341120 __ bind(is_nullable); do_oop_store(_masm, field, rax); @@ -2980,7 +2980,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri } else { Label is_flat, null_free_reference, rewrite_inline; __ test_field_is_flat(flags, rscratch1, is_flat); - __ test_field_is_null_free_inline_type(flags, rscratch1, null_free_reference); + __ test_field_is_null_free_value_type(flags, rscratch1, null_free_reference); pop_and_check_object(obj); // Store into the field do_oop_store(_masm, field, rax); @@ -4048,9 +4048,9 @@ void TemplateTable::monitorenter() { // check for null object __ null_check(rax); - Label is_inline_type; + Label is_value_type; __ movptr(rbx, Address(rax, oopDesc::mark_offset_in_bytes())); - __ test_markword_is_inline_type(rbx, is_inline_type); + __ test_markword_is_value_type(rbx, is_value_type); const Address monitor_block_top( rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize); @@ -4145,7 +4145,7 @@ void TemplateTable::monitorenter() { // next instruction. __ dispatch_next(vtos); - __ bind(is_inline_type); + __ bind(is_value_type); __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_identity_exception), rax); __ should_not_reach_here(); @@ -4157,11 +4157,11 @@ void TemplateTable::monitorexit() { // check for null object __ null_check(rax); - const int is_inline_type_mask = markWord::inline_type_pattern; + const int is_value_type_mask = markWord::value_type_pattern; Label has_identity; __ movptr(rbx, Address(rax, oopDesc::mark_offset_in_bytes())); - __ andptr(rbx, is_inline_type_mask); - __ cmpl(rbx, is_inline_type_mask); + __ andptr(rbx, is_value_type_mask); + __ cmpl(rbx, is_value_type_mask); __ jcc(Assembler::notEqual, has_identity); __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception)); diff --git a/src/hotspot/cpu/x86/vtableStubs_x86_64.cpp b/src/hotspot/cpu/x86/vtableStubs_x86_64.cpp index f47d1ad2ad5b..9cd94636a774 100644 --- a/src/hotspot/cpu/x86/vtableStubs_x86_64.cpp +++ b/src/hotspot/cpu/x86/vtableStubs_x86_64.cpp @@ -61,7 +61,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index, bool caller_is_c1) int slop_delta = 0; // No variance was detected in vtable stub sizes. Setting index_dependent_slop == 0 will unveil any deviation from this observation. const int index_dependent_slop = 0; - ByteSize entry_offset = caller_is_c1 ? Method::from_compiled_inline_offset() : Method::from_compiled_inline_ro_offset(); + ByteSize entry_offset = caller_is_c1 ? Method::from_compiled_value_offset() : Method::from_compiled_value_ro_offset(); ResourceMark rm; CodeBuffer cb(s->entry_point(), stub_code_length); @@ -142,7 +142,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index, bool caller_is_c1) VtableStub* VtableStubs::create_itable_stub(int itable_index, bool caller_is_c1) { // Read "A word on VtableStub sizing" in share/code/vtableStubs.hpp for details on stub sizing. const int stub_code_length = code_size_limit(false); - ByteSize entry_offset = caller_is_c1 ? Method::from_compiled_inline_offset() : Method::from_compiled_inline_ro_offset(); + ByteSize entry_offset = caller_is_c1 ? Method::from_compiled_value_offset() : Method::from_compiled_value_ro_offset(); VtableStub* s = new(stub_code_length) VtableStub(false, itable_index, caller_is_c1); // Can be nullptr if there is no free space in the code cache. if (s == nullptr) { diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index e88013a50939..f48a7d0eb777 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -2600,9 +2600,9 @@ void MachVEPNode::emit(C2_MacroAssembler* masm, PhaseRegAlloc* ra_) const int initial_framesize = ra_->C->output()->frame_size_in_bytes() - 2*wordSize; __ remove_frame(initial_framesize, false); } - // Unpack inline type args passed as oop and then jump to + // Unpack value type args passed as oop and then jump to // the verified entry point (skipping the unverified entry). - int sp_inc = __ unpack_inline_args(ra_->C, _receiver_only); + int sp_inc = __ unpack_value_args(ra_->C, _receiver_only); // Emit code for verified entry and save increment for stack repair on return __ verified_entry(ra_->C, sp_inc); if (Compile::current()->output()->in_scratch_emit_size()) { @@ -3055,7 +3055,6 @@ bool Matcher::match_rule_supported(int opcode) { } // fallthrough case Op_AddHF: case Op_DivHF: - case Op_FmaHF: case Op_MulHF: case Op_ReinterpretS2HF: case Op_ReinterpretHF2S: @@ -3065,6 +3064,12 @@ bool Matcher::match_rule_supported(int opcode) { return false; } break; + case Op_FmaHF: + // UseFMA also needs to be checked along with AVX512-FP16. + if (!UseFMA || !VM_Version::supports_avx512_fp16()) { + return false; + } + break; case Op_VectorLoadShuffle: case Op_VectorRearrange: case Op_MulReductionVI: @@ -3178,6 +3183,7 @@ bool Matcher::match_rule_supported(int opcode) { case Op_FmaD: case Op_FmaVD: case Op_FmaVF: + case Op_FmaVHF: if (!UseFMA) { return false; } @@ -4615,7 +4621,7 @@ encode %{ __ int3(); __ bind(L); } - if (tf()->returns_inline_type_as_fields() && !_method->is_method_handle_intrinsic() && _method->return_type()->is_loaded()) { + if (tf()->returns_value_type_as_fields() && !_method->is_method_handle_intrinsic() && _method->return_type()->is_loaded()) { // The last return value is not set by the callee but used to pass the null marker to compiled code. // Search for the corresponding projection, get the register and emit code that initializes it. uint con = (tf()->range_cc()->cnt() - 1); @@ -4637,9 +4643,9 @@ encode %{ } } if (return_value_is_used()) { - // An inline type is returned as fields in multiple registers. - // Rax either contains an oop if the inline type is buffered or a pointer - // to the corresponding InlineKlass with the lowest bit set to 1. Zero rax + // A value type is returned as fields in multiple registers. + // Rax either contains an oop if the value type is buffered or a pointer + // to the corresponding ValueKlass with the lowest bit set to 1. Zero rax // if the lowest bit is set to allow C2 to use the oop after null checking. // rax &= (rax & 1) - 1 __ movptr(rscratch1, rax); @@ -4736,12 +4742,9 @@ frame // return address specifies a type (REG or STACK) and a number // representing the register number (i.e. - use a register name) or // stack slot. - // Ret Addr is on stack in slot 0 if no locks or verification or alignment. - // Otherwise, it is above the locks and verification slot and alignment word - return_addr(STACK - 2 + - align_up((Compile::current()->in_preserve_stack_slots() + - Compile::current()->fixed_slots()), - stack_alignment_in_slots())); + // Ret Addr is on stack 2 slots below _old_SP, i.e. in slot 0 if no locks + // or verification or alignment. + return_addr(STACK OptoReg::reg2stack(_old_SP) - 2); // Location of compiled Java return values. Same as C for now. return_value @@ -25249,6 +25252,7 @@ instruct scalar_fma_HF_reg(regF dst, regF src1, regF src2) match(Set dst (FmaHF dst (Binary src1 src2))); format %{ "scalar_fma_fp16 $dst, $src1, $src2\t# $dst = $src1 * $src2 + $dst fma packedH" %} ins_encode %{ + assert(UseFMA, "Needs FMA instructions support."); __ vfmadd231sh($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister); %} ins_pipe( pipe_slow ); @@ -25315,6 +25319,7 @@ instruct vector_fma_HF_reg(vec dst, vec src1, vec src2) match(Set dst (FmaVHF dst (Binary src1 src2))); format %{ "vector_fma_fp16 $dst, $src1, $src2\t# $dst = $src1 * $src2 + $dst fma packedH" %} ins_encode %{ + assert(UseFMA, "Needs FMA instructions support."); int vlen_enc = vector_length_encoding(this); __ evfmadd231ph($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, vlen_enc); %} @@ -25327,6 +25332,7 @@ instruct vector_fma_HF_mem(vec dst, vec src1, memory src2) match(Set dst (FmaVHF dst (Binary src1 (VectorReinterpret (LoadVector src2))))); format %{ "vector_fma_fp16_mem $dst, $src1, $src2\t# $dst = $src1 * $src2 + $dst fma packedH" %} ins_encode %{ + assert(UseFMA, "Needs FMA instructions support."); int vlen_enc = vector_length_encoding(this); __ evfmadd231ph($dst$$XMMRegister, $src1$$XMMRegister, $src2$$Address, vlen_enc); %} diff --git a/src/hotspot/cpu/zero/globals_zero.hpp b/src/hotspot/cpu/zero/globals_zero.hpp index 7a3917489f2e..ef9c2690cea2 100644 --- a/src/hotspot/cpu/zero/globals_zero.hpp +++ b/src/hotspot/cpu/zero/globals_zero.hpp @@ -73,8 +73,8 @@ define_pd_global(uintx, TypeProfileLevel, 0); define_pd_global(bool, PreserveFramePointer, false); -define_pd_global(bool, InlineTypePassFieldsAsArgs, false); -define_pd_global(bool, InlineTypeReturnedAsFields, false); +define_pd_global(bool, ValueTypePassFieldsAsArgs, false); +define_pd_global(bool, ValueTypeReturnedAsFields, false); define_pd_global(bool, CompactStrings, true); diff --git a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp index 45ad6e257193..e98a5777efba 100644 --- a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp +++ b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp @@ -51,7 +51,7 @@ int SharedRuntime::java_return_convention(const BasicType *sig_bt, return 0; } -BufferedInlineTypeBlob* SharedRuntime::generate_buffered_inline_type_adapter(const InlineKlass* vk) { +BufferedValueTypeBlob* SharedRuntime::generate_buffered_value_type_adapter(const ValueKlass* vk) { Unimplemented(); return nullptr; } @@ -143,7 +143,7 @@ int SharedRuntime::vector_calling_convention(VMRegPair *regs, } // Call here from the interpreter or compiled code to store returned -// values to a newly allocated inline type instance. +// values to a newly allocated value type instance. RuntimeStub* SharedRuntime::generate_return_value_stub(address destination) { Unimplemented(); return nullptr; diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 7cbfc2c821b4..28b3c3aab1e7 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -2010,6 +2010,36 @@ void os::print_os_info(outputStream* st) { VM_Version::print_platform_virtualization_info(st); } +static bool getWindowsInstallationType(char* buffer, int bufferSize) { + HKEY hKey; + const char* subKey = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"; + const char* valueName = "InstallationType"; + + DWORD valueLength = bufferSize; + + // Initialize buffer with empty string + buffer[0] = '\0'; + + // Open the registry key + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, subKey, 0, KEY_READ, &hKey) != ERROR_SUCCESS) { + // Return empty buffer if key cannot be opened + return false; + } + + // Query the value + if (RegQueryValueExA(hKey, valueName, nullptr, nullptr, (LPBYTE)buffer, &valueLength) != ERROR_SUCCESS) { + RegCloseKey(hKey); + buffer[0] = '\0'; + return false; + } + + // If the value being queried is a string the value returned is NOT guaranteed to be null-terminated + buffer[valueLength - 1] = '\0'; + + RegCloseKey(hKey); + return true; +} + void os::win32::print_windows_version(outputStream* st) { bool is_workstation = !IsWindowsServer(); @@ -2097,6 +2127,12 @@ void os::win32::print_windows_version(outputStream* st) { st->print(" Build %d", build_number); st->print(" (%d.%d.%d.%d)", major_version, minor_version, build_number, build_minor); + // InstallationType (e.g. Server Core, Nano server) + const int BUFFER_SIZE = 256; + char installationType[BUFFER_SIZE]; + if (getWindowsInstallationType(installationType, BUFFER_SIZE)) { + st->print(" InstallationType: \"%s\"", installationType); + } st->cr(); } @@ -4275,33 +4311,7 @@ int os::win32::_build_minor = 0; bool os::win32::_processor_group_warning_displayed = false; bool os::win32::_job_object_processor_group_warning_displayed = false; -void getWindowsInstallationType(char* buffer, int bufferSize) { - HKEY hKey; - const char* subKey = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"; - const char* valueName = "InstallationType"; - - DWORD valueLength = bufferSize; - - // Initialize buffer with empty string - buffer[0] = '\0'; - - // Open the registry key - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, subKey, 0, KEY_READ, &hKey) != ERROR_SUCCESS) { - // Return empty buffer if key cannot be opened - return; - } - - // Query the value - if (RegQueryValueExA(hKey, valueName, nullptr, nullptr, (LPBYTE)buffer, &valueLength) != ERROR_SUCCESS) { - RegCloseKey(hKey); - buffer[0] = '\0'; - return; - } - - RegCloseKey(hKey); -} - -bool isNanoServer() { +static bool isNanoServer() { const int BUFFER_SIZE = 256; char installationType[BUFFER_SIZE]; getWindowsInstallationType(installationType, BUFFER_SIZE); diff --git a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp index c83e10e5b278..936ee93515fa 100644 --- a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp +++ b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp @@ -208,6 +208,9 @@ void RiscvHwprobe::add_features_from_query_result() { if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZBB)) { VM_Version::ext_Zbb.enable_feature(); } + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZBC)) { + VM_Version::ext_Zbc.enable_feature(); + } #ifndef PRODUCT if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZBKB)) { VM_Version::ext_Zbkb.enable_feature(); diff --git a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp index c9556d32cc50..fa8c349f788a 100644 --- a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp +++ b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp @@ -285,10 +285,13 @@ void VM_Version::vendor_features() { } switch (mvendorid.value()) { case RIVOS: - rivos_features(); - break; + rivos_features(); + break; + case XUANTIE: + xuantie_features(); + break; default: - break; + break; } } @@ -324,3 +327,48 @@ void VM_Version::rivos_features() { ext_Zihintpause.enable_feature(); } } + +void VM_Version::xuantie_features() { + if (!marchid.enabled()) { + return; + } + + const uint64_t architecture_id = static_cast(marchid.value()); + if (architecture_id != C925_MARCHID && + architecture_id != C930_MARCHID && + architecture_id != C950_MARCHID) { + return; + } + + ext_v.enable_feature(); + ext_Zba.enable_feature(); + ext_Zbb.enable_feature(); + ext_Zbc.enable_feature(); + ext_Zbs.enable_feature(); + ext_Zcb.enable_feature(); + ext_Zfa.enable_feature(); + ext_Zfh.enable_feature(); + ext_Zfhmin.enable_feature(); + ext_Zicbom.enable_feature(); + ext_Zicbop.enable_feature(); + ext_Zicntr.enable_feature(); + ext_Zicsr.enable_feature(); + ext_Zic64b.enable_feature(); + ext_Zifencei.enable_feature(); + ext_Zihintpause.enable_feature(); + ext_Zvbb.enable_feature(); + ext_Zvbc.enable_feature(); + ext_Zvfh.enable_feature(); + ext_Zvkn.enable_feature(); + ext_Zvkg.enable_feature(); + +#ifndef PRODUCT + ext_Zacas.enable_feature(); + ext_Zicboz.enable_feature(); + ext_Zicond.enable_feature(); + ext_Ztso.enable_feature(); +#endif + + unaligned_scalar.enable_feature(MISALIGNED_SCALAR_FAST); + unaligned_vector.enable_feature(MISALIGNED_VECTOR_FAST); +} diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index 167f19a8fde7..3108f963daa2 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -1139,17 +1139,31 @@ const char *InstructForm::mach_base_class(FormDict &globals) const { return nullptr; } -// Compare the instruction predicates for textual equality -bool equivalent_predicates( const InstructForm *instr1, const InstructForm *instr2 ) { - const Predicate *pred1 = instr1->_predicate; - const Predicate *pred2 = instr2->_predicate; - if( pred1 == nullptr && pred2 == nullptr ) { +// Do the instruction predicates allow target_instr to be replaced by replacement_instr for cisc-spill optimzation. +static bool has_predicate_subset( const InstructForm *target_instr, const InstructForm *replacement_instr ) { + const Predicate *target_p = target_instr->_predicate; + const Predicate *replacement_p = replacement_instr->_predicate; + if( target_p == nullptr && replacement_p == nullptr ) { // no predicates means they are identical return true; } - if( pred1 != nullptr && pred2 != nullptr ) { + + #ifdef AMD64 + // A replacement_instr with no predicate handles a superset of the cases that target_instr handles. + // *Except* when target_instr has "predicate(false)", which shouldn't match anything. + // This is safe for x86 which only uses such predicates for instructions that should only be expanded + // as part of peephole optimizations. It's unclear if this is safe for s390 due to more complex predicates + // like "predicate(false && )". For now only enable for x86 (AMD64) + #define PREDICATE_FALSE_EXPR "#line 9\nfalse\n#line 9\n" + + if( replacement_p == nullptr && !ADLParser::equivalent_expressions(target_p->_pred, PREDICATE_FALSE_EXPR) ) { + return true; + } + #endif /* AMD64 */ + + if( target_p != nullptr && replacement_p != nullptr ) { // compare the predicates - if (ADLParser::equivalent_expressions(pred1->_pred, pred2->_pred)) { + if (ADLParser::equivalent_expressions(target_p->_pred, replacement_p->_pred)) { return true; } } @@ -1169,8 +1183,8 @@ bool InstructForm::cisc_spills_to(ArchDesc &AD, InstructForm *instr) { const char *op_name = nullptr; const char *reg_type = nullptr; FormDict &globals = AD.globalNames(); - cisc_spill_operand = _matrule->matchrule_cisc_spill_match(globals, AD.get_registers(), instr->_matrule, op_name, reg_type); - if( (cisc_spill_operand != Not_cisc_spillable) && (op_name != nullptr) && equivalent_predicates(this, instr) ) { + cisc_spill_operand = _matrule->matchrule_cisc_spill_match(globals, AD.get_registers(), instr->_matrule, op_name, reg_type, this, instr); + if( (cisc_spill_operand != Not_cisc_spillable) && (op_name != nullptr) && has_predicate_subset(this, instr) ) { cisc_spill_operand = operand_position(op_name, Component::USE); int def_oper = operand_position(op_name, Component::DEF); if( def_oper == NameList::Not_in_list && instr->num_opnds() == num_opnds()) { @@ -3699,7 +3713,8 @@ bool static root_ops_match(FormDict &globals, const char *op1, const char *op2) //-------------------------cisc_spill_match_node------------------------------- // Recursively check two MatchRules for legal conversion via cisc-spilling -int MatchNode::cisc_spill_match(FormDict& globals, RegisterForm* registers, MatchNode* mRule2, const char* &operand, const char* ®_type) { +int MatchNode::cisc_spill_match(FormDict& globals, RegisterForm* registers, MatchNode* mRule2, const char* &operand, const char* ®_type, + InstructForm *from_instr, InstructForm *to_instr) { int cisc_spillable = Maybe_cisc_spillable; int left_spillable = Maybe_cisc_spillable; int right_spillable = Maybe_cisc_spillable; @@ -3715,7 +3730,14 @@ int MatchNode::cisc_spill_match(FormDict& globals, RegisterForm* registers, Matc const Form *form = globals[_opType]; const Form *form2 = globals[mRule2->_opType]; if( form == form2 ) { - cisc_spillable = Maybe_cisc_spillable; + if (form->is_operand()) { + // Disallow cisc-spilling if only 1 operand is a DEF, or both are DEFs but at different positions. + // from_instr: andI_rReg_ndd, MatchRule: ( Set dst (AndI src1 src2) ). src1: (position(DEF) = -1, position(USE) = 1) + // to_instr: andI_rReg_mem, MatchRule: ( Set dst (AndI dst (LoadI src)) ). dst: (position(DEF) = 0, position(USE) = 1) + if (from_instr->operand_position(this->_name, Component::DEF) != to_instr->operand_position(mRule2->_name, Component::DEF)) { + cisc_spillable = Not_cisc_spillable; + } + } } else { const InstructForm *form2_inst = form2 ? form2->is_instruction() : nullptr; const char *name_left = mRule2->_lChild ? mRule2->_lChild->_opType : nullptr; @@ -3762,14 +3784,14 @@ int MatchNode::cisc_spill_match(FormDict& globals, RegisterForm* registers, Matc if( (_lChild == nullptr) && (mRule2->_lChild == nullptr) ) { left_spillable = Maybe_cisc_spillable; } else if (_lChild != nullptr) { - left_spillable = _lChild->cisc_spill_match(globals, registers, mRule2->_lChild, operand, reg_type); + left_spillable = _lChild->cisc_spill_match(globals, registers, mRule2->_lChild, operand, reg_type, from_instr, to_instr); } // Check right operands if( (_rChild == nullptr) && (mRule2->_rChild == nullptr) ) { right_spillable = Maybe_cisc_spillable; } else if (_rChild != nullptr) { - right_spillable = _rChild->cisc_spill_match(globals, registers, mRule2->_rChild, operand, reg_type); + right_spillable = _rChild->cisc_spill_match(globals, registers, mRule2->_rChild, operand, reg_type, from_instr, to_instr); } // Combine results of left and right checks @@ -3785,7 +3807,7 @@ int MatchNode::cisc_spill_match(FormDict& globals, RegisterForm* registers, Matc // general recursive checks done in MatchNode int MatchRule::matchrule_cisc_spill_match(FormDict& globals, RegisterForm* registers, MatchRule* mRule2, const char* &operand, - const char* ®_type) { + const char* ®_type, InstructForm *from_instr, InstructForm *to_instr) { int cisc_spillable = Maybe_cisc_spillable; int left_spillable = Maybe_cisc_spillable; int right_spillable = Maybe_cisc_spillable; @@ -3815,7 +3837,7 @@ int MatchRule::matchrule_cisc_spill_match(FormDict& globals, RegisterForm* regi assert(0, "_rChild should not be null"); } } else { - right_spillable = _rChild->cisc_spill_match(globals, registers, mRule2->_rChild, operand, reg_type); + right_spillable = _rChild->cisc_spill_match(globals, registers, mRule2->_rChild, operand, reg_type, from_instr, to_instr); } // Combine results of left and right checks diff --git a/src/hotspot/share/adlc/formssel.hpp b/src/hotspot/share/adlc/formssel.hpp index 085617cbfd73..7a87b7255981 100644 --- a/src/hotspot/share/adlc/formssel.hpp +++ b/src/hotspot/share/adlc/formssel.hpp @@ -1007,7 +1007,7 @@ class MatchNode : public Form { // Recursive version of check in MatchRule int cisc_spill_match(FormDict& globals, RegisterForm* registers, MatchNode* mRule2, const char* &operand, - const char* ®_type); + const char* ®_type, InstructForm *from_instr, InstructForm *to_instr); int cisc_spill_merge(int left_result, int right_result); virtual bool equivalent(FormDict& globals, MatchNode* mNode2); @@ -1068,7 +1068,7 @@ class MatchRule : public MatchNode { // Check if 'mRule2' is a cisc-spill variant of this MatchRule int matchrule_cisc_spill_match(FormDict &globals, RegisterForm* registers, MatchRule* mRule2, const char* &operand, - const char* ®_type); + const char* ®_type, InstructForm *from_instr, InstructForm *to_instr); // Check if 'mRule2' is equivalent to this MatchRule virtual bool equivalent(FormDict& globals, MatchNode* mRule2); diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp index 549b2cb20639..05d80c75b3ef 100644 --- a/src/hotspot/share/asm/codeBuffer.hpp +++ b/src/hotspot/share/asm/codeBuffer.hpp @@ -53,9 +53,9 @@ class CodeOffsets: public StackObj { public: enum Entries { Entry, Verified_Entry, - Inline_Entry, - Verified_Inline_Entry, - Verified_Inline_Entry_RO, + Value_Entry, + Verified_Value_Entry, + Verified_Value_Entry_RO, Frame_Complete, // Offset in the code where the frame setup is (for forte stackwalks) is complete OSR_Entry, Exceptions, // Offset where exception handler lives @@ -77,9 +77,9 @@ class CodeOffsets: public StackObj { CodeOffsets() { _values[Entry ] = 0; _values[Verified_Entry] = 0; - _values[Inline_Entry ] = 0; - _values[Verified_Inline_Entry ] = no_such_entry_point; - _values[Verified_Inline_Entry_RO] = no_such_entry_point; + _values[Value_Entry ] = 0; + _values[Verified_Value_Entry ] = no_such_entry_point; + _values[Verified_Value_Entry_RO] = no_such_entry_point; _values[Frame_Complete] = frame_never_safe; _values[OSR_Entry ] = 0; _values[Exceptions ] = -1; diff --git a/src/hotspot/share/asm/macroAssembler_common.cpp b/src/hotspot/share/asm/macroAssembler_common.cpp index 96f0b5f8a500..a406b5e18115 100644 --- a/src/hotspot/share/asm/macroAssembler_common.cpp +++ b/src/hotspot/share/asm/macroAssembler_common.cpp @@ -26,7 +26,7 @@ #include "asm/assembler.inline.hpp" #include "asm/macroAssembler.hpp" #include "jvm.h" -#include "oops/inlineKlass.inline.hpp" +#include "oops/valueKlass.inline.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/signature_cc.hpp" #ifdef COMPILER2 @@ -35,7 +35,7 @@ #endif void MacroAssembler::skip_unpacked_fields(const GrowableArray* sig, int& sig_index, VMRegPair* regs_from, int regs_from_count, int& from_index) { - ScalarizedInlineArgsStream stream(sig, sig_index, regs_from, regs_from_count, from_index); + ScalarizedValueArgsStream stream(sig, sig_index, regs_from, regs_from_count, from_index); VMReg reg; BasicType bt; while (stream.next(reg, bt)) {} @@ -44,7 +44,7 @@ void MacroAssembler::skip_unpacked_fields(const GrowableArray* sig, in } bool MacroAssembler::is_reg_in_unpacked_fields(const GrowableArray* sig, int sig_index, VMReg to, VMRegPair* regs_from, int regs_from_count, int from_index) { - ScalarizedInlineArgsStream stream(sig, sig_index, regs_from, regs_from_count, from_index); + ScalarizedValueArgsStream stream(sig, sig_index, regs_from, regs_from_count, from_index); VMReg reg; BasicType bt; while (stream.next(reg, bt)) { @@ -79,8 +79,8 @@ MacroAssembler::RegState* MacroAssembler::init_reg_state(VMRegPair* regs, int nu } #ifdef COMPILER2 -int MacroAssembler::unpack_inline_args(Compile* C, bool receiver_only) { - assert(C->has_scalarized_args(), "inline type argument scalarization is disabled"); +int MacroAssembler::unpack_value_args(Compile* C, bool receiver_only) { + assert(C->has_scalarized_args(), "value type argument scalarization is disabled"); ciMethod* method = C->method(); const GrowableArray* sig = method->get_sig_cc(); assert(sig != nullptr, "must have scalarized signature"); @@ -102,8 +102,8 @@ int MacroAssembler::unpack_inline_args(Compile* C, bool receiver_only) { } else { // Only unpack the receiver, all other arguments are already scalarized ciInstanceKlass* holder = method->holder(); - int rec_len = (holder->is_inlinetype() && method->is_scalarized_arg(0)) ? holder->as_inline_klass()->inline_arg_length() : 1; - // Copy scalarized signature but skip receiver and inline type delimiters + int rec_len = (holder->is_value_klass() && method->is_scalarized_arg(0)) ? holder->as_value_klass()->value_arg_length() : 1; + // Copy scalarized signature but skip receiver and value type delimiters for (int i = 0; i < sig->length(); i++) { if (SigEntry::skip_value_delimiters(sig, i) && rec_len <= 0) { sig_bt[args_passed++] = sig->at(i)._bt; @@ -122,25 +122,25 @@ int MacroAssembler::unpack_inline_args(Compile* C, bool receiver_only) { // Check if we need to extend the stack for unpacking int sp_inc = 0; if (args_on_stack_cc > args_on_stack) { - sp_inc = extend_stack_for_inline_args(args_on_stack_cc); + sp_inc = extend_stack_for_value_args(args_on_stack_cc); } - shuffle_inline_args(false, receiver_only, sig, - args_passed, args_on_stack, regs, // from - args_passed_cc, args_on_stack_cc, regs_cc, // to - sp_inc, noreg); + shuffle_value_args(false, receiver_only, sig, + args_passed, args_on_stack, regs, // from + args_passed_cc, args_on_stack_cc, regs_cc, // to + sp_inc, noreg); return sp_inc; } #endif // COMPILER2 -void MacroAssembler::shuffle_inline_args(bool is_packing, bool receiver_only, - const GrowableArray* sig, - int args_passed, int args_on_stack, VMRegPair* regs, - int args_passed_to, int args_on_stack_to, VMRegPair* regs_to, - int sp_inc, Register val_array) { +void MacroAssembler::shuffle_value_args(bool is_packing, bool receiver_only, + const GrowableArray* sig, + int args_passed, int args_on_stack, VMRegPair* regs, + int args_passed_to, int args_on_stack_to, VMRegPair* regs_to, + int sp_inc, Register val_array) { int max_stack = MAX2(args_on_stack + sp_inc/VMRegImpl::stack_slot_size, args_on_stack_to); RegState* reg_state = init_reg_state(regs, args_passed, sp_inc, max_stack); - // Emit code for packing/unpacking inline type arguments + // Emit code for packing/unpacking value type arguments // We try multiple times and eventually start spilling to resolve (circular) dependencies bool done = (args_passed_to == 0); for (int i = 0; i < 2*args_passed_to && !done; ++i) { @@ -157,7 +157,7 @@ void MacroAssembler::shuffle_inline_args(bool is_packing, bool receiver_only, assert(0 <= sig_index && sig_index < sig->length(), "index out of bounds"); if (spill) { // This call returns true IFF we should keep trying to spill in this round. - spill = shuffle_inline_args_spill(is_packing, sig, sig_index, regs, from_index, args_passed, + spill = shuffle_value_args_spill(is_packing, sig, sig_index, regs, from_index, args_passed, reg_state); } BasicType bt = sig->at(sig_index)._bt; @@ -174,18 +174,18 @@ void MacroAssembler::shuffle_inline_args(bool is_packing, bool receiver_only, } else if (is_packing) { assert(val_array != noreg, "must be"); VMReg reg_to = regs_to[to_index].first(); - done &= pack_inline_helper(sig, sig_index, vtarg_index, - regs, args_passed, from_index, reg_to, - reg_state, val_array); + done &= pack_value_helper(sig, sig_index, vtarg_index, + regs, args_passed, from_index, reg_to, + reg_state, val_array); vtarg_index++; to_index++; } else if (!receiver_only || (from_index == 0 && bt == T_VOID)) { VMReg from_reg = regs[from_index].first(); - done &= unpack_inline_helper(sig, sig_index, - from_reg, from_index, regs_to, args_passed_to, to_index, - reg_state); + done &= unpack_value_helper(sig, sig_index, + from_reg, from_index, regs_to, args_passed_to, to_index, + reg_state); if (from_index == -1 && sig_index != 0) { - // This can happen when we are confusing an empty inline type argument which is + // This can happen when we are confusing an empty value type argument which is // not counted in the scalarized signature for the receiver. Just ignore it. assert(receiver_only, "sanity"); from_index = 0; @@ -193,11 +193,11 @@ void MacroAssembler::shuffle_inline_args(bool is_packing, bool receiver_only, } } } - guarantee(done, "Could not resolve circular dependency when shuffling inline type arguments"); + guarantee(done, "Could not resolve circular dependency when shuffling value type arguments"); } -bool MacroAssembler::shuffle_inline_args_spill(bool is_packing, const GrowableArray* sig, int sig_index, - VMRegPair* regs_from, int from_index, int regs_from_count, RegState* reg_state) { +bool MacroAssembler::shuffle_value_args_spill(bool is_packing, const GrowableArray* sig, int sig_index, + VMRegPair* regs_from, int from_index, int regs_from_count, RegState* reg_state) { VMReg reg; if (!is_packing || SigEntry::skip_value_delimiters(sig, sig_index)) { reg = regs_from[from_index].first(); @@ -206,7 +206,7 @@ bool MacroAssembler::shuffle_inline_args_spill(bool is_packing, const GrowableAr return true; } } else { - ScalarizedInlineArgsStream stream(sig, sig_index, regs_from, regs_from_count, from_index); + ScalarizedValueArgsStream stream(sig, sig_index, regs_from, regs_from_count, from_index); VMReg from_reg; BasicType bt; bool found = false; @@ -219,7 +219,7 @@ bool MacroAssembler::shuffle_inline_args_spill(bool is_packing, const GrowableAr } } if (!found) { - // Spilling fields in this inline type arg won't break cycles + // Spilling fields in this value type arg won't break cycles return true; } } diff --git a/src/hotspot/share/asm/macroAssembler_common.hpp b/src/hotspot/share/asm/macroAssembler_common.hpp index b9552601d7e1..0bb3996d6c6b 100644 --- a/src/hotspot/share/asm/macroAssembler_common.hpp +++ b/src/hotspot/share/asm/macroAssembler_common.hpp @@ -40,24 +40,24 @@ bool is_reg_in_unpacked_fields(const GrowableArray* sig, int sig_index, VMReg to, VMRegPair* regs_from, int regs_from_count, int from_index); RegState* init_reg_state(VMRegPair* regs, int num_regs, int sp_inc, int max_stack); - int unpack_inline_args(Compile* C, bool receiver_only); - void shuffle_inline_args(bool is_packing, bool receiver_only, - const GrowableArray* sig, - int args_passed, int args_on_stack, VMRegPair* regs, - int args_passed_to, int args_on_stack_to, VMRegPair* regs_to, - int sp_inc, Register val_array); - bool shuffle_inline_args_spill(bool is_packing, const GrowableArray* sig, int sig_index, - VMRegPair* regs_from, int from_index, int regs_from_count, RegState* reg_state); + int unpack_value_args(Compile* C, bool receiver_only); + void shuffle_value_args(bool is_packing, bool receiver_only, + const GrowableArray* sig, + int args_passed, int args_on_stack, VMRegPair* regs, + int args_passed_to, int args_on_stack_to, VMRegPair* regs_to, + int sp_inc, Register val_array); + bool shuffle_value_args_spill(bool is_packing, const GrowableArray* sig, int sig_index, + VMRegPair* regs_from, int from_index, int regs_from_count, RegState* reg_state); - int store_inline_type_fields_to_buf(ciInlineKlass* vk, bool from_interpreter = true); + int store_value_type_fields_to_buf(ciValueKlass* vk, bool from_interpreter = true); bool move_helper(VMReg from, VMReg to, BasicType bt, RegState reg_state[]); - bool unpack_inline_helper(const GrowableArray* sig, int& sig_index, - VMReg from, int& from_index, VMRegPair* to, int to_count, int& to_index, - RegState reg_state[]); - bool pack_inline_helper(const GrowableArray* sig, int& sig_index, int vtarg_index, - VMRegPair* from, int from_count, int& from_index, VMReg to, - RegState reg_state[], Register val_array); - int extend_stack_for_inline_args(int args_on_stack); + bool unpack_value_helper(const GrowableArray* sig, int& sig_index, + VMReg from, int& from_index, VMRegPair* to, int to_count, int& to_index, + RegState reg_state[]); + bool pack_value_helper(const GrowableArray* sig, int& sig_index, int vtarg_index, + VMRegPair* from, int from_count, int& from_index, VMReg to, + RegState reg_state[], Register val_array); + int extend_stack_for_value_args(int args_on_stack); void remove_frame(int initial_framesize, bool needs_stack_repair); VMReg spill_reg_for(VMReg reg); diff --git a/src/hotspot/share/c1/c1_Canonicalizer.cpp b/src/hotspot/share/c1/c1_Canonicalizer.cpp index 52e6d4966521..0187621a63c1 100644 --- a/src/hotspot/share/c1/c1_Canonicalizer.cpp +++ b/src/hotspot/share/c1/c1_Canonicalizer.cpp @@ -646,7 +646,7 @@ void Canonicalizer::do_CheckCast (CheckCast* x) { // Interface casts can't be statically optimized away since verifier doesn't // enforce interface types in bytecode. if (!is_interface && klass->is_subtype_of(x->klass())) { - assert(!x->klass()->is_inlinetype() || x->klass() == klass, "Inline klasses can't have subtypes"); + assert(!x->klass()->is_value_klass() || x->klass() == klass, "Value klasses can't have subtypes"); set_canonical(obj); return; } @@ -724,9 +724,17 @@ void Canonicalizer::do_If(If* x) { return; } - // Simplify further when we have two constants. However, if we have a substitutability check - // we must not constant fold as this would loose the substitutability semantics. - if (lt->is_constant() && rt->is_constant() && !x->substitutability_check()) { + // Simplify further when we have two constants. + if (lt->is_constant() && rt->is_constant()) { + const ciType* l_exact_type = l->exact_type(); + const ciType* r_exact_type = r->exact_type(); + if (l_exact_type != nullptr && l_exact_type->is_value_klass() && + r_exact_type != nullptr && r_exact_type->is_value_klass() && x->substitutability_check()) { + // If we have a substitutability check and both sides are known value types we must + // preserve it instead of performing a pointer comparison during compile time. + return; + } + if (x->x()->as_Constant() != nullptr) { // pattern: If (lc cond rc) => simplify to: Goto BlockBegin* sux = x->x()->as_Constant()->compare(x->cond(), x->y(), @@ -801,6 +809,10 @@ void Canonicalizer::do_If(If* x) { void Canonicalizer::do_TableSwitch(TableSwitch* x) { + // Keep the switch if we are profiling it + if (compilation()->profile_switches()) { + return; + } if (x->tag()->type()->is_constant()) { int v = x->tag()->type()->as_IntConstant()->value(); BlockBegin* sux = x->default_sux(); @@ -813,6 +825,10 @@ void Canonicalizer::do_TableSwitch(TableSwitch* x) { void Canonicalizer::do_LookupSwitch(LookupSwitch* x) { + // Keep the switch if we are profiling it + if (compilation()->profile_switches()) { + return; + } if (x->tag()->type()->is_constant()) { int v = x->tag()->type()->as_IntConstant()->value(); BlockBegin* sux = x->default_sux(); diff --git a/src/hotspot/share/c1/c1_Compilation.hpp b/src/hotspot/share/c1/c1_Compilation.hpp index 605d3e4c353b..f5001922ddc6 100644 --- a/src/hotspot/share/c1/c1_Compilation.hpp +++ b/src/hotspot/share/c1/c1_Compilation.hpp @@ -263,6 +263,10 @@ class Compilation: public StackObj { bool profile_acmp() { return is_profiling() && profile_branches() && MethodData::profile_acmp(); } + bool profile_switches() { + return env()->comp_level() == CompLevel_full_profile && + UseSwitchProfiling; + } // will compilation make optimistic assumptions that might lead to // deoptimization and that the runtime will account for? diff --git a/src/hotspot/share/c1/c1_Compiler.cpp b/src/hotspot/share/c1/c1_Compiler.cpp index d6cabf13d0c9..254c9ef81f95 100644 --- a/src/hotspot/share/c1/c1_Compiler.cpp +++ b/src/hotspot/share/c1/c1_Compiler.cpp @@ -225,7 +225,7 @@ bool Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_updateCRC32: case vmIntrinsics::_updateBytesCRC32: case vmIntrinsics::_updateByteBufferCRC32: -#if defined(S390) || defined(PPC64) || defined(AARCH64) || defined(AMD64) +#if defined(S390) || defined(PPC64) || defined(AARCH64) || defined(AMD64) || defined(RISCV64) case vmIntrinsics::_updateBytesCRC32C: case vmIntrinsics::_updateDirectByteBufferCRC32C: #endif diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp index a60a7619f208..fd512807719c 100644 --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp @@ -32,11 +32,11 @@ #include "ci/ciCallSite.hpp" #include "ci/ciField.hpp" #include "ci/ciFlatArrayKlass.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciKlass.hpp" #include "ci/ciMemberName.hpp" #include "ci/ciSymbols.hpp" #include "ci/ciUtilities.inline.hpp" +#include "ci/ciValueKlass.hpp" #include "classfile/javaClasses.hpp" #include "compiler/compilationPolicy.hpp" #include "compiler/compileBroker.hpp" @@ -1082,7 +1082,7 @@ void GraphBuilder::load_indexed(BasicType type) { if (array->is_loaded_flat_array()) { ciType* array_type = array->declared_type(); ciFlatArrayKlass* array_klass = array_type->as_flat_array_klass(); - ciInlineKlass* elem_klass = array_klass->element_klass()->as_inline_klass(); + ciValueKlass* elem_klass = array_klass->element_klass()->as_value_klass(); bool can_delay_access = false; ciBytecodeStream s(method()); @@ -1097,10 +1097,10 @@ void GraphBuilder::load_indexed(BasicType type) { !next_field->will_link(method(), Bytecodes::_getfield) || PatchALot; bool needs_atomic_access = array_klass->is_elem_atomic(); - // Offset adjustment for delayed reads requires a concrete inline holder - bool next_holder_is_inlinetype = next_holder->is_inlinetype(); + // Offset adjustment for delayed reads requires a concrete value holder + bool next_holder_is_value_klass = next_holder->is_value_klass(); can_delay_access = is_null_free && C1UseDelayedFlattenedFieldReads && - !next_needs_patching && !needs_atomic_access && next_holder_is_inlinetype; + !next_needs_patching && !needs_atomic_access && next_holder_is_value_klass; } if (can_delay_access) { // potentially optimizable array access, storing information for delayed decision @@ -1381,8 +1381,8 @@ void GraphBuilder::if_node(Value x, If::Condition cond, Value y, ValueStack* sta if (left_klass == nullptr || right_klass == nullptr) { // The klass is still unloaded, or came from a Phi node. Go slow case; subst_check = true; - } else if (left_klass->can_be_inline_klass() || right_klass->can_be_inline_klass()) { - // Either operand may be a value object, but we're not sure. Go slow case; + } else if (left_klass->can_be_value_klass() && right_klass->can_be_value_klass()) { + // Both operands may be a value object, but we're not sure. Go slow case; subst_check = true; } else { // No need to do substitutability check @@ -1803,12 +1803,12 @@ Value GraphBuilder::make_constant(ciConstant field_value, ciField* field) { } } -void GraphBuilder::copy_inline_content(ciInlineKlass* vk, Value src, int src_off, Value dest, int dest_off, ValueStack* state_before, ciField* enclosing_field) { +void GraphBuilder::copy_inline_content(ciValueKlass* vk, Value src, int src_off, Value dest, int dest_off, ValueStack* state_before, ciField* enclosing_field) { for (int i = 0; i < vk->nof_declared_nonstatic_fields(); i++) { ciField* field = vk->declared_nonstatic_field_at(i); int offset = field->offset_in_bytes() - vk->payload_offset(); if (field->is_flat()) { - copy_inline_content(field->type()->as_inline_klass(), src, src_off + offset, dest, dest_off + offset, state_before, enclosing_field); + copy_inline_content(field->type()->as_value_klass(), src, src_off + offset, dest, dest_off + offset, state_before, enclosing_field); if (!field->is_null_free()) { // Nullable, copy the null marker using Unsafe because null markers are not real fields int null_marker_offset = field->null_marker_offset() - vk->payload_offset(); @@ -1905,7 +1905,7 @@ void GraphBuilder::access_field(Bytecodes::Code code) { ciType* field_type = field->type(); if (field_type->is_loaded() && field->empty_null_free_initialized_value_field(!method()->is_class_initializer())) { - // Storing to an empty, null-free inline type field that is already initialized. Ignore. + // Storing to an empty, null-free value type field that is already initialized. Ignore. break; } } @@ -1951,13 +1951,13 @@ void GraphBuilder::access_field(Bytecodes::Code code) { if (has_pending_field_access()) { assert(!needs_patching, "Can't patch delayed field access"); obj = pending_field_access()->obj(); - offset += pending_field_access()->offset() - field->holder()->as_inline_klass()->payload_offset(); + offset += pending_field_access()->offset() - field->holder()->as_value_klass()->payload_offset(); field = pending_field_access()->holder()->get_field_by_offset(offset, false); assert(field != nullptr, "field not found"); set_pending_field_access(nullptr); } else if (has_pending_load_indexed()) { assert(!needs_patching, "Can't patch delayed field access"); - pending_load_indexed()->update(field, offset - field->holder()->as_inline_klass()->payload_offset()); + pending_load_indexed()->update(field, offset - field->holder()->as_value_klass()->payload_offset()); LoadIndexed* li = pending_load_indexed()->load_instr(); li->set_type(type); push(type, append(li)); @@ -1990,8 +1990,8 @@ void GraphBuilder::access_field(Bytecodes::Code code) { } } else { // Flat field - assert(!needs_patching, "Can't patch flat inline type field access"); - ciInlineKlass* inline_klass = field->type()->as_inline_klass(); + assert(!needs_patching, "Can't patch flat value type field access"); + ciValueKlass* value_klass = field->type()->as_value_klass(); if (field->is_atomic()) { assert(!has_pending_field_access(), "Pending field accesses are not supported"); LoadField* load = new LoadField(obj, offset, field, false, state_before, needs_patching); @@ -2011,10 +2011,10 @@ void GraphBuilder::access_field(Bytecodes::Code code) { PatchALot; // We can't update the offset for atomic accesses bool next_needs_atomic_access = next_field->is_flat() && next_field->is_atomic(); - // Offset adjustment for delayed reads requires a concrete inline holder - bool next_holder_is_inlinetype = next_holder->is_inlinetype(); + // Offset adjustment for delayed reads requires a concrete value holder + bool next_holder_is_value_klass = next_holder->is_value_klass(); can_delay_access = C1UseDelayedFlattenedFieldReads && !next_needs_patching && !next_needs_atomic_access && - next_field->is_null_free() && next_holder_is_inlinetype; + next_field->is_null_free() && next_holder_is_value_klass; } } @@ -2022,9 +2022,9 @@ void GraphBuilder::access_field(Bytecodes::Code code) { // Flat fields contain the nested value's payload but not its object header, // so accumulate the field offset relative to the holder's payload. if (has_pending_load_indexed()) { - pending_load_indexed()->update(field, offset - field->holder()->as_inline_klass()->payload_offset()); + pending_load_indexed()->update(field, offset - field->holder()->as_value_klass()->payload_offset()); } else if (has_pending_field_access()) { - pending_field_access()->inc_offset(offset - field->holder()->as_inline_klass()->payload_offset()); + pending_field_access()->inc_offset(offset - field->holder()->as_value_klass()->payload_offset()); } else { null_check(obj); DelayedFieldAccess* dfa = new DelayedFieldAccess(obj, field->holder(), field->offset_in_bytes(), state_before); @@ -2038,8 +2038,8 @@ void GraphBuilder::access_field(Bytecodes::Code code) { if (has_pending_load_indexed()) { assert(field->is_null_free(), "nullable fields do not support delayed accesses yet"); assert(!needs_patching, "Can't patch delayed field access"); - pending_load_indexed()->update(field, offset - field->holder()->as_inline_klass()->payload_offset()); - NewInstance* buffer = new NewInstance(inline_klass, pending_load_indexed()->state_before(), false, true); + pending_load_indexed()->update(field, offset - field->holder()->as_value_klass()->payload_offset()); + NewInstance* buffer = new NewInstance(value_klass, pending_load_indexed()->state_before(), false, true); buffer->set_null_free(true); _memory->new_instance(buffer); pending_load_indexed()->load_instr()->set_buffer(buffer); @@ -2049,36 +2049,36 @@ void GraphBuilder::access_field(Bytecodes::Code code) { } else if (has_pending_field_access()) { assert(field->is_null_free(), "nullable fields do not support delayed accesses yet"); state_before = pending_field_access()->state_before(); - NewInstance* buffer = new NewInstance(inline_klass, state_before, false, true); + NewInstance* buffer = new NewInstance(value_klass, state_before, false, true); _memory->new_instance(buffer); apush(append_split(buffer)); - copy_inline_content(inline_klass, pending_field_access()->obj(), - pending_field_access()->offset() + field->offset_in_bytes() - field->holder()->as_inline_klass()->payload_offset(), - buffer, inline_klass->payload_offset(), state_before); + copy_inline_content(value_klass, pending_field_access()->obj(), + pending_field_access()->offset() + field->offset_in_bytes() - field->holder()->as_value_klass()->payload_offset(), + buffer, value_klass->payload_offset(), state_before); set_pending_field_access(nullptr); } else { - if (!field->is_null_free() && !inline_klass->is_initialized()) { - // Cannot allocate an instance of inline_klass because it may have not been + if (!field->is_null_free() && !value_klass->is_initialized()) { + // Cannot allocate an instance of value_klass because it may have not been // initialized, bailout for now bailout("load from an uninitialized nullable non-atomic flat field"); return; } - NewInstance* buffer = new NewInstance(inline_klass, state_before, false, true); + NewInstance* buffer = new NewInstance(value_klass, state_before, false, true); _memory->new_instance(buffer); append_split(buffer); - if (inline_klass->is_initialized() && inline_klass->is_empty()) { + if (value_klass->is_initialized() && value_klass->is_empty()) { // Needs an explicit null check because below code does not perform any actual load if there are no fields null_check(obj); } - copy_inline_content(inline_klass, obj, field->offset_in_bytes(), buffer, inline_klass->payload_offset(), state_before); + copy_inline_content(value_klass, obj, field->offset_in_bytes(), buffer, value_klass->payload_offset(), state_before); Instruction* result = buffer; if (!field->is_null_free()) { Value int_zero = append(new Constant(intZero)); Value object_null = append(new Constant(objectNull)); - Value nm_offset = append(new Constant(new LongConstant(offset + inline_klass->null_marker_offset_in_payload()))); + Value nm_offset = append(new Constant(new LongConstant(offset + value_klass->null_marker_offset_in_payload()))); Value nm = append(new UnsafeGet(T_BOOLEAN, obj, nm_offset, false)); result = append(new IfOp(nm, Instruction::neq, int_zero, buffer, object_null, state_before, false)); } @@ -2108,7 +2108,7 @@ void GraphBuilder::access_field(Bytecodes::Code code) { ciType* field_type = field->type(); if (field_type->is_loaded() && field->empty_null_free_initialized_value_field(!method()->is_object_constructor())) { - // Storing to an empty, null-free inline type field that is already initialized. Ignore. + // Storing to an empty, null-free value type field that is already initialized. Ignore. null_check(obj); null_check(val); } else if (!field->is_flat()) { @@ -2122,18 +2122,18 @@ void GraphBuilder::access_field(Bytecodes::Code code) { } } else { // Flat field - assert(!needs_patching, "Can't patch flat inline type field access"); - ciInlineKlass* inline_klass = field_type->as_inline_klass(); + assert(!needs_patching, "Can't patch flat value type field access"); + ciValueKlass* value_klass = field_type->as_value_klass(); if (field->is_atomic()) { if (field->is_null_free()) { null_check(val); } append(new StoreField(obj, offset, field, val, false, state_before, needs_patching)); } else if (field->is_null_free()) { - assert(!inline_klass->is_empty(), "should have been handled"); - copy_inline_content(inline_klass, val, inline_klass->payload_offset(), obj, offset, state_before, field); + assert(!value_klass->is_empty(), "should have been handled"); + copy_inline_content(value_klass, val, value_klass->payload_offset(), obj, offset, state_before, field); } else { - if (!inline_klass->is_initialized()) { + if (!value_klass->is_initialized()) { // null_reset_value is not available, bailout for now bailout("store to an uninitialized nullable non-atomic flat field"); return; @@ -2141,15 +2141,15 @@ void GraphBuilder::access_field(Bytecodes::Code code) { // Store the subfields when field is a nullable non-atomic field Value object_null = append(new Constant(objectNull)); - Value null_reset_value = append(new Constant(new ObjectConstant(inline_klass->get_null_reset_value().as_object()))); + Value null_reset_value = append(new Constant(new ObjectConstant(value_klass->get_null_reset_value().as_object()))); Value src = append(new IfOp(val, Instruction::neq, object_null, val, null_reset_value, state_before, false)); - copy_inline_content(inline_klass, src, inline_klass->payload_offset(), obj, offset, state_before); + copy_inline_content(value_klass, src, value_klass->payload_offset(), obj, offset, state_before); // Store the null marker Value int_one = append(new Constant(new IntConstant(1))); Value int_zero = append(new Constant(intZero)); Value nm = append(new IfOp(val, Instruction::neq, object_null, int_one, int_zero, state_before, false)); - Value nm_offset = append(new Constant(new LongConstant(offset + inline_klass->null_marker_offset_in_payload()))); + Value nm_offset = append(new Constant(new LongConstant(offset + value_klass->null_marker_offset_in_payload()))); append(new UnsafePut(T_BOOLEAN, obj, nm_offset, nm, false)); } } @@ -2610,28 +2610,28 @@ void GraphBuilder::instance_of(int klass_index) { void GraphBuilder::monitorenter(Value x, int bci) { - bool maybe_inlinetype = false; + bool maybe_valuetype = false; if (bci == InvocationEntryBci) { // Called by GraphBuilder::inline_sync_entry. #ifdef ASSERT ciType* obj_type = x->declared_type(); - assert(obj_type == nullptr || !obj_type->is_inlinetype(), "inline types cannot have synchronized methods"); + assert(obj_type == nullptr || !obj_type->is_value_klass(), "value types cannot have synchronized methods"); #endif } else { // We are compiling a monitorenter bytecode if (Arguments::is_valhalla_enabled()) { ciType* obj_type = x->declared_type(); - if (obj_type == nullptr || obj_type->can_be_inline_klass()) { - // If we're (possibly) locking on an inline type, check for markWord::always_locked_pattern + if (obj_type == nullptr || obj_type->can_be_value_klass()) { + // If we're (possibly) locking on a value type, check for markWord::always_locked_pattern // and throw IMSE. (obj_type is null for Phi nodes, so let's just be conservative). - maybe_inlinetype = true; + maybe_valuetype = true; } } } // save state before locking in case of deoptimization after a NullPointerException ValueStack* state_before = copy_state_for_exception_with_bci(bci); - append_with_bci(new MonitorEnter(x, state()->lock(x), state_before, maybe_inlinetype), bci); + append_with_bci(new MonitorEnter(x, state()->lock(x), state_before, maybe_valuetype), bci); kill_all(); } diff --git a/src/hotspot/share/c1/c1_GraphBuilder.hpp b/src/hotspot/share/c1/c1_GraphBuilder.hpp index 5fcde20964ba..9251f496db65 100644 --- a/src/hotspot/share/c1/c1_GraphBuilder.hpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.hpp @@ -298,8 +298,8 @@ class GraphBuilder { void new_multi_array(int dimensions); void throw_op(int bci); - // inline types - void copy_inline_content(ciInlineKlass* vk, Value src, int src_off, Value dest, int dest_off, ValueStack* state_before, ciField* enclosing_field = nullptr); + // value types + void copy_inline_content(ciValueKlass* vk, Value src, int src_off, Value dest, int dest_off, ValueStack* state_before, ciField* enclosing_field = nullptr); // stack/code manipulation helpers Instruction* append_with_bci(Instruction* instr, int bci); diff --git a/src/hotspot/share/c1/c1_Instruction.cpp b/src/hotspot/share/c1/c1_Instruction.cpp index 50b99e313a4a..80a7bdcd742a 100644 --- a/src/hotspot/share/c1/c1_Instruction.cpp +++ b/src/hotspot/share/c1/c1_Instruction.cpp @@ -27,9 +27,9 @@ #include "c1/c1_IR.hpp" #include "c1/c1_ValueStack.hpp" #include "ci/ciFlatArrayKlass.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciObjArrayKlass.hpp" #include "ci/ciTypeArrayKlass.hpp" +#include "ci/ciValueKlass.hpp" #include "utilities/bitMap.inline.hpp" @@ -144,7 +144,7 @@ bool Instruction::maybe_flat_array() const { } else if (type->is_obj_array_klass()) { // This is the unrefined array type ciKlass* element_klass = type->as_obj_array_klass()->element_klass(); - if (element_klass->can_be_inline_klass() && (!element_klass->is_inlinetype() || element_klass->as_inline_klass()->maybe_flat_in_array())) { + if (element_klass->can_be_value_klass() && (!element_klass->is_value_klass() || element_klass->as_value_klass()->maybe_flat_in_array())) { return true; } } else if (type->is_klass() && type->as_klass()->is_java_lang_Object()) { @@ -167,7 +167,7 @@ bool Instruction::maybe_null_free_array() const { return type->as_array_klass()->is_elem_null_free(); } else if (type->is_obj_array_klass()) { // Due to array covariance, the runtime type might be a null-free array. - if (type->as_obj_array_klass()->can_be_inline_array_klass()) { + if (type->as_obj_array_klass()->can_be_value_array_klass()) { return true; } } diff --git a/src/hotspot/share/c1/c1_Instruction.hpp b/src/hotspot/share/c1/c1_Instruction.hpp index a823f8c15859..59ae95f23521 100644 --- a/src/hotspot/share/c1/c1_Instruction.hpp +++ b/src/hotspot/share/c1/c1_Instruction.hpp @@ -1579,18 +1579,18 @@ BASE(AccessMonitor, StateSplit) LEAF(MonitorEnter, AccessMonitor) - bool _maybe_inlinetype; + bool _maybe_valuetype; public: // creation - MonitorEnter(Value obj, int monitor_no, ValueStack* state_before, bool maybe_inlinetype) + MonitorEnter(Value obj, int monitor_no, ValueStack* state_before, bool maybe_valuetype) : AccessMonitor(obj, monitor_no, state_before) - , _maybe_inlinetype(maybe_inlinetype) + , _maybe_valuetype(maybe_valuetype) { ASSERT_VALUES } // accessors - bool maybe_inlinetype() const { return _maybe_inlinetype; } + bool maybe_valuetype() const { return _maybe_valuetype; } // generic virtual bool can_trap() const { return true; } diff --git a/src/hotspot/share/c1/c1_InstructionPrinter.cpp b/src/hotspot/share/c1/c1_InstructionPrinter.cpp index 35a7b3dc2b31..481a74f31a5d 100644 --- a/src/hotspot/share/c1/c1_InstructionPrinter.cpp +++ b/src/hotspot/share/c1/c1_InstructionPrinter.cpp @@ -25,7 +25,6 @@ #include "c1/c1_InstructionPrinter.hpp" #include "c1/c1_ValueStack.hpp" #include "ci/ciArray.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciInstance.hpp" #include "ci/ciObject.hpp" #include "classfile/vmSymbols.hpp" diff --git a/src/hotspot/share/c1/c1_LIR.cpp b/src/hotspot/share/c1/c1_LIR.cpp index 65b28be7911d..79b415a60f9f 100644 --- a/src/hotspot/share/c1/c1_LIR.cpp +++ b/src/hotspot/share/c1/c1_LIR.cpp @@ -27,8 +27,8 @@ #include "c1/c1_LIR.hpp" #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_ValueStack.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciInstance.hpp" +#include "ci/ciValueKlass.hpp" #include "runtime/safepointMechanism.inline.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/vm_version.hpp" @@ -976,14 +976,14 @@ void LIR_OpVisitState::visit(LIR_Op* op) { break; } - // LIR_OpProfileInlineType: - case lir_profile_inline_type: { - assert(op->as_OpProfileInlineType() != nullptr, "must be"); - LIR_OpProfileInlineType* opProfileInlineType = (LIR_OpProfileInlineType*)op; + // LIR_OpProfileValueType: + case lir_profile_value_type: { + assert(op->as_OpProfileValueType() != nullptr, "must be"); + LIR_OpProfileValueType* opProfileValueType = (LIR_OpProfileValueType*)op; - do_input(opProfileInlineType->_mdp); do_temp(opProfileInlineType->_mdp); - do_input(opProfileInlineType->_obj); - do_temp(opProfileInlineType->_tmp); + do_input(opProfileValueType->_mdp); do_temp(opProfileValueType->_mdp); + do_input(opProfileValueType->_obj); + do_temp(opProfileValueType->_tmp); break; } default: @@ -1059,11 +1059,11 @@ void LIR_OpJavaCall::emit_code(LIR_Assembler* masm) { masm->emit_call(this); } -bool LIR_OpJavaCall::maybe_return_as_fields(ciInlineKlass** vk_ret) const { +bool LIR_OpJavaCall::maybe_return_as_fields(ciValueKlass** vk_ret) const { ciType* return_type = method()->return_type(); - if (InlineTypeReturnedAsFields) { - if (return_type->is_inlinetype()) { - ciInlineKlass* vk = return_type->as_inline_klass(); + if (ValueTypeReturnedAsFields) { + if (return_type->is_value_klass()) { + ciValueKlass* vk = return_type->as_value_klass(); if (vk->can_be_returned_as_fields()) { if (vk_ret != nullptr) { *vk_ret = vk; @@ -1073,12 +1073,12 @@ bool LIR_OpJavaCall::maybe_return_as_fields(ciInlineKlass** vk_ret) const { } else if (return_type->is_instance_klass() && (method()->is_method_handle_intrinsic() || !return_type->is_loaded() || StressCallingConvention)) { - // An inline type might be returned from the call but we don't know its type. + // A value type might be returned from the call but we don't know its type. // This can happen with method handle intrinsics or when the return type is // not loaded (method holder is not loaded or preload attribute is missing). - // If an inline type is returned, we either get an oop to a buffer and nothing + // If a value type is returned, we either get an oop to a buffer and nothing // needs to be done or one of the values being returned is the klass of the - // inline type (RAX on x64, with LSB set to 1) and we need to allocate an inline + // value type (RAX on x64, with LSB set to 1) and we need to allocate a value // type instance of that type and initialize it with the fields values being // returned in other registers. return true; @@ -1205,8 +1205,8 @@ void LIR_OpProfileType::emit_code(LIR_Assembler* masm) { masm->emit_profile_type(this); } -void LIR_OpProfileInlineType::emit_code(LIR_Assembler* masm) { - masm->emit_profile_inline_type(this); +void LIR_OpProfileValueType::emit_code(LIR_Assembler* masm) { + masm->emit_profile_value_type(this); } // LIR_List @@ -1928,8 +1928,8 @@ const char * LIR_Op::name() const { case lir_profile_call: s = "profile_call"; break; // LIR_OpProfileType case lir_profile_type: s = "profile_type"; break; - // LIR_OpProfileInlineType - case lir_profile_inline_type: s = "profile_inline_type"; break; + // LIR_OpProfileValueType + case lir_profile_value_type: s = "profile_value_type"; break; // LIR_OpAssert #ifdef ASSERT case lir_assert: s = "assert"; break; @@ -2260,8 +2260,8 @@ void LIR_OpProfileType::print_instr(outputStream* out) const { tmp()->print(out); out->print(" "); } -// LIR_OpProfileInlineType -void LIR_OpProfileInlineType::print_instr(outputStream* out) const { +// LIR_OpProfileValueType +void LIR_OpProfileValueType::print_instr(outputStream* out) const { out->print(" flag = %x ", flag()); mdp()->print(out); out->print(" "); obj()->print(out); out->print(" "); diff --git a/src/hotspot/share/c1/c1_LIR.hpp b/src/hotspot/share/c1/c1_LIR.hpp index 91a80bfdd12e..5f2a0bcbd843 100644 --- a/src/hotspot/share/c1/c1_LIR.hpp +++ b/src/hotspot/share/c1/c1_LIR.hpp @@ -896,7 +896,7 @@ class LIR_OpCompareAndSwap; class LIR_OpLoadKlass; class LIR_OpProfileCall; class LIR_OpProfileType; -class LIR_OpProfileInlineType; +class LIR_OpProfileValueType; #ifdef ASSERT class LIR_OpAssert; #endif @@ -1011,7 +1011,7 @@ enum LIR_Code { , begin_opMDOProfile , lir_profile_call , lir_profile_type - , lir_profile_inline_type + , lir_profile_value_type , end_opMDOProfile , begin_opAssert , lir_assert @@ -1157,7 +1157,7 @@ class LIR_Op: public CompilationResourceObj { virtual LIR_OpLoadKlass* as_OpLoadKlass() { return nullptr; } virtual LIR_OpProfileCall* as_OpProfileCall() { return nullptr; } virtual LIR_OpProfileType* as_OpProfileType() { return nullptr; } - virtual LIR_OpProfileInlineType* as_OpProfileInlineType() { return nullptr; } + virtual LIR_OpProfileValueType* as_OpProfileValueType() { return nullptr; } #ifdef ASSERT virtual LIR_OpAssert* as_OpAssert() { return nullptr; } #endif @@ -1228,7 +1228,7 @@ class LIR_OpJavaCall: public LIR_OpCall { virtual LIR_OpJavaCall* as_OpJavaCall() { return this; } virtual void print_instr(outputStream* out) const PRODUCT_RETURN; - bool maybe_return_as_fields(ciInlineKlass** vk = nullptr) const; + bool maybe_return_as_fields(ciValueKlass** vk = nullptr) const; }; // -------------------------------------------------- @@ -1281,8 +1281,8 @@ class LIR_OpArrayCopy: public LIR_Op { src_objarray = 1 << 10, dst_objarray = 1 << 11, always_slow_path = 1 << 12, - src_inlinetype_check = 1 << 13, - dst_inlinetype_check = 1 << 14, + src_valuetype_check = 1 << 13, + dst_valuetype_check = 1 << 14, all_flags = (1 << 15) - 1 }; @@ -2114,8 +2114,8 @@ class LIR_OpProfileType : public LIR_Op { virtual void print_instr(outputStream* out) const PRODUCT_RETURN; }; -// LIR_OpProfileInlineType -class LIR_OpProfileInlineType : public LIR_Op { +// LIR_OpProfileValueType +class LIR_OpProfileValueType : public LIR_Op { friend class LIR_OpVisitState; private: @@ -2127,8 +2127,8 @@ class LIR_OpProfileInlineType : public LIR_Op { public: // Destroys recv - LIR_OpProfileInlineType(LIR_Opr mdp, LIR_Opr obj, int flag, LIR_Opr tmp, bool not_null) - : LIR_Op(lir_profile_inline_type, LIR_OprFact::illegalOpr, nullptr) // no result, no info + LIR_OpProfileValueType(LIR_Opr mdp, LIR_Opr obj, int flag, LIR_Opr tmp, bool not_null) + : LIR_Op(lir_profile_value_type, LIR_OprFact::illegalOpr, nullptr) // no result, no info , _mdp(mdp) , _obj(obj) , _flag(flag) @@ -2142,7 +2142,7 @@ class LIR_OpProfileInlineType : public LIR_Op { bool not_null() const { return _not_null; } virtual void emit_code(LIR_Assembler* masm); - virtual LIR_OpProfileInlineType* as_OpProfileInlineType() { return this; } + virtual LIR_OpProfileValueType* as_OpProfileValueType() { return this; } virtual void print_instr(outputStream* out) const PRODUCT_RETURN; }; @@ -2444,8 +2444,8 @@ class LIR_List: public CompilationResourceObj { void profile_type(LIR_Address* mdp, LIR_Opr obj, ciKlass* exact_klass, intptr_t current_klass, LIR_Opr tmp, bool not_null, bool no_conflict) { append(new LIR_OpProfileType(LIR_OprFact::address(mdp), obj, exact_klass, current_klass, tmp, not_null, no_conflict)); } - void profile_inline_type(LIR_Address* mdp, LIR_Opr obj, int flag, LIR_Opr tmp, bool not_null) { - append(new LIR_OpProfileInlineType(LIR_OprFact::address(mdp), obj, flag, tmp, not_null)); + void profile_value_type(LIR_Address* mdp, LIR_Opr obj, int flag, LIR_Opr tmp, bool not_null) { + append(new LIR_OpProfileValueType(LIR_OprFact::address(mdp), obj, flag, tmp, not_null)); } void xadd(LIR_Opr src, LIR_Opr add, LIR_Opr res, LIR_Opr tmp) { append(new LIR_Op2(lir_xadd, src, add, res, tmp)); } diff --git a/src/hotspot/share/c1/c1_LIRAssembler.cpp b/src/hotspot/share/c1/c1_LIRAssembler.cpp index 6f6c6c9d576a..93adc24b4d81 100644 --- a/src/hotspot/share/c1/c1_LIRAssembler.cpp +++ b/src/hotspot/share/c1/c1_LIRAssembler.cpp @@ -29,8 +29,8 @@ #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_MacroAssembler.hpp" #include "c1/c1_ValueStack.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciUtilities.inline.hpp" +#include "ci/ciValueKlass.hpp" #include "compiler/compilerDefinitions.inline.hpp" #include "compiler/oopMap.hpp" #include "runtime/os.hpp" @@ -120,7 +120,7 @@ LIR_Assembler::~LIR_Assembler() { // The unwind handler label may be unnbound if this destructor is invoked because of a bail-out. // Reset it here to avoid an assertion. _unwind_handler_entry.reset(); - _verified_inline_entry.reset(); + _verified_value_entry.reset(); } @@ -482,9 +482,9 @@ void LIR_Assembler::emit_call(LIR_OpJavaCall* op) { break; } - ciInlineKlass* vk = nullptr; + ciValueKlass* vk = nullptr; if (op->maybe_return_as_fields(&vk)) { - int offset = store_inline_type_fields_to_buf(vk); + int offset = store_value_type_fields_to_buf(vk); add_call_info(offset, op->info(), true); } } @@ -577,7 +577,7 @@ void LIR_Assembler::emit_op1(LIR_Op1* op) { } void LIR_Assembler::add_scalarized_debug_info(int pc_offset) { - // The VEP and VIEP(RO) of a C1-compiled method call buffer_inline_args_xxx() + // The VEP and VIEP(RO) of a C1-compiled method call buffer_value_args_xxx() // before doing any argument shuffling. This call may cause GC. When GC happens, // all the parameters are still as passed by the caller, so we just use // map->set_include_argument_oops() inside frame::sender_for_compiled_frame(RegisterMap* map). @@ -594,22 +594,22 @@ void LIR_Assembler::add_scalarized_debug_info(int pc_offset) { } // The entries points of C1-compiled methods can have the following types: -// (1) Methods with no inline type args -// (2) Methods with inline type receiver but no inline type args +// (1) Methods with no value type args +// (2) Methods with value type receiver but no value type args // VIEP_RO is the same as VIEP -// (3) Methods with non-inline type receiver and some inline type args +// (3) Methods with non-value type receiver and some value type args // VIEP_RO is the same as VEP -// (4) Methods with inline type receiver and other inline type args +// (4) Methods with value type receiver and other value type args // Separate VEP, VIEP and VIEP_RO // // (1) (2) (3) (4) // UEP/UIEP: VEP: UEP: UEP: // check_icache pack receiver check_icache check_icache // VEP/VIEP/VIEP_RO jump to VIEP VEP/VIEP_RO: VIEP_RO: -// body UEP/UIEP: pack inline args pack inline args (except receiver) +// body UEP/UIEP: pack value args pack value args (except receiver) // check_icache jump to VIEP jump to VIEP // VIEP/VIEP_RO UIEP: VEP: -// body check_icache pack all inline args +// body check_icache pack all value args // VIEP: jump to VIEP // body UIEP: // check_icache @@ -622,13 +622,13 @@ void LIR_Assembler::emit_std_entries() { if (method()->has_scalarized_args()) { VM_ENTRY_MARK; - assert(InlineTypePassFieldsAsArgs, "must be"); + assert(ValueTypePassFieldsAsArgs, "must be"); CompiledEntrySignature ces(method()->get_Method()); ces.compute_calling_conventions(false); - CodeOffsets::Entries ro_entry_type = ces.c1_inline_ro_entry_type(); + CodeOffsets::Entries ro_entry_type = ces.c1_value_ro_entry_type(); // UEP: check icache and fall-through - if (ro_entry_type != CodeOffsets::Verified_Inline_Entry) { + if (ro_entry_type != CodeOffsets::Verified_Value_Entry) { offsets()->set_value(CodeOffsets::Entry, _masm->offset()); if (needs_icache(method())) { check_icache(); @@ -636,8 +636,8 @@ void LIR_Assembler::emit_std_entries() { } // VIEP_RO: pack all value parameters, except the receiver - if (ro_entry_type == CodeOffsets::Verified_Inline_Entry_RO) { - emit_std_entry(CodeOffsets::Verified_Inline_Entry_RO, &ces); + if (ro_entry_type == CodeOffsets::Verified_Value_Entry_RO) { + emit_std_entry(CodeOffsets::Verified_Value_Entry_RO, &ces); } // VEP: pack all value parameters @@ -646,8 +646,8 @@ void LIR_Assembler::emit_std_entries() { // UIEP: check icache and fall-through _masm->align(CodeEntryAlignment); - offsets()->set_value(CodeOffsets::Inline_Entry, _masm->offset()); - if (ro_entry_type == CodeOffsets::Verified_Inline_Entry) { + offsets()->set_value(CodeOffsets::Value_Entry, _masm->offset()); + if (ro_entry_type == CodeOffsets::Verified_Value_Entry) { // Special case if we have VIEP == VIEP(RO): // this means UIEP (called by C1) == UEP (called by C2). offsets()->set_value(CodeOffsets::Entry, _masm->offset()); @@ -657,25 +657,25 @@ void LIR_Assembler::emit_std_entries() { } // VIEP: all value parameters are passed as refs - no packing. - emit_std_entry(CodeOffsets::Verified_Inline_Entry, nullptr); + emit_std_entry(CodeOffsets::Verified_Value_Entry, nullptr); - if (ro_entry_type != CodeOffsets::Verified_Inline_Entry_RO) { + if (ro_entry_type != CodeOffsets::Verified_Value_Entry_RO) { // The VIEP(RO) is the same as VEP or VIEP assert(ro_entry_type == CodeOffsets::Verified_Entry || - ro_entry_type == CodeOffsets::Verified_Inline_Entry, "must be"); - offsets()->set_value(CodeOffsets::Verified_Inline_Entry_RO, + ro_entry_type == CodeOffsets::Verified_Value_Entry, "must be"); + offsets()->set_value(CodeOffsets::Verified_Value_Entry_RO, offsets()->value(ro_entry_type)); } } else { - // All 3 entries are the same (no inline type packing) + // All 3 entries are the same (no value type packing) offsets()->set_value(CodeOffsets::Entry, _masm->offset()); - offsets()->set_value(CodeOffsets::Inline_Entry, _masm->offset()); + offsets()->set_value(CodeOffsets::Value_Entry, _masm->offset()); if (needs_icache(method())) { check_icache(); } - emit_std_entry(CodeOffsets::Verified_Inline_Entry, nullptr); - offsets()->set_value(CodeOffsets::Verified_Entry, offsets()->value(CodeOffsets::Verified_Inline_Entry)); - offsets()->set_value(CodeOffsets::Verified_Inline_Entry_RO, offsets()->value(CodeOffsets::Verified_Inline_Entry)); + emit_std_entry(CodeOffsets::Verified_Value_Entry, nullptr); + offsets()->set_value(CodeOffsets::Verified_Entry, offsets()->value(CodeOffsets::Verified_Value_Entry)); + offsets()->set_value(CodeOffsets::Verified_Value_Entry_RO, offsets()->value(CodeOffsets::Verified_Value_Entry)); } } @@ -687,17 +687,17 @@ void LIR_Assembler::emit_std_entry(CodeOffsets::Entries entry, const CompiledEnt if (needs_clinit_barrier_on_entry(method())) { clinit_barrier(method()); } - int rt_call_offset = _masm->verified_entry(ces, initial_frame_size_in_bytes(), bang_size_in_bytes(), in_bytes(frame_map()->sp_offset_for_orig_pc()), _verified_inline_entry); + int rt_call_offset = _masm->verified_entry(ces, initial_frame_size_in_bytes(), bang_size_in_bytes(), in_bytes(frame_map()->sp_offset_for_orig_pc()), _verified_value_entry); add_scalarized_debug_info(rt_call_offset); break; } - case CodeOffsets::Verified_Inline_Entry_RO: { + case CodeOffsets::Verified_Value_Entry_RO: { assert(!needs_clinit_barrier_on_entry(method()), "can't be static"); - int rt_call_offset = _masm->verified_inline_ro_entry(ces, initial_frame_size_in_bytes(), bang_size_in_bytes(), in_bytes(frame_map()->sp_offset_for_orig_pc()), _verified_inline_entry); + int rt_call_offset = _masm->verified_value_ro_entry(ces, initial_frame_size_in_bytes(), bang_size_in_bytes(), in_bytes(frame_map()->sp_offset_for_orig_pc()), _verified_value_entry); add_scalarized_debug_info(rt_call_offset); break; } - case CodeOffsets::Verified_Inline_Entry: { + case CodeOffsets::Verified_Value_Entry: { if (needs_clinit_barrier_on_entry(method())) { clinit_barrier(method()); } @@ -861,7 +861,7 @@ void LIR_Assembler::emit_op4(LIR_Op4* op) { void LIR_Assembler::build_frame() { _masm->build_frame(initial_frame_size_in_bytes(), bang_size_in_bytes(), in_bytes(frame_map()->sp_offset_for_orig_pc()), - method()->has_scalarized_args(), &_verified_inline_entry); + method()->has_scalarized_args(), &_verified_value_entry); } diff --git a/src/hotspot/share/c1/c1_LIRAssembler.hpp b/src/hotspot/share/c1/c1_LIRAssembler.hpp index fe2a408c1174..de8c8688f4bc 100644 --- a/src/hotspot/share/c1/c1_LIRAssembler.hpp +++ b/src/hotspot/share/c1/c1_LIRAssembler.hpp @@ -48,7 +48,7 @@ class LIR_Assembler: public CompilationResourceObj { int _immediate_oops_patched; Label _unwind_handler_entry; - Label _verified_inline_entry; + Label _verified_value_entry; #ifdef ASSERT BlockList _branch_target_blocks; @@ -208,7 +208,7 @@ class LIR_Assembler: public CompilationResourceObj { void emit_rtcall(LIR_OpRTCall* op); void emit_profile_call(LIR_OpProfileCall* op); void emit_profile_type(LIR_OpProfileType* op); - void emit_profile_inline_type(LIR_OpProfileInlineType* op); + void emit_profile_value_type(LIR_OpProfileValueType* op); void emit_std_entries(); void emit_std_entry(CodeOffsets::Entries entry, const CompiledEntrySignature* ces); void add_scalarized_debug_info(int call_offset); @@ -232,7 +232,7 @@ class LIR_Assembler: public CompilationResourceObj { void call( LIR_OpJavaCall* op, relocInfo::relocType rtype); void ic_call( LIR_OpJavaCall* op); void vtable_call( LIR_OpJavaCall* op); - int store_inline_type_fields_to_buf(ciInlineKlass* vk); + int store_value_type_fields_to_buf(ciValueKlass* vk); void osr_entry(); diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index f61daa556699..90e8f103e8aa 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -31,11 +31,11 @@ #include "c1/c1_ValueStack.hpp" #include "ci/ciArrayKlass.hpp" #include "ci/ciFlatArrayKlass.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciInstance.hpp" #include "ci/ciObjArray.hpp" #include "ci/ciObjArrayKlass.hpp" #include "ci/ciUtilities.hpp" +#include "ci/ciValueKlass.hpp" #include "compiler/compilerDefinitions.inline.hpp" #include "compiler/compilerOracle.hpp" #include "gc/shared/barrierSet.hpp" @@ -659,13 +659,13 @@ void LIRGenerator::print_if_not_loaded(const NewInstance* new_instance) { void LIRGenerator::new_instance(LIR_Opr dst, ciInstanceKlass* klass, bool is_unresolved, bool allow_inline, LIR_Opr scratch1, LIR_Opr scratch2, LIR_Opr scratch3, LIR_Opr scratch4, LIR_Opr klass_reg, CodeEmitInfo* info) { if (allow_inline) { - assert(!is_unresolved && klass->is_loaded(), "inline type klass should be resolved"); + assert(!is_unresolved && klass->is_loaded(), "value type klass should be resolved"); __ metadata2reg(klass->constant_encoding(), klass_reg); } else { klass2reg_with_patching(klass_reg, klass, info, is_unresolved); } - // If klass is not loaded we do not know if the klass has finalizers or is an unexpected inline klass - if (UseFastNewInstance && klass->is_loaded() && (allow_inline || !klass->is_inlinetype()) + // If klass is not loaded we do not know if the klass has finalizers or is an unexpected value klass + if (UseFastNewInstance && klass->is_loaded() && (allow_inline || !klass->is_value_klass()) && !Klass::layout_helper_needs_slow_path(klass->layout_helper())) { StubId stub_id = klass->is_initialized() ? StubId::c1_fast_new_instance_id : StubId::c1_fast_new_instance_init_check_id; @@ -786,15 +786,15 @@ void LIRGenerator::arraycopy_helper(Intrinsic* x, int* flagsp, ciArrayKlass** ex int flags = LIR_OpArrayCopy::all_flags; // TODO 8251971 Compare ArrayKlass::properties() of source and destination - // array here instead, see also LIR_Assembler::arraycopy_inlinetype_check + // array here instead, see also LIR_Assembler::arraycopy_valuetype_check if (!src->is_loaded_flat_array() && !dst->is_loaded_flat_array()) { flags &= ~LIR_OpArrayCopy::always_slow_path; } if (!src->maybe_flat_array()) { - flags &= ~LIR_OpArrayCopy::src_inlinetype_check; + flags &= ~LIR_OpArrayCopy::src_valuetype_check; } if (!dst->maybe_flat_array() && !dst->maybe_null_free_array()) { - flags &= ~LIR_OpArrayCopy::dst_inlinetype_check; + flags &= ~LIR_OpArrayCopy::dst_valuetype_check; } if (!src_objarray) @@ -1558,7 +1558,12 @@ void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) { // Returns an int/long value with the null marker bit set. static LIR_Opr null_marker_mask(BasicType bt, int nm_offset) { assert(nm_offset >= 0, "field does not have null marker"); - jlong null_marker = 1ULL << (nm_offset << LogBitsPerByte); +#ifdef VM_LITTLE_ENDIAN + int bit_pos = nm_offset << LogBitsPerByte; +#else + int bit_pos = (type2aelembytes(bt) - nm_offset - 1) << LogBitsPerByte; +#endif + jlong null_marker = 1ULL << bit_pos; return (bt == T_LONG) ? LIR_OprFact::longConst(null_marker) : LIR_OprFact::intConst(null_marker); } @@ -1664,7 +1669,7 @@ void LIRGenerator::do_StoreField(StoreField* x) { } if (field->is_flat()) { - ciInlineKlass* vk = field->type()->as_inline_klass(); + ciValueKlass* vk = field->type()->as_value_klass(); #ifdef ASSERT assert(field->is_atomic(), "No atomic access required %s.%s", field->holder()->name()->as_utf8(), field->name()->as_utf8()); @@ -1772,11 +1777,11 @@ LIR_Opr LIRGenerator::access_flat_array(bool is_load, LIRItem& array, LIRItem& i LIR_Opr elm_op = get_and_load_element_address(array, index); ciFlatArrayKlass* array_klass = array.value()->declared_type()->as_flat_array_klass(); - ciInlineKlass* elem_klass = nullptr; + ciValueKlass* elem_klass = nullptr; if (field != nullptr) { - elem_klass = field->type()->as_inline_klass(); + elem_klass = field->type()->as_value_klass(); } else { - elem_klass = array_klass->element_klass()->as_inline_klass(); + elem_klass = array_klass->element_klass()->as_value_klass(); } bool null_free = array_klass->is_elem_null_free(); @@ -1895,7 +1900,7 @@ bool LIRGenerator::needs_flat_array_store_check(StoreIndexed* x) { ciType* type = x->value()->declared_type(); if (type != nullptr && type->is_klass()) { ciKlass* klass = type->as_klass(); - if (!klass->can_be_inline_klass() || (klass->is_inlinetype() && !klass->as_inline_klass()->maybe_flat_in_array())) { + if (!klass->can_be_value_klass() || (klass->is_value_klass() && !klass->as_value_klass()->maybe_flat_in_array())) { // This is known to be a non-flat object. If the array is a flat array, // it will be caught by the code generated by array_store_check(). return false; @@ -1991,12 +1996,12 @@ void LIRGenerator::do_StoreIndexed(StoreIndexed* x) { if (is_loaded_flat_array) { ciFlatArrayKlass* array_klass = x->array()->declared_type()->as_flat_array_klass(); - ciInlineKlass* elem_klass = array_klass->element_klass()->as_inline_klass(); + ciValueKlass* elem_klass = array_klass->element_klass()->as_value_klass(); bool null_free = array_klass->is_elem_null_free(); if (null_free && !x->value()->is_null_free()) { __ null_check(value.result(), new CodeEmitInfo(range_check_info)); } - // If array element is an empty null-free inline type, no need to copy anything. + // If array element is an empty null-free value type, no need to copy anything. // Nullable empty arrays still need their null marker updated. if (!elem_klass->is_empty() || !null_free) { access_flat_array(false, array, index, value); @@ -2057,7 +2062,7 @@ void LIRGenerator::access_load(DecoratorSet decorators, BasicType type, void LIRGenerator::access_store_at(DecoratorSet decorators, BasicType type, LIRItem& base, LIR_Opr offset, LIR_Opr value, CodeEmitInfo* patch_info, CodeEmitInfo* store_emit_info, - ciInlineKlass* vk) { + ciValueKlass* vk) { decorators |= ACCESS_WRITE; LIRAccess access(this, decorators, base, offset, type, patch_info, store_emit_info, vk); if (access.is_raw()) { @@ -2164,7 +2169,7 @@ void LIRGenerator::do_LoadField(LoadField* x) { } if (field->is_flat()) { - ciInlineKlass* vk = field->type()->as_inline_klass(); + ciValueKlass* vk = field->type()->as_value_klass(); #ifdef ASSERT assert(field->is_atomic(), "No atomic access required"); assert(!is_volatile, "Flat fields cannot be volatile"); @@ -2387,12 +2392,12 @@ void LIRGenerator::do_LoadIndexed(LoadIndexed* x) { ciFlatArrayKlass* flat_array_klass = x->array()->is_loaded_flat_array() ? x->array()->declared_type()->as_flat_array_klass() : nullptr; bool assert_null = flat_array_klass != nullptr && !flat_array_klass->is_elem_null_free() && - !flat_array_klass->element_klass()->as_inline_klass()->is_initialized(); + !flat_array_klass->element_klass()->as_value_klass()->is_initialized(); if (assert_null) { // Deoptimize on non-null because buffering requires the value class to be initialized assert(x->buffer() == nullptr && x->delayed() == nullptr, "null assertion should not buffer"); assert(flat_array_klass->is_elem_atomic(), "nullable flat arrays must use an atomic layout"); - ciInlineKlass* elem_klass = flat_array_klass->element_klass()->as_inline_klass(); + ciValueKlass* elem_klass = flat_array_klass->element_klass()->as_value_klass(); CodeEmitInfo* null_assert_info = state_for(x, x->state_before()); BasicType bt = elem_klass->atomic_size_to_basic_type(false); LIR_Opr elm_op = get_and_load_element_address(array, index); @@ -2411,7 +2416,7 @@ void LIRGenerator::do_LoadIndexed(LoadIndexed* x) { Value element = nullptr; if (x->buffer() != nullptr) { assert(x->array()->is_loaded_flat_array(), "must be"); - // Find the destination address (of the NewInlineTypeInstance). + // Find the destination address (of the NewValueTypeInstance). LIRItem buffer(x->buffer(), this); LIR_Opr payload = access_flat_array(true, array, index, buffer, x->delayed() == nullptr ? nullptr : x->delayed()->field(), @@ -2421,7 +2426,7 @@ void LIRGenerator::do_LoadIndexed(LoadIndexed* x) { set_result(x, x->buffer()->operand()); } else { // Check the null marker and set result to null if it's not set - ciInlineKlass* elem_klass = array_klass->element_klass()->as_inline_klass(); + ciValueKlass* elem_klass = array_klass->element_klass()->as_value_klass(); BasicType bt = elem_klass->atomic_size_to_basic_type(false); assert(payload->is_valid(), "nullable flat array load must return the atomic payload"); __ logical_and(payload, null_marker_mask(bt, elem_klass->null_marker_offset_in_payload()), payload); @@ -2739,7 +2744,7 @@ void LIRGenerator::do_TableSwitch(TableSwitch* x) { assert(lo_key <= (lo_key + (len - 1)), "integer overflow"); LIR_Opr value = tag.result(); - if (compilation()->env()->comp_level() == CompLevel_full_profile && UseSwitchProfiling) { + if (compilation()->profile_switches()) { ciMethod* method = x->state()->scope()->method(); ciMethodData* md = method->method_data_or_null(); assert(md != nullptr, "Sanity"); @@ -2797,7 +2802,7 @@ void LIRGenerator::do_LookupSwitch(LookupSwitch* x) { LIR_Opr value = tag.result(); int len = x->length(); - if (compilation()->env()->comp_level() == CompLevel_full_profile && UseSwitchProfiling) { + if (compilation()->profile_switches()) { ciMethod* method = x->state()->scope()->method(); ciMethodData* md = method->method_data_or_null(); assert(md != nullptr, "Sanity"); @@ -2983,8 +2988,8 @@ ciKlass* LIRGenerator::profile_type(ciMethodData* md, int md_base_offset, int md ciArrayKlass* exact_array_klass = exact_klass->as_array_klass(); if (exact_array_klass->is_refined()) { do_update = ciTypeEntries::valid_ciklass(profiled_k) != exact_klass; - } else if (exact_klass->can_be_inline_array_klass()) { - // Inline type arrays can have additional properties. Load the klass unless + } else if (exact_klass->can_be_value_array_klass()) { + // Value type arrays can have additional properties. Load the klass unless // the C1 type already carries refined array properties. exact_klass = nullptr; do_update = true; @@ -3181,7 +3186,7 @@ void LIRGenerator::do_Base(Base* x) { increment_invocation_counter(info); } if (method()->has_scalarized_args()) { - // Check if deoptimization was triggered (i.e. orig_pc was set) while buffering scalarized inline type arguments + // Check if deoptimization was triggered (i.e. orig_pc was set) while buffering scalarized value type arguments // in the entry point (see comments in frame::deoptimize). If so, deoptimize only now that we have the right state. CodeEmitInfo* info = new CodeEmitInfo(scope()->start()->state()->copy(ValueStack::StateBefore, 0), nullptr, false); CodeStub* deopt_stub = new DeoptimizeStub(info, Deoptimization::Reason_none, Deoptimization::Action_none); @@ -3427,8 +3432,8 @@ void LIRGenerator::substitutability_check_common(Value left_val, Value right_val ciKlass* left_klass = left_val->as_loaded_klass_or_null(); ciKlass* right_klass = right_val->as_loaded_klass_or_null(); - if (left_klass != nullptr && left_klass->is_inlinetype() && left_klass == right_klass) { - // No need to load klass -- the operands are statically known to be the same inline klass. + if (left_klass != nullptr && left_klass->is_value_klass() && left_klass == right_klass) { + // No need to load klass -- the operands are statically known to be the same value klass. } else { BasicType t_klass = UseCompressedOops ? T_INT : T_METADATA; tmp1 = new_register(t_klass); @@ -3733,12 +3738,12 @@ void LIRGenerator::do_ProfileReturnType(ProfileReturnType* x) { } } -bool LIRGenerator::profile_inline_klass(ciMethodData* md, ciProfileData* data, Value value, int flag) { +bool LIRGenerator::profile_value_klass(ciMethodData* md, ciProfileData* data, Value value, int flag) { ciKlass* klass = value->as_loaded_klass_or_null(); if (klass != nullptr) { - if (klass->is_inlinetype()) { + if (klass->is_value_klass()) { profile_flags(md, data, flag, lir_cond_always); - } else if (klass->can_be_inline_klass()) { + } else if (klass->can_be_value_klass()) { return false; } } else { @@ -3760,22 +3765,22 @@ void LIRGenerator::do_ProfileACmpTypes(ProfileACmpTypes* x) { profile_type(md, md->byte_offset_of_slot(acmp, ACmpData::left_offset()), 0, acmp->left()->type(), x->left(), mdp, !x->left_maybe_null(), nullptr, nullptr); int flags_offset = md->byte_offset_of_slot(data, DataLayout::flags_offset()); - if (!profile_inline_klass(md, acmp, x->left(), ACmpData::left_inline_type_byte_constant())) { + if (!profile_value_klass(md, acmp, x->left(), ACmpData::left_value_type_byte_constant())) { LIR_Opr mdp = new_register(T_METADATA); __ metadata2reg(md->constant_encoding(), mdp); LIRItem value(x->left(), this); value.load_item(); - __ profile_inline_type(new LIR_Address(mdp, flags_offset, T_INT), value.result(), ACmpData::left_inline_type_byte_constant(), new_register(T_INT), !x->left_maybe_null()); + __ profile_value_type(new LIR_Address(mdp, flags_offset, T_INT), value.result(), ACmpData::left_value_type_byte_constant(), new_register(T_INT), !x->left_maybe_null()); } profile_type(md, md->byte_offset_of_slot(acmp, ACmpData::left_offset()), in_bytes(ACmpData::right_offset()) - in_bytes(ACmpData::left_offset()), acmp->right()->type(), x->right(), mdp, !x->right_maybe_null(), nullptr, nullptr); - if (!profile_inline_klass(md, acmp, x->right(), ACmpData::right_inline_type_byte_constant())) { + if (!profile_value_klass(md, acmp, x->right(), ACmpData::right_value_type_byte_constant())) { LIR_Opr mdp = new_register(T_METADATA); __ metadata2reg(md->constant_encoding(), mdp); LIRItem value(x->right(), this); value.load_item(); - __ profile_inline_type(new LIR_Address(mdp, flags_offset, T_INT), value.result(), ACmpData::right_inline_type_byte_constant(), new_register(T_INT), !x->right_maybe_null()); + __ profile_value_type(new LIR_Address(mdp, flags_offset, T_INT), value.result(), ACmpData::right_value_type_byte_constant(), new_register(T_INT), !x->right_maybe_null()); } } diff --git a/src/hotspot/share/c1/c1_LIRGenerator.hpp b/src/hotspot/share/c1/c1_LIRGenerator.hpp index 65c64d2262cd..4cd09678c572 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.hpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.hpp @@ -303,7 +303,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { public: void access_store_at(DecoratorSet decorators, BasicType type, LIRItem& base, LIR_Opr offset, LIR_Opr value, - CodeEmitInfo* patch_info = nullptr, CodeEmitInfo* store_emit_info = nullptr, ciInlineKlass* vk = nullptr); + CodeEmitInfo* patch_info = nullptr, CodeEmitInfo* store_emit_info = nullptr, ciValueKlass* vk = nullptr); void access_load_at(DecoratorSet decorators, BasicType type, LIRItem& base, LIR_Opr offset, LIR_Opr result, @@ -496,7 +496,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { void profile_null_free_array(LIRItem array, ciMethodData* md, ciProfileData* load_store); template void profile_array_type(AccessIndexed* x, ciMethodData*& md, ArrayData*& load_store); void profile_element_type(Value element, ciMethodData* md, ciArrayLoadData* load_store); - bool profile_inline_klass(ciMethodData* md, ciProfileData* data, Value value, int flag); + bool profile_value_klass(ciMethodData* md, ciProfileData* data, Value value, int flag); LIR_Opr mask_boolean(LIR_Opr array, LIR_Opr value, CodeEmitInfo*& null_check_info); public: diff --git a/src/hotspot/share/c1/c1_MacroAssembler.hpp b/src/hotspot/share/c1/c1_MacroAssembler.hpp index 840ca51d76e2..2d821f96a755 100644 --- a/src/hotspot/share/c1/c1_MacroAssembler.hpp +++ b/src/hotspot/share/c1/c1_MacroAssembler.hpp @@ -32,7 +32,7 @@ class CodeEmitInfo; class CompiledEntrySignature; class C1_MacroAssembler: public MacroAssembler { private: - int scalarized_entry(const CompiledEntrySignature* ces, int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, Label& verified_inline_entry_label, bool is_inline_ro_entry); + int scalarized_entry(const CompiledEntrySignature* ces, int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, Label& verified_value_entry_label, bool is_value_ro_entry); void build_frame_helper(int frame_size_in_bytes, int sp_offset_for_orig_pc, bool reset_orig_pc); public: // creation @@ -41,13 +41,13 @@ class C1_MacroAssembler: public MacroAssembler { //---------------------------------------------------- void explicit_null_check(Register base); - void build_frame(int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc = 0, bool has_scalarized_args = false, Label* verified_inline_entry_label = nullptr); + void build_frame(int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc = 0, bool has_scalarized_args = false, Label* verified_value_entry_label = nullptr); - int verified_entry(const CompiledEntrySignature* ces, int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, Label& verified_inline_entry_label) { - return scalarized_entry(ces, frame_size_in_bytes, bang_size_in_bytes, sp_offset_for_orig_pc, verified_inline_entry_label, false); + int verified_entry(const CompiledEntrySignature* ces, int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, Label& verified_value_entry_label) { + return scalarized_entry(ces, frame_size_in_bytes, bang_size_in_bytes, sp_offset_for_orig_pc, verified_value_entry_label, false); } - int verified_inline_ro_entry(const CompiledEntrySignature* ces, int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, Label& verified_inline_entry_label) { - return scalarized_entry(ces, frame_size_in_bytes, bang_size_in_bytes, sp_offset_for_orig_pc, verified_inline_entry_label, true); + int verified_value_ro_entry(const CompiledEntrySignature* ces, int frame_size_in_bytes, int bang_size_in_bytes, int sp_offset_for_orig_pc, Label& verified_value_entry_label) { + return scalarized_entry(ces, frame_size_in_bytes, bang_size_in_bytes, sp_offset_for_orig_pc, verified_value_entry_label, true); } void verified_entry(bool breakAtEntry); void verify_stack_oop(int offset) PRODUCT_RETURN; diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index d4b1f3a111e7..0f8cb60cd955 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -126,8 +126,8 @@ uint Runtime1::_new_multi_array_slowcase_cnt = 0; uint Runtime1::_load_flat_array_slowcase_cnt = 0; uint Runtime1::_store_flat_array_slowcase_cnt = 0; uint Runtime1::_substitutability_check_slowcase_cnt = 0; -uint Runtime1::_buffer_inline_args_slowcase_cnt = 0; -uint Runtime1::_buffer_inline_args_no_receiver_slowcase_cnt = 0; +uint Runtime1::_buffer_value_args_slowcase_cnt = 0; +uint Runtime1::_buffer_value_args_no_receiver_slowcase_cnt = 0; uint Runtime1::_monitorenter_slowcase_cnt = 0; uint Runtime1::_monitorexit_slowcase_cnt = 0; uint Runtime1::_patch_code_slowcase_cnt = 0; @@ -454,7 +454,7 @@ JRT_ENTRY(void, Runtime1::new_null_free_array(JavaThread* current, Klass* array_ assert(array_klass->is_klass(), "not a class"); Handle holder(THREAD, array_klass->klass_holder()); // keep the klass alive Klass* elem_klass = ObjArrayKlass::cast(array_klass)->element_klass(); - assert(elem_klass->is_inline_klass(), "must be"); + assert(elem_klass->is_value_klass(), "must be"); // Logically creates elements, ensure klass init elem_klass->initialize(CHECK); @@ -557,21 +557,21 @@ JRT_ENTRY(int, Runtime1::substitutability_check(JavaThread* current, oopDesc* le return result.get_jboolean() ? 1 : 0; JRT_END -void Runtime1::buffer_inline_args_impl(JavaThread* current, Method* m, bool allocate_receiver) { +void Runtime1::buffer_value_args_impl(JavaThread* current, Method* m, bool allocate_receiver) { JavaThread* THREAD = current; - methodHandle method(current, m); // We are inside the verified_entry or verified_inline_ro_entry of this method. - oop obj = SharedRuntime::allocate_inline_types_impl(current, method, allocate_receiver, true, CHECK); + methodHandle method(current, m); // We are inside the verified_entry or verified_value_ro_entry of this method. + oop obj = SharedRuntime::allocate_value_types_impl(current, method, allocate_receiver, true, CHECK); current->set_vm_result_oop(obj); } -JRT_ENTRY(void, Runtime1::buffer_inline_args(JavaThread* current, Method* method)) - NOT_PRODUCT(_buffer_inline_args_slowcase_cnt++;) - buffer_inline_args_impl(current, method, true); +JRT_ENTRY(void, Runtime1::buffer_value_args(JavaThread* current, Method* method)) + NOT_PRODUCT(_buffer_value_args_slowcase_cnt++;) + buffer_value_args_impl(current, method, true); JRT_END -JRT_ENTRY(void, Runtime1::buffer_inline_args_no_receiver(JavaThread* current, Method* method)) - NOT_PRODUCT(_buffer_inline_args_no_receiver_slowcase_cnt++;) - buffer_inline_args_impl(current, method, false); +JRT_ENTRY(void, Runtime1::buffer_value_args_no_receiver(JavaThread* current, Method* method)) + NOT_PRODUCT(_buffer_value_args_no_receiver_slowcase_cnt++;) + buffer_value_args_impl(current, method, false); JRT_END JRT_ENTRY(void, Runtime1::unimplemented_entry(JavaThread* current, StubId id)) @@ -1141,7 +1141,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, StubId stub_id )) // The field we are patching is null-free. Deoptimize and regenerate // the compiled code if we patch a putfield/putstatic because it // does not contain the required null check. - deoptimize_for_null_free = result.is_null_free_inline_type() && (field_access.is_putfield() || field_access.is_putstatic()); + deoptimize_for_null_free = result.is_null_free_value_type() && (field_access.is_putfield() || field_access.is_putstatic()); // The field we are patching is flat. Deoptimize and regenerate // the compiled code which can't handle the layout of the flat @@ -1701,8 +1701,8 @@ void Runtime1::print_statistics() { tty->print_cr(" _load_flat_array_slowcase_cnt: %u", _load_flat_array_slowcase_cnt); tty->print_cr(" _store_flat_array_slowcase_cnt: %u", _store_flat_array_slowcase_cnt); tty->print_cr(" _substitutability_check_slowcase_cnt: %u", _substitutability_check_slowcase_cnt); - tty->print_cr(" _buffer_inline_args_slowcase_cnt:%u", _buffer_inline_args_slowcase_cnt); - tty->print_cr(" _buffer_inline_args_no_receiver_slowcase_cnt:%u", _buffer_inline_args_no_receiver_slowcase_cnt); + tty->print_cr(" _buffer_value_args_slowcase_cnt:%u", _buffer_value_args_slowcase_cnt); + tty->print_cr(" _buffer_value_args_no_receiver_slowcase_cnt:%u", _buffer_value_args_no_receiver_slowcase_cnt); tty->print_cr(" _monitorenter_slowcase_cnt: %u", _monitorenter_slowcase_cnt); tty->print_cr(" _monitorexit_slowcase_cnt: %u", _monitorexit_slowcase_cnt); diff --git a/src/hotspot/share/c1/c1_Runtime1.hpp b/src/hotspot/share/c1/c1_Runtime1.hpp index c8a19d9bf3ef..ed2e167cb1fd 100644 --- a/src/hotspot/share/c1/c1_Runtime1.hpp +++ b/src/hotspot/share/c1/c1_Runtime1.hpp @@ -62,8 +62,8 @@ class Runtime1: public AllStatic { static uint _load_flat_array_slowcase_cnt; static uint _store_flat_array_slowcase_cnt; static uint _substitutability_check_slowcase_cnt; - static uint _buffer_inline_args_slowcase_cnt; - static uint _buffer_inline_args_no_receiver_slowcase_cnt; + static uint _buffer_value_args_slowcase_cnt; + static uint _buffer_value_args_no_receiver_slowcase_cnt; static uint _monitorenter_slowcase_cnt; static uint _monitorexit_slowcase_cnt; static uint _patch_code_slowcase_cnt; @@ -80,7 +80,7 @@ class Runtime1: public AllStatic { private: static CodeBlob* _blobs[(int)StubInfo::C1_STUB_COUNT]; - static void buffer_inline_args_impl(JavaThread* current, Method* m, bool allocate_receiver); + static void buffer_value_args_impl(JavaThread* current, Method* m, bool allocate_receiver); // stub generation public: @@ -105,8 +105,8 @@ class Runtime1: public AllStatic { static void load_flat_array(JavaThread* current, flatArrayOopDesc* array, int index); static void store_flat_array(JavaThread* current, flatArrayOopDesc* array, int index, oopDesc* value); static int substitutability_check(JavaThread* current, oopDesc* left, oopDesc* right); - static void buffer_inline_args(JavaThread* current, Method* method); - static void buffer_inline_args_no_receiver(JavaThread* current, Method* method); + static void buffer_value_args(JavaThread* current, Method* method); + static void buffer_value_args_no_receiver(JavaThread* current, Method* method); static address counter_overflow(JavaThread* current, int bci, Method* method); diff --git a/src/hotspot/share/cds/aotMapLogger.cpp b/src/hotspot/share/cds/aotMapLogger.cpp index 63aeac091f7a..26692ec982f1 100644 --- a/src/hotspot/share/cds/aotMapLogger.cpp +++ b/src/hotspot/share/cds/aotMapLogger.cpp @@ -632,7 +632,7 @@ class AOTMapLogger::FakeOop { return FakeOop(_iter, _iter->obj_at(addr)); } - FakeOop read_inline_oop_at(address value_addr, Klass* k) { + FakeOop read_value_oop_at(address value_addr, Klass* k) { OopData data = { value_addr, // _buffered_addr, address of the flat value shifted by the payload offset requested_addr() + (value_addr - buffered_addr()), // _requested_addr @@ -711,9 +711,9 @@ class AOTMapLogger::FakeFlatArray : public AOTMapLogger::FakeOop { // Create a wrapper for an archived flat array element FakeOop element_at(int i) { - InlineKlass* elem_k = ((FlatArrayKlass*)real_klass())->element_klass(); + ValueKlass* elem_k = ((FlatArrayKlass*)real_klass())->element_klass(); address value_addr = (address)raw_flatArrayOop()->value_at_addr(i, real_klass()->layout_helper()) - elem_k->payload_offset(); - return read_inline_oop_at(value_addr, elem_k); + return read_value_oop_at(value_addr, elem_k); } int element_offset_at(int i) { @@ -880,22 +880,22 @@ class AOTMapLogger::ArchivedFieldPrinter : public FieldClosure { { if (fd->is_flat()) { int index = fd->index(); - InlineKlass* vk = fd->field_holder()->get_inline_type_field_klass(index); + ValueKlass* vk = fd->field_holder()->get_value_type_field_klass(index); int field_offset = fd->offset() - vk->payload_offset(); address field_addr = (address)_fake_oop.buffered_field_addr(field_offset); bool is_null = false; - if (!fd->is_null_free_inline_type()) { + if (!fd->is_null_free_value_type()) { assert(fd->has_null_marker(), "should have null marker"); is_null = vk->is_payload_marked_as_null(_fake_oop.buffered_addr() + fd->offset()); - _st->print("Flat inline type field '%s':", vk->name()->as_C_string()); + _st->print("Flat value type field '%s':", vk->name()->as_C_string()); } else { - _st->print("Flat inline null-free type field '%s':", vk->name()->as_C_string()); + _st->print("Flat value null-free type field '%s':", vk->name()->as_C_string()); } // Print fields of flat field (recursively) if (!is_null) { _st->cr(); - FakeOop obj = _fake_oop.read_inline_oop_at(field_addr, vk); + FakeOop obj = _fake_oop.read_value_oop_at(field_addr, vk); ArchivedFieldPrinter print_field(obj, _st, _indent + 1, _base_offset + field_offset); vk->do_nonstatic_fields(&print_field); } else { @@ -1057,7 +1057,7 @@ void AOTMapLogger::print_oop_details(FakeOop fake_oop, outputStream* st) { fake_oop.as_type_array().print_elements_on(st); } else if (real_klass->is_flatArray_klass()) { FakeFlatArray fake_flat_array = fake_oop.as_flat_array(); - InlineKlass* elem_k = ((FlatArrayKlass*)real_klass)->element_klass(); + ValueKlass* elem_k = ((FlatArrayKlass*)real_klass)->element_klass(); for (int i = 0; i < fake_flat_array.length(); i++) { bool is_null = false; int off = fake_flat_array.element_offset_at(i); @@ -1065,9 +1065,9 @@ void AOTMapLogger::print_oop_details(FakeOop fake_oop, outputStream* st) { if (!real_klass->is_null_free_array_klass()) { is_null = elem_k->is_payload_marked_as_null(elm.buffered_addr() + elem_k->payload_offset()); - st->print(" - Flat inline type element '%s':", elem_k->name()->as_C_string()); + st->print(" - Flat value type element '%s':", elem_k->name()->as_C_string()); } else { - st->print(" - Flat inline null-free type element '%s':", elem_k->name()->as_C_string()); + st->print(" - Flat value null-free type element '%s':", elem_k->name()->as_C_string()); } st->print(" - Index %3d offset %3d: ", i, off); diff --git a/src/hotspot/share/cds/aotMappedHeapWriter.cpp b/src/hotspot/share/cds/aotMappedHeapWriter.cpp index 8db7c6f3ff2d..4ffc44c6eae0 100644 --- a/src/hotspot/share/cds/aotMappedHeapWriter.cpp +++ b/src/hotspot/share/cds/aotMappedHeapWriter.cpp @@ -437,7 +437,7 @@ size_t AOTMappedHeapWriter::filler_array_byte_size(int length) { int AOTMappedHeapWriter::filler_array_length(size_t fill_bytes) { assert(is_object_aligned(fill_bytes), "must be"); - size_t elemSize = (UseCompressedOops ? sizeof(narrowOop) : sizeof(oop)); + size_t elemSize = heapOopSize; int initial_length = to_array_length(fill_bytes / elemSize); for (int length = initial_length; length >= 0; length --) { @@ -734,7 +734,7 @@ void AOTMappedHeapWriter::update_header_for_requested_obj(oop requested_obj, oop // We need to retain the identity_hash, because it may have been used by some hashtables // in the shared heap. - if (src_obj != nullptr && !src_obj->is_inline_type() && src_obj->has_identity_hash()) { + if (src_obj != nullptr && !src_obj->is_value_type() && src_obj->has_identity_hash()) { intptr_t src_hash = src_obj->identity_hash(); mw = mw.copy_set_hash(src_hash); } @@ -786,7 +786,7 @@ static void log_bitmap_usage(const char* which, BitMap* bitmap, size_t total_bit // Update all oop fields embedded in the buffered objects void AOTMappedHeapWriter::relocate_embedded_oops(GrowableArrayCHeap* roots, AOTMappedHeapInfo* heap_info) { - size_t oopmap_unit = (UseCompressedOops ? sizeof(narrowOop) : sizeof(oop)); + size_t oopmap_unit = heapOopSize; size_t heap_region_byte_size = _buffer_used; heap_info->oopmap()->resize(heap_region_byte_size / oopmap_unit); @@ -813,7 +813,7 @@ void AOTMappedHeapWriter::relocate_embedded_oops(GrowableArrayCHeap(seg_offset); int length = _heap_root_segments.size_in_elems(seg_idx); - size_t elem_size = UseCompressedOops ? sizeof(narrowOop) : sizeof(oop); + size_t elem_size = heapOopSize; for (int i = 0; i < length; i++) { // There is no source object; these are native oops - load, translate and @@ -833,7 +833,7 @@ void AOTMappedHeapWriter::relocate_embedded_oops(GrowableArrayCHeaplength(); - log_bitmap_usage("oopmap", heap_info->oopmap(), total_bytes / (UseCompressedOops ? sizeof(narrowOop) : sizeof(oop))); + log_bitmap_usage("oopmap", heap_info->oopmap(), total_bytes / heapOopSize); log_bitmap_usage("ptrmap", heap_info->ptrmap(), total_bytes / sizeof(address)); } diff --git a/src/hotspot/share/cds/aotMetaspace.cpp b/src/hotspot/share/cds/aotMetaspace.cpp index ca0fd2f4e9e9..69eb6a56f6ae 100644 --- a/src/hotspot/share/cds/aotMetaspace.cpp +++ b/src/hotspot/share/cds/aotMetaspace.cpp @@ -79,7 +79,6 @@ #include "oops/compressedKlass.hpp" #include "oops/constantPool.inline.hpp" #include "oops/flatArrayKlass.hpp" -#include "oops/inlineKlass.hpp" #include "oops/instanceMirrorKlass.hpp" #include "oops/klass.inline.hpp" #include "oops/objArrayOop.hpp" @@ -87,6 +86,7 @@ #include "oops/oopHandle.hpp" #include "oops/resolvedFieldEntry.hpp" #include "oops/trainingData.hpp" +#include "oops/valueKlass.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/arguments.hpp" #include "runtime/globals.hpp" @@ -615,7 +615,7 @@ static void rewrite_bytecodes(const methodHandle& method) { case btos: new_code = Bytecodes::_fast_bputfield; break; case ztos: new_code = Bytecodes::_fast_zputfield; break; case atos: { - if (rfe->is_flat() || rfe->is_null_free_inline_type()) { + if (rfe->is_flat() || rfe->is_null_free_value_type()) { new_code = Bytecodes::_fast_vputfield; } else { new_code = Bytecodes::_fast_aputfield; diff --git a/src/hotspot/share/cds/aotStreamedHeapWriter.cpp b/src/hotspot/share/cds/aotStreamedHeapWriter.cpp index a8a5a5beb380..64b6c27e78f6 100644 --- a/src/hotspot/share/cds/aotStreamedHeapWriter.cpp +++ b/src/hotspot/share/cds/aotStreamedHeapWriter.cpp @@ -378,7 +378,7 @@ void AOTStreamedHeapWriter::update_header_for_buffered_addr(address buffered_add // in the shared heap. This also has the side effect of pre-initializing the // identity_hash for all shared objects, so they are less likely to be written // into during run time, increasing the potential of memory sharing. - if (src_obj != nullptr && !src_klass->is_inline_klass()) { + if (src_obj != nullptr && !src_klass->is_value_klass()) { intptr_t src_hash = src_obj->identity_hash(); mw = mw.copy_set_hash(src_hash); } @@ -435,7 +435,7 @@ static void log_bitmap_usage(const char* which, BitMap* bitmap, size_t total_bit // Update all oop fields embedded in the buffered objects void AOTStreamedHeapWriter::map_embedded_oops(AOTStreamedHeapInfo* heap_info) { - size_t oopmap_unit = (UseCompressedOops ? sizeof(narrowOop) : sizeof(oop)); + size_t oopmap_unit = heapOopSize; size_t heap_region_byte_size = _buffer_used; heap_info->oopmap()->resize(heap_region_byte_size / oopmap_unit); diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 0e65d9d2101b..576dc5562a89 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -639,7 +639,10 @@ void ArchiveBuilder::make_shallow_copies(DumpRegion *dump_region, void ArchiveBuilder::make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* src_info) { address src = src_info->source_addr(); - int bytes = src_info->size_in_bytes(); + // Symbols may be allocated in C-heap with a size smaller than src_info->size_in_bytes(), so + // copy the exact number of bytes to avoid triggering ASAN error. + int bytes = (src_info->type() == MetaspaceClosureType::SymbolType) ? + ((Symbol*)src)->byte_size() : src_info->size_in_bytes(); char* dest = dump_region->allocate_metaspace_obj(bytes, src, src_info->type(), src_info->read_only(), &_alloc_stats); diff --git a/src/hotspot/share/cds/cppVtables.cpp b/src/hotspot/share/cds/cppVtables.cpp index 7905b4d938b5..e300393bb557 100644 --- a/src/hotspot/share/cds/cppVtables.cpp +++ b/src/hotspot/share/cds/cppVtables.cpp @@ -30,7 +30,6 @@ #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "oops/flatArrayKlass.hpp" -#include "oops/inlineKlass.hpp" #include "oops/instanceClassLoaderKlass.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/instanceMirrorKlass.hpp" @@ -42,6 +41,7 @@ #include "oops/refArrayKlass.hpp" #include "oops/trainingData.hpp" #include "oops/typeArrayKlass.hpp" +#include "oops/valueKlass.hpp" #include "runtime/arguments.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/growableArray.hpp" @@ -90,7 +90,7 @@ using GrowableArray_SigEntry = GrowableArray; f(ObjArrayKlass) \ f(RefArrayKlass) \ f(FlatArrayKlass) \ - f(InlineKlass) \ + f(ValueKlass) \ f(KlassTrainingData) \ f(MethodTrainingData) \ f(CompileTrainingData) \ diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index 9bb5686832a4..126e269db7b5 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -106,8 +106,8 @@ class FileMapRegion: private CDSFileMapRegion { #define CDS_MUST_MATCH_FLAGS_DO(f) \ f(UseArrayFlattening) \ f(UseFieldFlattening) \ - f(InlineTypePassFieldsAsArgs) \ - f(InlineTypeReturnedAsFields) \ + f(ValueTypePassFieldsAsArgs) \ + f(ValueTypeReturnedAsFields) \ f(UseNullFreeNonAtomicValueFlattening) \ f(UseNullFreeAtomicValueFlattening) \ f(UseNullableAtomicValueFlattening) \ diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 5402a5f9309d..2cd96ce718fd 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -446,7 +446,7 @@ void HeapShared::make_archived_object_cache_gc_safe() { // Copy all CachedOopInfo into a new table using a different hashing algorithm archived_object_cache()->iterate_all([&] (OopHandle oh, CachedOopInfo info) { - if (Arguments::is_valhalla_enabled() && oh.resolve()->klass()->is_inline_klass()) { + if (Arguments::is_valhalla_enabled() && oh.resolve()->klass()->is_value_klass()) { // After make_archived_object_cache_gc_safe() returns, // _archived_object_cache->get() is called only from the (future) AOT code // compiler to access heap oops referenced by AOT-compiled method. @@ -818,7 +818,7 @@ void HeapShared::copy_and_rescan_aot_inited_mirror(InstanceKlass* ik) { oop orig_mirror; if (RegeneratedClasses::is_regenerated_object(ik)) { - assert(!ik->is_inline_klass(), "not supported"); + assert(!ik->is_value_klass(), "not supported"); InstanceKlass* orig_ik = RegeneratedClasses::get_original_object(ik); precond(orig_ik->is_initialized()); orig_mirror = orig_ik->java_mirror(); @@ -888,11 +888,11 @@ void HeapShared::copy_and_rescan_aot_inited_mirror(InstanceKlass* ik) { assert(success, "sanity"); } - if (ik->is_inline_klass()) { - InlineKlass* ilk = InlineKlass::cast(ik); - if (ilk->supports_nullable_layouts()) { - oop null_reset_value = ilk->null_reset_value(); - m->obj_field_put(ilk->null_reset_value_offset(), null_reset_value); + if (ik->is_value_klass()) { + ValueKlass* vk = ValueKlass::cast(ik); + if (vk->supports_nullable_layouts()) { + oop null_reset_value = vk->null_reset_value(); + m->obj_field_put(vk->null_reset_value_offset(), null_reset_value); bool success = archive_reachable_objects_from(1, _dump_time_special_subgraph, null_reset_value); assert(success, "sanity"); } @@ -1743,8 +1743,8 @@ void HeapShared::init_box_classes(TRAPS) { } } -// Used by HeapShared::find_inline_classes(). -class HeapShared::InlineKlassFinder : public FieldClosure { +// Used by HeapShared::find_value_classes(). +class HeapShared::ValueKlassFinder : public FieldClosure { KlassSubGraphInfo* _subgraph_info; InstanceKlass* _ik; address _obj; @@ -1754,9 +1754,9 @@ class HeapShared::InlineKlassFinder : public FieldClosure { // (b) an element of a flattened array, or // (c) a flattened field embedded inside a heap object. // For (a), obj is the same as the address of the heap object. - // For (b) and (c), obj points to InlineKlass::cast(_ik)->payload_offset() bytes below + // For (b) and (c), obj points to ValueKlass::cast(_ik)->payload_offset() bytes below // the payload. - InlineKlassFinder(KlassSubGraphInfo* subgraph_info, InstanceKlass* ik, address obj) + ValueKlassFinder(KlassSubGraphInfo* subgraph_info, InstanceKlass* ik, address obj) : _subgraph_info(subgraph_info), _ik(ik), _obj(obj) { precond(obj != nullptr); precond(ik->has_inlined_fields()); @@ -1769,16 +1769,16 @@ class HeapShared::InlineKlassFinder : public FieldClosure { precond(_ik == fd->field_holder()); // The type of this flattened field - InlineKlass* vk = _ik->get_inline_type_field_klass(fd->index()); + ValueKlass* vk = _ik->get_value_type_field_klass(fd->index()); // The "logical address" of this flattened field address field_addr = _obj + fd->offset() - vk->payload_offset(); - if (fd->is_null_free_inline_type() || !vk->is_payload_marked_as_null(field_addr)) { + if (fd->is_null_free_value_type() || !vk->is_payload_marked_as_null(field_addr)) { // Found a non-null flattened instance of vk. Let's record vk. - add_inline_class(_subgraph_info, vk); + add_value_class(_subgraph_info, vk); if (vk->has_inlined_fields()) { - InlineKlassFinder finder(_subgraph_info, vk, field_addr); + ValueKlassFinder finder(_subgraph_info, vk, field_addr); finder.find(); } } @@ -1790,7 +1790,7 @@ class HeapShared::InlineKlassFinder : public FieldClosure { } }; -void HeapShared::add_inline_class(KlassSubGraphInfo* subgraph_info, InlineKlass* k) { +void HeapShared::add_value_class(KlassSubGraphInfo* subgraph_info, ValueKlass* k) { subgraph_info->add_subgraph_object_klass(k); if (InstanceKlass::cast(k)->is_enum_subclass() || (subgraph_info == _dump_time_special_subgraph)) { @@ -1798,8 +1798,8 @@ void HeapShared::add_inline_class(KlassSubGraphInfo* subgraph_info, InlineKlass* } } -// Recursively scan for any InlineKlass K that has least one non-null flattened instance -// inside orig_obj. K should be recorded with add_inline_class(). +// Recursively scan for any ValueKlass K that has least one non-null flattened instance +// inside orig_obj. K should be recorded with add_value_class(). // // Reason for doing this: // @@ -1813,24 +1813,24 @@ void HeapShared::add_inline_class(KlassSubGraphInfo* subgraph_info, InlineKlass* // If only a single instance of Line is archived, HeapShared::archive_object() would // have never visited a (non-flattened) instance of Point, but we must store Point in // AOT-initialized state. This function finds Point. -void HeapShared::find_inline_classes(KlassSubGraphInfo* subgraph_info, oop orig_obj) { +void HeapShared::find_value_classes(KlassSubGraphInfo* subgraph_info, oop orig_obj) { Klass* klass = orig_obj->klass(); if (klass->is_flatArray_klass()) { FlatArrayKlass* fak = FlatArrayKlass::cast(klass); precond(orig_obj->is_flatArray()); flatArrayOop fa = oop_cast(orig_obj); - InlineKlass* elem_k = fak->element_klass(); + ValueKlass* elem_k = fak->element_klass(); bool added = false; for (int i = 0; i < fa->length(); i++) { if (fak->is_null_free_array_klass() || !fa->obj_at_is_null(i)) { if (!added) { - add_inline_class(subgraph_info, elem_k); + add_value_class(subgraph_info, elem_k); } if (elem_k->has_inlined_fields()) { // "logical address" of the i-th array element. address elem = static_cast
(fa->value_at_addr(i, fak->layout_helper())) - elem_k->payload_offset(); - InlineKlassFinder finder(subgraph_info, elem_k, elem); + ValueKlassFinder finder(subgraph_info, elem_k, elem); finder.find(); } } @@ -1838,7 +1838,7 @@ void HeapShared::find_inline_classes(KlassSubGraphInfo* subgraph_info, oop orig_ } else if (klass->is_instance_klass()) { InstanceKlass* ik = InstanceKlass::cast(klass); if (ik->has_inlined_fields()) { - InlineKlassFinder finder(subgraph_info, ik, cast_from_oop
(orig_obj)); + ValueKlassFinder finder(subgraph_info, ik, cast_from_oop
(orig_obj)); finder.find(); } } @@ -1979,7 +1979,7 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap orig_obj->oop_iterate(&pusher); } - find_inline_classes(subgraph_info, orig_obj); + find_value_classes(subgraph_info, orig_obj); if (CDSConfig::is_dumping_aot_linked_classes()) { // The enum klasses are archived with aot-initialized mirror. diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index 993719909d81..a293abbe8880 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -365,14 +365,14 @@ class HeapShared: AllStatic { }; class OopFieldPusher; - class InlineKlassFinder; + class ValueKlassFinder; using PendingOopStack = GrowableArrayCHeap; static PendingOop _object_being_archived; static bool walk_one_object(PendingOopStack* stack, int level, KlassSubGraphInfo* subgraph_info, oop orig_obj, oop referrer); - static void find_inline_classes(KlassSubGraphInfo* subgraph_info, oop orig_obj); - static void add_inline_class(KlassSubGraphInfo* subgraph_info, InlineKlass* k); + static void find_value_classes(KlassSubGraphInfo* subgraph_info, oop orig_obj); + static void add_value_class(KlassSubGraphInfo* subgraph_info, ValueKlass* k); static void reset_archived_object_states(TRAPS); static void ensure_determinism(TRAPS); diff --git a/src/hotspot/share/ci/ciClassList.hpp b/src/hotspot/share/ci/ciClassList.hpp index 5e21c2c07058..954d310fdcd3 100644 --- a/src/hotspot/share/ci/ciClassList.hpp +++ b/src/hotspot/share/ci/ciClassList.hpp @@ -64,7 +64,7 @@ class ciWrapper; class ciReturnAddress; class ciKlass; class ciInstanceKlass; -class ciInlineKlass; +class ciValueKlass; class ciArrayKlass; class ciObjArrayKlass; class ciFlatArrayKlass; @@ -120,7 +120,7 @@ friend class ciReturnAddress; \ friend class ciWrapper; \ friend class ciKlass; \ friend class ciInstanceKlass; \ -friend class ciInlineKlass; \ +friend class ciValueKlass; \ friend class ciArrayKlass; \ friend class ciFlatArrayKlass; \ friend class ciObjArrayKlass; \ diff --git a/src/hotspot/share/ci/ciField.cpp b/src/hotspot/share/ci/ciField.cpp index 8a28f51dd1d7..299e3b2d5fbd 100644 --- a/src/hotspot/share/ci/ciField.cpp +++ b/src/hotspot/share/ci/ciField.cpp @@ -24,11 +24,11 @@ #include "ci/ciConstant.hpp" #include "ci/ciField.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciInstanceKlass.hpp" #include "ci/ciSymbol.hpp" #include "ci/ciSymbols.hpp" #include "ci/ciUtilities.inline.hpp" +#include "ci/ciValueKlass.hpp" #include "classfile/javaClasses.hpp" #include "classfile/vmClasses.hpp" #include "gc/shared/collectedHeap.inline.hpp" @@ -222,16 +222,16 @@ ciField::ciField(fieldDescriptor *fd) : "bootstrap classes must not create & cache unshared fields"); } -// Special copy constructor used to flatten inline type fields by -// copying the fields of the inline type to a new holder klass. +// Special copy constructor used to flatten value type fields by +// copying the fields of the value type to a new holder klass. ciField::ciField(ciField* declared_field, ciField* subfield) { - assert(subfield->holder()->is_inlinetype() || subfield->holder()->is_abstract(), "should only be used for inline type field flattening"); + assert(subfield->holder()->is_value_klass() || subfield->holder()->is_abstract(), "should only be used for value type field flattening"); assert(!subfield->is_flat(), "subfield must not be flat"); assert(declared_field->is_flat(), "declared field must be flat"); _flags = declared_field->flags(); _holder = declared_field->holder(); - _offset = declared_field->offset_in_bytes() + (subfield->offset_in_bytes() - declared_field->type()->as_inline_klass()->payload_offset()); + _offset = declared_field->offset_in_bytes() + (subfield->offset_in_bytes() - declared_field->type()->as_value_klass()->payload_offset()); ResourceMark rm; char buffer[256]; @@ -299,8 +299,8 @@ static bool trust_final_nonstatic_fields(ciInstanceKlass* holder) { // can't be serialized, so there is no hacking of finals going on with them. if (holder->is_hidden()) return true; - // Trust final fields in inline type buffers - if (holder->is_inlinetype()) + // Trust final fields in value type buffers + if (holder->is_value_klass()) return true; // Trust final fields in records if (holder->is_record()) @@ -316,9 +316,9 @@ void ciField::initialize_from(fieldDescriptor* fd) { assert(field_holder != nullptr, "null field_holder"); _holder = CURRENT_ENV->get_instance_klass(field_holder); _is_flat = fd->is_flat(); - _is_null_free = fd->is_null_free_inline_type(); + _is_null_free = fd->is_null_free_value_type(); if (fd->has_null_marker()) { - InlineLayoutInfo* li = field_holder->inline_layout_info_adr(fd->index()); + ValueFieldLayoutInfo* li = field_holder->value_field_layout_info_adr(fd->index()); _null_marker_offset = li->null_marker_offset(); } else { _null_marker_offset = -1; @@ -420,7 +420,7 @@ ciType* ciField::compute_type_impl() { bool ciField::is_atomic() { assert(is_flat(), "should not ask this property for non-flat field %s.%s", holder()->name()->as_utf8(), name()->as_utf8()); - return LayoutKindHelper::is_atomic_flat(_layout_kind) && !type()->as_inline_klass()->is_naturally_atomic(is_null_free()); + return LayoutKindHelper::is_atomic_flat(_layout_kind) && !type()->as_value_klass()->is_naturally_atomic(is_null_free()); } // ------------------------------------------------------------------ @@ -510,7 +510,7 @@ bool ciField::is_autobox_cache() { bool ciField::empty_null_free_initialized_value_field(bool method_is_safe) { ciType* field_type = type(); - return is_null_free() && field_type->is_inlinetype() && field_type->as_inline_klass()->is_empty() && + return is_null_free() && field_type->is_value_klass() && field_type->as_value_klass()->is_empty() && (method_is_safe || is_flat()); } diff --git a/src/hotspot/share/ci/ciFlatArray.cpp b/src/hotspot/share/ci/ciFlatArray.cpp index 0180fbdb8686..5b0bb0bbd0f2 100644 --- a/src/hotspot/share/ci/ciFlatArray.cpp +++ b/src/hotspot/share/ci/ciFlatArray.cpp @@ -26,8 +26,8 @@ #include "ci/ciConstant.hpp" #include "ci/ciField.hpp" #include "ci/ciFlatArray.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciUtilities.inline.hpp" +#include "ci/ciValueKlass.hpp" #include "oops/oop.inline.hpp" // Current value of an element. @@ -67,7 +67,7 @@ ciConstant ciFlatArray::element_value_by_offset(intptr_t element_offset) { } ciConstant ciFlatArray::field_value_by_offset(intptr_t field_offset) { - ciInlineKlass* elt_type = element_type()->as_inline_klass(); + ciValueKlass* elt_type = element_type()->as_value_klass(); FlatArrayKlass* faklass; GUARDED_VM_ENTRY(faklass = FlatArrayKlass::cast(get_arrayOop()->klass());) int lh = faklass->layout_helper(); diff --git a/src/hotspot/share/ci/ciFlatArrayKlass.hpp b/src/hotspot/share/ci/ciFlatArrayKlass.hpp index 197f1fecf530..4de6adff2388 100644 --- a/src/hotspot/share/ci/ciFlatArrayKlass.hpp +++ b/src/hotspot/share/ci/ciFlatArrayKlass.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_VM_CI_CIFLATARRAYKLASS_HPP #define SHARE_VM_CI_CIFLATARRAYKLASS_HPP -#include "ci/ciInlineKlass.hpp" #include "ci/ciObjArrayKlass.hpp" +#include "ci/ciValueKlass.hpp" #include "oops/flatArrayKlass.hpp" // ciFlatArrayKlass @@ -65,7 +65,7 @@ class ciFlatArrayKlass : public ciObjArrayKlass { virtual bool is_flat_array_klass() const override { return true; } virtual ciKlass* exact_klass() override { - assert(element_klass()->as_inline_klass()->exact_klass() != nullptr, "must have exact klass"); + assert(element_klass()->as_value_klass()->exact_klass() != nullptr, "must have exact klass"); return this; } }; diff --git a/src/hotspot/share/ci/ciInstance.cpp b/src/hotspot/share/ci/ciInstance.cpp index 790d3f47f87e..3315b9ca494b 100644 --- a/src/hotspot/share/ci/ciInstance.cpp +++ b/src/hotspot/share/ci/ciInstance.cpp @@ -24,11 +24,11 @@ #include "ci/ciConstant.hpp" #include "ci/ciField.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciInstance.hpp" #include "ci/ciInstanceKlass.hpp" #include "ci/ciNullObject.hpp" #include "ci/ciUtilities.inline.hpp" +#include "ci/ciValueKlass.hpp" #include "classfile/javaClasses.inline.hpp" #include "classfile/vmClasses.hpp" #include "oops/fieldStreams.hpp" @@ -85,7 +85,7 @@ ciConstant ciInstance::field_value_impl(ciField* field) { case T_ARRAY: { if (field->is_flat()) { assert(field->is_atomic(), "do not query atomically a non-atomic flat field"); - InlineKlass* vk = field->type()->as_inline_klass()->get_InlineKlass(); + ValueKlass* vk = field->type()->as_value_klass()->get_ValueKlass(); FlatValuePayload payload = FlatValuePayload::construct_from_parts(obj, offset, vk, field->layout_kind()); oop res = payload.read(THREAD); if (HAS_PENDING_EXCEPTION) { @@ -138,7 +138,7 @@ ciConstant ciInstance::field_value_impl(ciField* field) { ciConstant ciInstance::field_value(ciField* field) { assert(is_loaded(), "invalid access - must be loaded"); assert(field->holder()->is_loaded(), "invalid access - holder must be loaded"); - assert(field->is_static() || field->holder()->is_inlinetype() || klass()->is_subclass_of(field->holder()), + assert(field->is_static() || field->holder()->is_value_klass() || klass()->is_subclass_of(field->holder()), "invalid access - must be subclass"); ciInstanceKlass* klass = this->klass()->as_instance_klass(); int containing_field_idx = klass->field_index_by_offset(field->offset_in_bytes()); @@ -157,8 +157,8 @@ ciConstant ciInstance::field_value(ciField* field) { ciObject* obj = containing_field_value.as_object(); if (obj->is_instance()) { ciInstance* inst = obj->as_instance(); - // inst->klass() must be an inline klass since it is the value of a flat field. - ciInlineKlass* inst_klass = inst->klass()->as_inline_klass(); + // inst->klass() must be a value klass since it is the value of a flat field. + ciValueKlass* inst_klass = inst->klass()->as_value_klass(); ciField* field_in_value_klass = inst_klass->get_field_by_offset(inst_klass->payload_offset() + field->offset_in_bytes() - containing_field->offset_in_bytes(), false); return inst->sub_field_value(field_in_value_klass); } else if (obj->is_null_object()) { @@ -181,7 +181,7 @@ ciConstant ciInstance::field_value(ciField* field) { // the result and must be called only on already cached values (to ensure consistency). // field_value takes care of that. ciConstant ciInstance::sub_field_value(ciField* field) { - precond(klass()->is_inlinetype()); + precond(klass()->is_value_klass()); precond(!field->is_flat()); int offset = field->offset_in_bytes(); BasicType field_btype = field->type()->basic_type(); diff --git a/src/hotspot/share/ci/ciInstanceKlass.cpp b/src/hotspot/share/ci/ciInstanceKlass.cpp index d6791fab709c..9a6ee422a6e4 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.cpp +++ b/src/hotspot/share/ci/ciInstanceKlass.cpp @@ -23,10 +23,10 @@ */ #include "ci/ciField.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciInstance.hpp" #include "ci/ciInstanceKlass.hpp" #include "ci/ciUtilities.inline.hpp" +#include "ci/ciValueKlass.hpp" #include "classfile/javaClasses.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmClasses.hpp" @@ -455,7 +455,7 @@ int ciInstanceKlass::field_index_by_offset(int offset) { } } assert(best_index >= 0, "field not found"); - assert(best_offset == offset || declared_nonstatic_field_at(best_index)->type()->is_inlinetype(), "offset should match for non-inline types"); + assert(best_offset == offset || declared_nonstatic_field_at(best_index)->type()->is_value_klass(), "offset should match for non-value types"); return best_index; } @@ -593,8 +593,8 @@ void ciInstanceKlass::compute_nonstatic_fields_impl(const GrowableArrayget_inline_type_field_klass(fd.index()); - ciInlineKlass* vk = CURRENT_ENV->get_klass(k)->as_inline_klass(); + ValueKlass* k = this_klass->get_value_type_field_klass(fd.index()); + ciValueKlass* vk = CURRENT_ENV->get_klass(k)->as_value_klass(); field_num += vk->nof_nonstatic_fields(); field_num += fd.has_null_marker() ? 1 : 0; } else { @@ -630,9 +630,9 @@ void ciInstanceKlass::compute_nonstatic_fields_impl(const GrowableArrayget_inline_type_field_klass(fd.index()); - ciInlineKlass* vk = CURRENT_ENV->get_klass(k)->as_inline_klass(); - // Iterate over fields of the flat inline type and copy them to 'this' + Klass* k = get_instanceKlass()->get_value_type_field_klass(fd.index()); + ciValueKlass* vk = CURRENT_ENV->get_klass(k)->as_value_klass(); + // Iterate over fields of the flat value type and copy them to 'this' for (int i = 0; i < vk->nof_nonstatic_fields(); ++i) { assert(tmp_fields != nullptr, "should be initialized"); tmp_fields->append(new (arena) ciField(declared_field, vk->nonstatic_field_at(i))); @@ -796,16 +796,16 @@ ciInstanceKlass* ciInstanceKlass::implementor() { return impl; } -bool ciInstanceKlass::can_be_inline_klass(bool is_exact) { +bool ciInstanceKlass::can_be_value_klass(bool is_exact) { if (!Arguments::is_valhalla_enabled()) { return false; } - if (!is_loaded() || is_inlinetype()) { - // Not loaded or known to be an inline klass + if (!is_loaded() || is_value_klass()) { + // Not loaded or known to be a value klass return true; } if (!is_exact) { - // Not exact, check if this is a valid super for an inline klass + // Not exact, check if this is a valid super for a value klass GUARDED_VM_ENTRY( return !get_instanceKlass()->access_flags().is_identity_class() || is_java_lang_Object(); ) @@ -853,10 +853,10 @@ class StaticFinalFieldPrinter : public StaticFieldPrinter { } }; -class InlineTypeFieldPrinter : public StaticFieldPrinter { +class ValueTypeFieldPrinter : public StaticFieldPrinter { oop _obj; public: - InlineTypeFieldPrinter(outputStream* out, oop obj) : + ValueTypeFieldPrinter(outputStream* out, oop obj) : StaticFieldPrinter(out), _obj(obj) { } void do_field(fieldDescriptor* fd) { @@ -886,7 +886,7 @@ void StaticFieldPrinter::do_field_helper(fieldDescriptor* fd, oop mirror, bool i } case T_ARRAY: // fall-through case T_OBJECT: - if (!fd->is_null_free_inline_type()) { + if (!fd->is_null_free_value_type()) { _out->print("%s", fd->signature()->as_quoted_ascii()); oop value = mirror->obj_field_acquire(fd->offset()); if (value == nullptr) { @@ -937,7 +937,7 @@ void StaticFieldPrinter::do_field_helper(fieldDescriptor* fd, oop mirror, bool i } break; } else { - // handling of null free inline type + // handling of null free value type _out->print("%s", fd->signature()->as_quoted_ascii()); ResetNoHandleMark rnhm; Thread* THREAD = Thread::current(); @@ -948,7 +948,7 @@ void StaticFieldPrinter::do_field_helper(fieldDescriptor* fd, oop mirror, bool i InstanceKlass* k = SystemDictionary::find_instance_klass(THREAD, name, Handle(THREAD, holder->class_loader())); guarantee(k != nullptr && !HAS_PENDING_EXCEPTION, "can resolve klass?"); - InlineKlass* vk = InlineKlass::cast(k); + ValueKlass* vk = ValueKlass::cast(k); oop obj; if (is_flat) { int field_offset = fd->offset() - vk->payload_offset(); @@ -956,7 +956,7 @@ void StaticFieldPrinter::do_field_helper(fieldDescriptor* fd, oop mirror, bool i } else { obj = mirror->obj_field_acquire(fd->offset()); } - InlineTypeFieldPrinter print_field(_out, obj); + ValueTypeFieldPrinter print_field(_out, obj); vk->do_nonstatic_fields(&print_field); break; } diff --git a/src/hotspot/share/ci/ciInstanceKlass.hpp b/src/hotspot/share/ci/ciInstanceKlass.hpp index 160c050d4680..b2522697a0df 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.hpp +++ b/src/hotspot/share/ci/ciInstanceKlass.hpp @@ -300,7 +300,7 @@ class ciInstanceKlass : public ciKlass { return (impl != this ? impl : nullptr); } - virtual bool can_be_inline_klass(bool is_exact = false); + virtual bool can_be_value_klass(bool is_exact = false); // Is the defining class loader of this class the default loader? bool uses_default_loader() const; diff --git a/src/hotspot/share/ci/ciKlass.hpp b/src/hotspot/share/ci/ciKlass.hpp index 04112c433430..d156ad7369c0 100644 --- a/src/hotspot/share/ci/ciKlass.hpp +++ b/src/hotspot/share/ci/ciKlass.hpp @@ -107,7 +107,7 @@ class ciKlass : public ciType { return false; } - virtual bool can_be_inline_array_klass() { + virtual bool can_be_value_array_klass() { return Arguments::is_valhalla_enabled() && is_java_lang_Object(); } diff --git a/src/hotspot/share/ci/ciMetadata.hpp b/src/hotspot/share/ci/ciMetadata.hpp index fc94950d09ca..5dc4efc9b8db 100644 --- a/src/hotspot/share/ci/ciMetadata.hpp +++ b/src/hotspot/share/ci/ciMetadata.hpp @@ -55,7 +55,7 @@ class ciMetadata: public ciBaseObject { virtual bool is_method_data() const { return false; } virtual bool is_klass() const { return false; } virtual bool is_instance_klass() const { return false; } - virtual bool is_inlinetype() const { return false; } + virtual bool is_value_klass() const { return false; } virtual bool is_array_klass() const { return false; } virtual bool is_obj_array_klass() const { return false; } virtual bool is_flat_array_klass() const { return false; } @@ -113,9 +113,9 @@ class ciMetadata: public ciBaseObject { assert(is_type_array_klass(), "bad cast"); return (ciTypeArrayKlass*)this; } - ciInlineKlass* as_inline_klass() { - assert(is_inlinetype(), "bad cast"); - return (ciInlineKlass*)this; + ciValueKlass* as_value_klass() { + assert(is_value_klass(), "bad cast"); + return (ciValueKlass*)this; } Metadata* constant_encoding() { return _metadata; } diff --git a/src/hotspot/share/ci/ciMethod.cpp b/src/hotspot/share/ci/ciMethod.cpp index db4bf40271a6..5e9ca7e82516 100644 --- a/src/hotspot/share/ci/ciMethod.cpp +++ b/src/hotspot/share/ci/ciMethod.cpp @@ -712,7 +712,7 @@ bool ciMethod::array_access_profiled_type(int bci, ciKlass*& array_type, ciKlass return false; } -bool ciMethod::acmp_profiled_type(int bci, ciKlass*& left_type, ciKlass*& right_type, ProfilePtrKind& left_ptr, ProfilePtrKind& right_ptr, bool &left_inline_type, bool &right_inline_type) { +bool ciMethod::acmp_profiled_type(int bci, ciKlass*& left_type, ciKlass*& right_type, ProfilePtrKind& left_ptr, ProfilePtrKind& right_ptr, bool &left_value_type, bool &right_value_type) { if (method_data() != nullptr && method_data()->is_mature()) { ciProfileData* data = method_data()->bci_to_data(bci); if (data != nullptr && data->is_ACmpData()) { @@ -721,8 +721,8 @@ bool ciMethod::acmp_profiled_type(int bci, ciKlass*& left_type, ciKlass*& right_ right_type = acmp->right()->valid_type(); left_ptr = acmp->left()->ptr_kind(); right_ptr = acmp->right()->ptr_kind(); - left_inline_type = acmp->left_inline_type(); - right_inline_type = acmp->right_inline_type(); + left_value_type = acmp->left_value_type(); + right_value_type = acmp->right_value_type(); return true; } } diff --git a/src/hotspot/share/ci/ciMethod.hpp b/src/hotspot/share/ci/ciMethod.hpp index 5acaa6a50623..f5dee91e725a 100644 --- a/src/hotspot/share/ci/ciMethod.hpp +++ b/src/hotspot/share/ci/ciMethod.hpp @@ -275,7 +275,7 @@ class ciMethod : public ciMetadata { bool& flat_array, bool& null_free); bool acmp_profiled_type(int bci, ciKlass*& left_type, ciKlass*& right_type, ProfilePtrKind& left_ptr, ProfilePtrKind& right_ptr, - bool& left_inline_type, bool& right_inline_type); + bool& left_value_type, bool& right_value_type); ciField* get_field_at_bci( int bci, bool &will_link); ciMethod* get_method_at_bci(int bci, bool &will_link, ciSignature* *declared_signature); ciMethod* get_method_at_bci(int bci) { @@ -391,7 +391,7 @@ class ciMethod : public ciMetadata { static bool is_consistent_info(ciMethod* declared_method, ciMethod* resolved_method); - // Support for the inline type calling convention + // Support for the value type calling convention bool is_scalarized_arg(int idx) const; bool is_scalarized_buffer_arg(int idx) const; bool has_scalarized_args() const; diff --git a/src/hotspot/share/ci/ciObjArrayKlass.cpp b/src/hotspot/share/ci/ciObjArrayKlass.cpp index 1aa8b398ea49..09ab28e3319a 100644 --- a/src/hotspot/share/ci/ciObjArrayKlass.cpp +++ b/src/hotspot/share/ci/ciObjArrayKlass.cpp @@ -152,8 +152,8 @@ ciObjArrayKlass* ciObjArrayKlass::make_impl(ciKlass* element_klass, bool refined return CURRENT_THREAD_ENV->get_obj_array_klass(array); } - assert(!null_free || element_klass->is_inlinetype(), "Only value class arrays can be null free"); - assert(atomic || element_klass->is_inlinetype(), "Only value class arrays can be non-atomic"); + assert(!null_free || element_klass->is_value_klass(), "Only value class arrays can be null free"); + assert(atomic || element_klass->is_value_klass(), "Only value class arrays can be non-atomic"); const ArrayProperties props = ArrayProperties::Default() .with_null_restricted(null_free) diff --git a/src/hotspot/share/ci/ciObjArrayKlass.hpp b/src/hotspot/share/ci/ciObjArrayKlass.hpp index ddea7278ec8c..84dbe30d93a7 100644 --- a/src/hotspot/share/ci/ciObjArrayKlass.hpp +++ b/src/hotspot/share/ci/ciObjArrayKlass.hpp @@ -76,8 +76,8 @@ class ciObjArrayKlass : public ciArrayKlass { virtual ciKlass* exact_klass(); - virtual bool can_be_inline_array_klass() { - return element_klass()->can_be_inline_klass(); + virtual bool can_be_value_array_klass() { + return element_klass()->can_be_value_klass(); } }; diff --git a/src/hotspot/share/ci/ciObjectFactory.cpp b/src/hotspot/share/ci/ciObjectFactory.cpp index 12cfef50fada..3891c4e6ee91 100644 --- a/src/hotspot/share/ci/ciObjectFactory.cpp +++ b/src/hotspot/share/ci/ciObjectFactory.cpp @@ -25,7 +25,6 @@ #include "ci/ciCallSite.hpp" #include "ci/ciFlatArray.hpp" #include "ci/ciFlatArrayKlass.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciInstance.hpp" #include "ci/ciInstanceKlass.hpp" #include "ci/ciMemberName.hpp" @@ -45,6 +44,7 @@ #include "ci/ciTypeArray.hpp" #include "ci/ciTypeArrayKlass.hpp" #include "ci/ciUtilities.inline.hpp" +#include "ci/ciValueKlass.hpp" #include "classfile/javaClasses.inline.hpp" #include "classfile/vmClasses.hpp" #include "compiler/compiler_globals.hpp" @@ -431,8 +431,8 @@ ciMetadata* ciObjectFactory::create_new_metadata(Metadata* o) { if (o->is_klass()) { Klass* k = (Klass*)o; - if (k->is_inline_klass()) { - return new (arena()) ciInlineKlass(k); + if (k->is_value_klass()) { + return new (arena()) ciValueKlass(k); } else if (k->is_instance_klass()) { assert(!ReplayCompiles || ciReplay::no_replay_state() || !ciReplay::is_klass_unresolved((InstanceKlass*)k), "must be whitelisted for replay compilation"); return new (arena()) ciInstanceKlass(k); diff --git a/src/hotspot/share/ci/ciReplay.cpp b/src/hotspot/share/ci/ciReplay.cpp index af232db004d2..519944ecbd63 100644 --- a/src/hotspot/share/ci/ciReplay.cpp +++ b/src/hotspot/share/ci/ciReplay.cpp @@ -43,12 +43,12 @@ #include "oops/constantPool.inline.hpp" #include "oops/cpCache.inline.hpp" #include "oops/fieldStreams.inline.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/klass.inline.hpp" #include "oops/method.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/oopCast.inline.hpp" #include "oops/resolvedIndyEntry.hpp" +#include "oops/valueKlass.inline.hpp" #include "prims/jvmtiExport.hpp" #include "prims/methodHandles.hpp" #include "runtime/fieldDescriptor.inline.hpp" @@ -1025,16 +1025,16 @@ class CompileReplay : public StackObj { } } - class InlineTypeFieldInitializer : public FieldClosure { + class ValueTypeFieldInitializer : public FieldClosure { oop _vt; CompileReplay* _replay; public: - InlineTypeFieldInitializer(oop vt, CompileReplay* replay) + ValueTypeFieldInitializer(oop vt, CompileReplay* replay) : _vt(vt), _replay(replay) {} void do_field(fieldDescriptor* fd) { BasicType bt = fd->field_type(); - const char* string_value = fd->is_null_free_inline_type() ? nullptr : _replay->parse_escaped_string(); + const char* string_value = fd->is_null_free_value_type() ? nullptr : _replay->parse_escaped_string(); switch (bt) { case T_BYTE: { int value = atoi(string_value); @@ -1082,11 +1082,11 @@ class CompileReplay : public StackObj { } case T_ARRAY: case T_OBJECT: - if (fd->is_null_free_inline_type() && fd->is_flat()) { - InlineKlass* vk = InlineKlass::cast(fd->field_holder()->get_inline_type_field_klass(fd->index())); + if (fd->is_null_free_value_type() && fd->is_flat()) { + ValueKlass* vk = ValueKlass::cast(fd->field_holder()->get_value_type_field_klass(fd->index())); int field_offset = fd->offset() - vk->payload_offset(); oop obj = cast_to_oop(cast_from_oop
(_vt) + field_offset); - InlineTypeFieldInitializer init_fields(obj, _replay); + ValueTypeFieldInitializer init_fields(obj, _replay); vk->do_nonstatic_fields(&init_fields); } else { JavaThread* THREAD = JavaThread::current(); @@ -1155,7 +1155,7 @@ class CompileReplay : public StackObj { Klass* actual_array_klass = parse_klass(CHECK_(true)); Klass* kelem = ObjArrayKlass::cast(actual_array_klass)->element_klass(); ArrayProperties props = ArrayProperties::Default().with_non_atomic(non_atomic).with_null_restricted(null_restricted); - value = oopFactory::new_flatArray(InlineKlass::cast(kelem), length, props, CHECK_(true)); + value = oopFactory::new_flatArray(ValueKlass::cast(kelem), length, props, CHECK_(true)); } else { report_error("unrecognized array kind"); } @@ -1248,11 +1248,11 @@ class CompileReplay : public StackObj { const char* string_value = parse_escaped_string(); double value = atof(string_value); java_mirror->double_field_put(fd.offset(), value); - } else if (fd.is_null_free_inline_type()) { + } else if (fd.is_null_free_value_type()) { Klass* kelem = resolve_klass(field_signature, CHECK); - InlineKlass* vk = InlineKlass::cast(kelem); + ValueKlass* vk = ValueKlass::cast(kelem); oop value = vk->allocate_instance(CHECK); - InlineTypeFieldInitializer init_fields(value, this); + ValueTypeFieldInitializer init_fields(value, this); vk->do_nonstatic_fields(&init_fields); java_mirror->obj_field_put(fd.offset(), value); } else { diff --git a/src/hotspot/share/ci/ciType.cpp b/src/hotspot/share/ci/ciType.cpp index 69c297957518..6480de0b8301 100644 --- a/src/hotspot/share/ci/ciType.cpp +++ b/src/hotspot/share/ci/ciType.cpp @@ -33,7 +33,7 @@ ciType* ciType::_basic_types[T_CONFLICT+1]; // ciType // -// This class represents a Java reference, inline type or primitive type. +// This class represents a Java reference, value type or primitive type. // ------------------------------------------------------------------ // ciType::ciType @@ -146,10 +146,10 @@ ciWrapper::ciWrapper(ciType* type, int properties) _type(type), _properties(properties) { assert(!type->is_wrapper(), "Thou shall not double wrap!"); - assert(type->is_inlinetype() + assert(type->is_value_klass() // An abstract value type is an instance_klass || (type->is_instance_klass() && !type->as_instance_klass()->flags().is_identity()) - // An unloaded inline type is an instance_klass (see ciEnv::get_klass_by_name_impl()) + // An unloaded value type is an instance_klass (see ciEnv::get_klass_by_name_impl()) || (type->is_instance_klass() && !type->is_loaded()), - "should only be used for inline types"); + "should only be used for value types"); } diff --git a/src/hotspot/share/ci/ciType.hpp b/src/hotspot/share/ci/ciType.hpp index 90b4c3a97575..52a36a22934f 100644 --- a/src/hotspot/share/ci/ciType.hpp +++ b/src/hotspot/share/ci/ciType.hpp @@ -29,7 +29,7 @@ // ciType // -// This class represents a Java reference, inline type or primitive type. +// This class represents a Java reference, value type or primitive type. class ciType : public ciMetadata { CI_PACKAGE_ACCESS @@ -76,7 +76,7 @@ class ciType : public ciMetadata { virtual ciType* unwrap() { return this; } virtual bool is_null_free() const { return false; } - virtual bool can_be_inline_klass(bool is_exact = false) { + virtual bool can_be_value_klass(bool is_exact = false) { return false; } diff --git a/src/hotspot/share/ci/ciTypeArrayKlass.hpp b/src/hotspot/share/ci/ciTypeArrayKlass.hpp index 34f82bce3287..e1e39b457f16 100644 --- a/src/hotspot/share/ci/ciTypeArrayKlass.hpp +++ b/src/hotspot/share/ci/ciTypeArrayKlass.hpp @@ -62,7 +62,7 @@ class ciTypeArrayKlass : public ciArrayKlass { return this; } - virtual bool can_be_inline_array_klass() { + virtual bool can_be_value_array_klass() { return false; } }; diff --git a/src/hotspot/share/ci/ciTypeFlow.cpp b/src/hotspot/share/ci/ciTypeFlow.cpp index b18288a88dba..486f057c21a8 100644 --- a/src/hotspot/share/ci/ciTypeFlow.cpp +++ b/src/hotspot/share/ci/ciTypeFlow.cpp @@ -24,13 +24,13 @@ #include "ci/ciConstant.hpp" #include "ci/ciField.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciMethod.hpp" #include "ci/ciMethodData.hpp" #include "ci/ciObjArrayKlass.hpp" #include "ci/ciStreams.hpp" #include "ci/ciTypeArrayKlass.hpp" #include "ci/ciTypeFlow.hpp" +#include "ci/ciValueKlass.hpp" #include "compiler/compileLog.hpp" #include "interpreter/bytecode.hpp" #include "interpreter/bytecodes.hpp" @@ -330,10 +330,10 @@ ciType* ciTypeFlow::StateVector::type_meet_internal(ciType* t1, ciType* t2, ciTy elem = type_meet_internal(elem1, elem2, analyzer)->as_klass(); } // Do an easy shortcut if one type is a super of the other. - if (elem == elem1 && !elem->is_inlinetype()) { + if (elem == elem1 && !elem->is_value_klass()) { assert(k1 == ciArrayKlass::make(elem), "shortcut is OK"); return k1; - } else if (elem == elem2 && !elem->is_inlinetype()) { + } else if (elem == elem2 && !elem->is_value_klass()) { assert(k2 == ciArrayKlass::make(elem), "shortcut is OK"); return k2; } else { @@ -347,7 +347,7 @@ ciType* ciTypeFlow::StateVector::type_meet_internal(ciType* t1, ciType* t2, ciTy assert(k1->is_instance_klass(), "previous cases handle non-instances"); assert(k2->is_instance_klass(), "previous cases handle non-instances"); ciType* result = k1->least_common_ancestor(k2); - if (null_free1 && null_free2 && result->is_inlinetype()) { + if (null_free1 && null_free2 && result->is_value_klass()) { result = analyzer->mark_as_null_free(result); } if (is_early_larval) { @@ -417,12 +417,12 @@ const ciTypeFlow::StateVector* ciTypeFlow::get_start_state() { if (!method()->is_static()) { ciType* holder = method()->holder(); if (method()->is_object_constructor()) { - if (holder->is_inlinetype() || (holder->is_instance_klass() && !holder->as_instance_klass()->flags().is_identity())) { + if (holder->is_value_klass() || (holder->is_instance_klass() && !holder->as_instance_klass()->flags().is_identity())) { // The receiver is early larval (so also null-free) holder = mark_as_early_larval(holder); } } else { - if (holder->is_inlinetype()) { + if (holder->is_value_klass()) { // The receiver is null-free holder = mark_as_null_free(holder); } @@ -657,7 +657,7 @@ void ciTypeFlow::StateVector::do_getstatic(ciBytecodeStream* str) { ciType* field_type = field->type(); if (field->is_static() && field->is_null_free() && !field_type->as_instance_klass()->is_initialized()) { - // Deoptimize if we load from a static field with an uninitialized inline type + // Deoptimize if we load from a static field with an uninitialized value type // because we need to throw an exception if initialization of the type failed. trap(str, field_type->as_klass(), Deoptimization::make_trap_request @@ -802,7 +802,7 @@ void ciTypeFlow::StateVector::do_ldc(ciBytecodeStream* str) { } else { assert(obj->is_instance() || obj->is_array(), "must be java_mirror of klass"); ciType* type = obj->klass(); - if (type->is_inlinetype()) { + if (type->is_value_klass()) { type = outer()->mark_as_null_free(type); } push(type); @@ -843,7 +843,7 @@ void ciTypeFlow::StateVector::do_new(ciBytecodeStream* str) { if (!will_link || str->is_unresolved_klass()) { trap(str, klass, str->get_klass_index()); } else { - if (klass->is_inlinetype()) { + if (klass->is_value_klass()) { push(outer()->mark_as_early_larval(klass)); return; } diff --git a/src/hotspot/share/ci/ciInlineKlass.cpp b/src/hotspot/share/ci/ciValueKlass.cpp similarity index 52% rename from src/hotspot/share/ci/ciInlineKlass.cpp rename to src/hotspot/share/ci/ciValueKlass.cpp index 5e83f7bf648a..0655e18e21e4 100644 --- a/src/hotspot/share/ci/ciInlineKlass.cpp +++ b/src/hotspot/share/ci/ciValueKlass.cpp @@ -24,53 +24,53 @@ #include "ci/ciConstant.hpp" #include "ci/ciField.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciUtilities.inline.hpp" +#include "ci/ciValueKlass.hpp" #include "oops/array.hpp" #include "runtime/signature.hpp" #include "utilities/globalDefinitions.hpp" -// Offset of the first field in the inline type -int ciInlineKlass::payload_offset() const { - GUARDED_VM_ENTRY(return to_InlineKlass()->payload_offset();) +// Offset of the first field in the value type +int ciValueKlass::payload_offset() const { + GUARDED_VM_ENTRY(return to_ValueKlass()->payload_offset();) } // Could any array containing an instance of this value class ever be flat? -bool ciInlineKlass::maybe_flat_in_array() const { - GUARDED_VM_ENTRY(return to_InlineKlass()->maybe_flat_in_array();) +bool ciValueKlass::maybe_flat_in_array() const { + GUARDED_VM_ENTRY(return to_ValueKlass()->maybe_flat_in_array();) } -// Can this inline type be passed as multiple values? -bool ciInlineKlass::can_be_passed_as_fields() const { - GUARDED_VM_ENTRY(return to_InlineKlass()->can_be_passed_as_fields();) +// Can this value type be passed as multiple values? +bool ciValueKlass::can_be_passed_as_fields() const { + GUARDED_VM_ENTRY(return to_ValueKlass()->can_be_passed_as_fields();) } -// Can this inline type be returned as multiple values? -bool ciInlineKlass::can_be_returned_as_fields() const { - GUARDED_VM_ENTRY(return to_InlineKlass()->can_be_returned_as_fields();) +// Can this value type be returned as multiple values? +bool ciValueKlass::can_be_returned_as_fields() const { + GUARDED_VM_ENTRY(return to_ValueKlass()->can_be_returned_as_fields();) } -bool ciInlineKlass::is_empty() { - // Do not use InlineKlass::is_empty_inline_type here because it does - // consider the container empty even if fields of empty inline types +bool ciValueKlass::is_empty() { + // Do not use ValueKlass::is_empty_value_type here because it does + // consider the container empty even if fields of empty value types // are not flat return nof_declared_nonstatic_fields() == 0; } -bool ciInlineKlass::is_cloneable() const { - GUARDED_VM_ENTRY(return get_InlineKlass()->is_cloneable();) +bool ciValueKlass::is_cloneable() const { + GUARDED_VM_ENTRY(return get_ValueKlass()->is_cloneable();) } -int ciInlineKlass::inline_arg_length() const { +int ciValueKlass::value_arg_length() const { VM_ENTRY_MARK; - return get_InlineKlass()->extended_sig()->length(); + return get_ValueKlass()->extended_sig()->length(); } -// When passing an inline type's fields as arguments, count the number +// When passing a value type's fields as arguments, count the number // of argument slots that are needed -int ciInlineKlass::inline_arg_slots() const { +int ciValueKlass::value_arg_slots() const { VM_ENTRY_MARK; - const Array* sig_vk = get_InlineKlass()->extended_sig(); + const Array* sig_vk = get_ValueKlass()->extended_sig(); int slots = 0; for (int i = 0; i < sig_vk->length(); i++) { BasicType bt = sig_vk->at(i)._bt; @@ -82,46 +82,46 @@ int ciInlineKlass::inline_arg_slots() const { return slots; } -bool ciInlineKlass::contains_oops() const { - GUARDED_VM_ENTRY(return get_InlineKlass()->contains_oops();) +bool ciValueKlass::contains_oops() const { + GUARDED_VM_ENTRY(return get_ValueKlass()->contains_oops();) } -int ciInlineKlass::oop_count() const { - GUARDED_VM_ENTRY(return get_InlineKlass()->nonstatic_oop_count();) +int ciValueKlass::oop_count() const { + GUARDED_VM_ENTRY(return get_ValueKlass()->nonstatic_oop_count();) } -address ciInlineKlass::pack_handler() const { - GUARDED_VM_ENTRY(return get_InlineKlass()->pack_handler();) +address ciValueKlass::pack_handler() const { + GUARDED_VM_ENTRY(return get_ValueKlass()->pack_handler();) } -address ciInlineKlass::unpack_handler() const { - GUARDED_VM_ENTRY(return get_InlineKlass()->unpack_handler();) +address ciValueKlass::unpack_handler() const { + GUARDED_VM_ENTRY(return get_ValueKlass()->unpack_handler();) } -InlineKlass* ciInlineKlass::get_InlineKlass() const { - GUARDED_VM_ENTRY(return to_InlineKlass();) +ValueKlass* ciValueKlass::get_ValueKlass() const { + GUARDED_VM_ENTRY(return to_ValueKlass();) } -bool ciInlineKlass::has_null_free_non_atomic_layout() const { - GUARDED_VM_ENTRY(return get_InlineKlass()->has_null_free_non_atomic_layout();) +bool ciValueKlass::has_null_free_non_atomic_layout() const { + GUARDED_VM_ENTRY(return get_ValueKlass()->has_null_free_non_atomic_layout();) } -bool ciInlineKlass::has_null_free_atomic_layout() const { - GUARDED_VM_ENTRY(return get_InlineKlass()->has_null_free_atomic_layout();) +bool ciValueKlass::has_null_free_atomic_layout() const { + GUARDED_VM_ENTRY(return get_ValueKlass()->has_null_free_atomic_layout();) } -bool ciInlineKlass::has_nullable_atomic_layout() const { - GUARDED_VM_ENTRY(return get_InlineKlass()->has_nullable_atomic_layout();) +bool ciValueKlass::has_nullable_atomic_layout() const { + GUARDED_VM_ENTRY(return get_ValueKlass()->has_nullable_atomic_layout();) } -int ciInlineKlass::null_marker_offset_in_payload() const { - GUARDED_VM_ENTRY(return get_InlineKlass()->null_marker_offset_in_payload();) +int ciValueKlass::null_marker_offset_in_payload() const { + GUARDED_VM_ENTRY(return get_ValueKlass()->null_marker_offset_in_payload();) } // Convert size of atomic layout in bytes to corresponding BasicType -BasicType ciInlineKlass::atomic_size_to_basic_type(bool null_free) const { +BasicType ciValueKlass::atomic_size_to_basic_type(bool null_free) const { VM_ENTRY_MARK - InlineKlass* vk = get_InlineKlass(); + ValueKlass* vk = get_ValueKlass(); assert(!null_free || vk->has_null_free_atomic_layout(), "No null-free atomic layout available"); assert( null_free || vk->has_nullable_atomic_layout(), "No nullable atomic layout available"); int size = null_free ? vk->null_free_atomic_size_in_bytes() : vk->nullable_atomic_size_in_bytes(); @@ -140,17 +140,17 @@ BasicType ciInlineKlass::atomic_size_to_basic_type(bool null_free) const { return bt; } -bool ciInlineKlass::is_naturally_atomic(bool null_free) { +bool ciValueKlass::is_naturally_atomic(bool null_free) { return null_free ? (nof_nonstatic_fields() <= 1) : (nof_nonstatic_fields() == 0); } -int ciInlineKlass::field_map_offset() const { - GUARDED_VM_ENTRY(return get_InlineKlass()->acmp_maps_offset();) +int ciValueKlass::field_map_offset() const { + GUARDED_VM_ENTRY(return get_ValueKlass()->acmp_maps_offset();) } -ciConstant ciInlineKlass::get_field_map() const { +ciConstant ciValueKlass::get_field_map() const { VM_ENTRY_MARK - InlineKlass* vk = get_InlineKlass(); + ValueKlass* vk = get_ValueKlass(); oop array = vk->java_mirror()->obj_field(vk->acmp_maps_offset()); return ciConstant(T_ARRAY, CURRENT_ENV->get_object(array)); } @@ -158,14 +158,14 @@ ciConstant ciInlineKlass::get_field_map() const { // All fields of this object are zero even if they are null-free. As a result, this object should // only be used to reset the payload of fields or array elements and should not be leaked // elsewhere. -ciConstant ciInlineKlass::get_null_reset_value() { +ciConstant ciValueKlass::get_null_reset_value() { assert(is_initialized(), "null_reset_value is only allocated during initialization of %s", name()->as_utf8()); VM_ENTRY_MARK - InlineKlass* vk = get_InlineKlass(); + ValueKlass* vk = get_ValueKlass(); oop null_reset_value = vk->null_reset_value(); return ciConstant(T_OBJECT, CURRENT_ENV->get_object(null_reset_value)); } -ArrayDescription ciInlineKlass::array_description_of_array_properties(const ArrayProperties& requested_properties) { - GUARDED_VM_ENTRY(return ObjArrayKlass::array_layout_selection(get_InlineKlass(), requested_properties);) +ArrayDescription ciValueKlass::array_description_of_array_properties(const ArrayProperties& requested_properties) { + GUARDED_VM_ENTRY(return ObjArrayKlass::array_layout_selection(get_ValueKlass(), requested_properties);) } diff --git a/src/hotspot/share/ci/ciInlineKlass.hpp b/src/hotspot/share/ci/ciValueKlass.hpp similarity index 70% rename from src/hotspot/share/ci/ciInlineKlass.hpp rename to src/hotspot/share/ci/ciValueKlass.hpp index d77fbf7e7b77..3bd9292ff4f7 100644 --- a/src/hotspot/share/ci/ciInlineKlass.hpp +++ b/src/hotspot/share/ci/ciValueKlass.hpp @@ -22,57 +22,57 @@ * */ -#ifndef SHARE_VM_CI_CIINLINEKLASS_HPP -#define SHARE_VM_CI_CIINLINEKLASS_HPP +#ifndef SHARE_VM_CI_CIVALUEKLASS_HPP +#define SHARE_VM_CI_CIVALUEKLASS_HPP #include "ci/ciInstanceKlass.hpp" -#include "oops/inlineKlass.hpp" +#include "oops/valueKlass.hpp" -// ciInlineKlass +// ciValueKlass // -// Specialized ciInstanceKlass for inline types. -class ciInlineKlass : public ciInstanceKlass { +// Specialized ciInstanceKlass for value types. +class ciValueKlass : public ciInstanceKlass { CI_PACKAGE_ACCESS private: - InlineKlass* to_InlineKlass() const { - return InlineKlass::cast(get_Klass()); + ValueKlass* to_ValueKlass() const { + return ValueKlass::cast(get_Klass()); } protected: - ciInlineKlass(Klass* h_k) : ciInstanceKlass(h_k) { - assert(is_final(), "InlineKlass must be final"); + ciValueKlass(Klass* h_k) : ciInstanceKlass(h_k) { + assert(is_final(), "ValueKlass must be final"); }; - ciInlineKlass(ciSymbol* name, jobject loader) : + ciValueKlass(ciSymbol* name, jobject loader) : ciInstanceKlass(name, loader, T_OBJECT) {} - const char* type_string() override { return "ciInlineKlass"; } + const char* type_string() override { return "ciValueKlass"; } public: - bool is_inlinetype() const override { return true; } + bool is_value_klass() const override { return true; } - // Inline type fields + // Value type fields int payload_offset() const; bool maybe_flat_in_array() const override; - // Scalarized calling convention support: pass/return this inline type as its + // Scalarized calling convention support: pass/return this value type as its // field components in the calling convention (registers/stack), not as a single oop. - // See InlineKlass::initialize_calling_convention for details. + // See ValueKlass::initialize_calling_convention for details. bool can_be_passed_as_fields() const; bool can_be_returned_as_fields() const; bool is_empty(); bool is_cloneable() const; - int inline_arg_length() const; - int inline_arg_slots() const; + int value_arg_length() const; + int value_arg_slots() const; bool contains_oops() const; int oop_count() const; address pack_handler() const; address unpack_handler() const; - InlineKlass* get_InlineKlass() const; + ValueKlass* get_ValueKlass() const; bool has_null_free_non_atomic_layout() const; bool has_null_free_atomic_layout() const; bool has_nullable_atomic_layout() const; @@ -86,4 +86,4 @@ class ciInlineKlass : public ciInstanceKlass { ArrayDescription array_description_of_array_properties(const ArrayProperties&); }; -#endif // SHARE_VM_CI_CIINLINEKLASS_HPP +#endif // SHARE_VM_CI_CIVALUEKLASS_HPP diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index cd4b32d80465..b689f13b8d7a 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -53,7 +53,6 @@ #include "oops/constantPool.inline.hpp" #include "oops/fieldInfo.hpp" #include "oops/fieldStreams.inline.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/instanceMirrorKlass.hpp" #include "oops/klass.inline.hpp" @@ -63,6 +62,7 @@ #include "oops/oop.inline.hpp" #include "oops/recordComponent.hpp" #include "oops/symbol.hpp" +#include "oops/valueKlass.inline.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiThreadState.hpp" #include "runtime/arguments.hpp" @@ -1394,10 +1394,8 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, assert(nullptr == _fields_annotations, "invariant"); assert(nullptr == _fields_type_annotations, "invariant"); - // "inline type" means concrete value class - bool is_inline_type = !class_access_flags.is_identity_class() && !class_access_flags.is_abstract(); - // "value class" can be either abstract or concrete value class - bool is_value_class = !class_access_flags.is_identity_class() && !class_access_flags.is_interface(); + bool is_concrete_value_class = !class_access_flags.is_identity_class() && !class_access_flags.is_abstract(); + bool is_concrete_or_abstract_value_class = !class_access_flags.is_identity_class() && !class_access_flags.is_interface(); cfs->guarantee_more(2, CHECK); // length const u2 length = cfs->get_u2_fast(); *java_fields_count_ptr = length; @@ -1406,16 +1404,16 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, const InjectedField* const injected = JavaClasses::get_injected(_class_name, &num_injected); - // Two more slots are required for inline classes: + // Two more slots are required for concrete value classes: // - The static field ".null_reset" which carries the nullable flat layout // representation of null, added below // - The nonstatic field ".empty" the JVM injects when detecting an empty - // inline class, added in FieldLayoutBuilder::compute_inline_class_layout - // One more slot is required for both abstract value class and inline classes: + // value class, added in FieldLayoutBuilder::compute_value_class_layout + // One more slot is required for both concrete and abstract value classes: // - The static field ".acmp_maps" for acmp and identity hash, tracks // nonstatic fields both inherited or declared, added below - const int total_fields = length + num_injected + (is_inline_type ? 2 : 0) - + (is_value_class ? 1 : 0); + const int total_fields = length + num_injected + (is_concrete_value_class ? 2 : 0) + + (is_concrete_or_abstract_value_class ? 1 : 0); // Allocate a temporary resource array to collect field data. // After parsing all fields, data are stored in a UNSIGNED5 compressed stream. @@ -1427,7 +1425,7 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, cfs->guarantee_more(8, CHECK); jint recognized_modifiers = JVM_RECOGNIZED_FIELD_MODIFIERS; - if (!supports_inline_types()) { + if (!supports_value_types()) { recognized_modifiers &= ~JVM_ACC_STRICT_INIT; } @@ -1488,7 +1486,7 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, class_name()->as_C_string(), name->as_C_string(), sig->as_C_string()); return; } - if (!supports_inline_types()) { + if (!supports_value_types()) { Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(), @@ -1527,7 +1525,7 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, } if (is_null_restricted) { - fieldFlags.update_null_free_inline_type(true); + fieldFlags.update_null_free_value_type(true); if (is_static) { _has_null_restricted_static_fields = true; } @@ -1549,8 +1547,12 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, if (fi.field_flags().is_contended()) { _has_contended_fields = true; } - if (access_flags.is_strict() && access_flags.is_static()) { - _has_strict_static_fields = true; + if (access_flags.is_strict()) { + if (access_flags.is_static()) { + _has_strict_static_fields = true; + } else { + _has_strict_instance_fields = true; + } } _temp_field_info->append(fi); } @@ -1588,7 +1590,7 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, } } - if (is_inline_type) { + if (is_concrete_value_class) { // Inject static ".null_reset" field. This is an all-zero value with its null-channel set to zero. // It should never be seen by user code, it is used when writing "null" to a nullable flat field // The all-zero value ensure that any embedded oop will be set to null, to avoid keeping dead objects @@ -3151,7 +3153,7 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(const ClassFileStrea flags |= JVM_ACC_ABSTRACT; } - if (!supports_inline_types()) { + if (!supports_value_types()) { const bool is_module = (flags & JVM_ACC_MODULE) != 0; const bool is_interface = (flags & JVM_ACC_INTERFACE) != 0; if (!is_module && !is_interface) { @@ -3971,7 +3973,7 @@ void ClassFileParser::apply_parsed_class_metadata( this_klass->set_annotations(_combined_annotations); this_klass->set_permitted_subclasses(_permitted_subclasses); this_klass->set_record_components(_record_components); - this_klass->set_inline_layout_info_array(_inline_layout_info_array); + this_klass->set_value_field_layout_info_array(_value_field_layout_info_array); DEBUG_ONLY(FieldInfoStream::validate_search_table(_cp, _fieldinfo_stream, _fieldinfo_search_table)); @@ -4203,8 +4205,8 @@ void ClassFileParser::set_precomputed_flags(InstanceKlass* ik) { } } -bool ClassFileParser::supports_inline_types() const { - // Inline types are only supported by class file version 71.65535 and later +bool ClassFileParser::supports_value_types() const { + // Value types are only supported by class file version 71.65535 and later return _major_version > JAVA_28_VERSION || (_major_version == JAVA_28_VERSION && _minor_version == JAVA_PREVIEW_MINOR_VERSION); } @@ -4511,7 +4513,7 @@ void ClassFileParser::verify_legal_class_modifiers(jint flags, Symbol* inner_nam const bool is_enum = (flags & JVM_ACC_ENUM) != 0; const bool is_annotation = (flags & JVM_ACC_ANNOTATION) != 0; const bool major_gte_1_5 = _major_version >= JAVA_1_5_VERSION; - const bool valid_value_class = is_identity || is_interface || (supports_inline_types() && (is_abstract || is_final)); + const bool valid_value_class = is_identity || is_interface || (supports_value_types() && (is_abstract || is_final)); if ((is_abstract && is_final) || (is_interface && !is_abstract) || @@ -4636,10 +4638,9 @@ void ClassFileParser:: verify_legal_field_modifiers(jint flags, const char* error_msg = ""; // There is some overlap in the checks that apply, for example interface fields - // must be static, static fields can't be strict, and therefore interfaces can't - // have strict fields. So we don't have to check every possible invalid combination - // individually as long as all are covered. Once we have found an illegal combination - // we can stop checking. + // must be static, therefore interfaces can't have strict instance fields. + // We don't have to check every possible invalid combination individually as long as + // all are covered. Once we have found an illegal combination we can stop checking. if (!is_illegal) { if (is_interface) { @@ -4656,7 +4657,7 @@ void ClassFileParser:: verify_legal_field_modifiers(jint flags, } else if (is_final && is_volatile) { is_illegal = true; error_msg = "fields cannot be final and volatile"; - } else if (supports_inline_types()) { + } else if (supports_value_types()) { if (!is_identity_class && !is_static && (!is_strict || !is_final)) { is_illegal = true; error_msg = "value class fields must be either non-static final and strict, or static"; @@ -5365,9 +5366,9 @@ void ClassFileParser::create_acmp_maps(InstanceKlass* ik, TRAPS) { ik->set_acmp_maps_array(acmp_maps_array); } -// See the declarations of _fast_acmp_offset and _fast_acmp_mask in InlineKlass::Members +// See the declarations of _fast_acmp_offset and _fast_acmp_mask in ValueKlass::Members // for details about the fast path logic, and the meaning of these values. -void ClassFileParser::set_fast_acmp_members(InlineKlass* vk) const { +void ClassFileParser::set_fast_acmp_members(ValueKlass* vk) const { if (_layout_info->_oop_acmp_map->length() > 0) { // Oops are not allowed in the fast path return; } @@ -5483,9 +5484,9 @@ void ClassFileParser::set_fast_acmp_members(InlineKlass* vk) const { #endif // VM_LITTLE_ENDIAN } -// See the declarations of _fast_hashcode_offset and _fast_hashcode_shift in InlineKlass::Members +// See the declarations of _fast_hashcode_offset and _fast_hashcode_shift in ValueKlass::Members // for details about the fast path logic, and the meaning of these values. -void ClassFileParser::set_fast_hashcode_members(InlineKlass* vk) const { +void ClassFileParser::set_fast_hashcode_members(ValueKlass* vk) const { if (_layout_info->_oop_acmp_map->length() > 0) { // Oops are not allowed in the fast path return; } @@ -5545,6 +5546,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, ik->set_nonstatic_field_size(_layout_info->_nonstatic_field_size); ik->set_has_nonstatic_fields(_layout_info->_has_nonstatic_fields); ik->set_has_strict_static_fields(_has_strict_static_fields); + ik->set_has_strict_instance_fields(_has_strict_instance_fields); if (_layout_info->_is_naturally_atomic) { ik->set_is_naturally_atomic(); @@ -5560,15 +5562,15 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, ik->set_has_null_restricted_static_fields(); for (int i = 0; i < _temp_field_info->length(); i++) { FieldInfo& fieldinfo = _temp_field_info->at(i); - if (fieldinfo.access_flags().is_static() && fieldinfo.field_flags().is_null_free_inline_type()) { + if (fieldinfo.access_flags().is_static() && fieldinfo.field_flags().is_null_free_value_type()) { Symbol* sig = fieldinfo.signature(_cp); assert(Signature::has_envelope(sig), "Must already have been checked"); TempNewSymbol name = Signature::strip_envelope(sig); if (name == _class_name) { // Replace the nullptr previously stored now that we have the InstanceKlass for this klass. - _inline_layout_info_array->adr_at(fieldinfo.index())->set_klass(InlineKlass::cast(ik)); + _value_field_layout_info_array->adr_at(fieldinfo.index())->set_klass(ValueKlass::cast(ik)); } - assert(_inline_layout_info_array->adr_at(fieldinfo.index())->klass()->is_inline_klass(), "Must be"); + assert(_value_field_layout_info_array->adr_at(fieldinfo.index())->klass()->is_value_klass(), "Must be"); } } } @@ -5594,7 +5596,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, assert(nullptr == _combined_annotations, "invariant"); assert(nullptr == _record_components, "invariant"); assert(nullptr == _permitted_subclasses, "invariant"); - assert(nullptr == _inline_layout_info_array, "invariant"); + assert(nullptr == _value_field_layout_info_array, "invariant"); if (_has_localvariable_table) { ik->set_has_localvariable_table(true); @@ -5733,8 +5735,8 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, } } - if (is_inline_type()) { - InlineKlass* vk = InlineKlass::cast(ik); + if (is_concrete_value_class()) { + ValueKlass* vk = ValueKlass::cast(ik); vk->set_payload_alignment(_layout_info->_payload_alignment); vk->set_payload_offset(_layout_info->_payload_offset); vk->set_payload_size_in_bytes(_layout_info->_payload_size_in_bytes); @@ -5745,7 +5747,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, vk->set_nullable_non_atomic_size_in_bytes(_layout_info->_nullable_non_atomic_layout_size_in_bytes); vk->set_null_marker_offset(_layout_info->_null_marker_offset); vk->set_null_reset_value_offset(_layout_info->_null_reset_value_offset); - if (_layout_info->_is_empty_inline_klass) vk->set_is_empty_inline_type(); + if (_layout_info->_is_empty_value_klass) vk->set_is_empty_value_type(); if (UseAcmpFastPath) { set_fast_acmp_members(vk); @@ -5860,7 +5862,7 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream, _klass_to_deallocate(nullptr), _parsed_annotations(nullptr), _layout_info(nullptr), - _inline_layout_info_array(nullptr), + _value_field_layout_info_array(nullptr), _temp_field_info(nullptr), _method_ordering(nullptr), _all_mirandas(nullptr), @@ -5890,6 +5892,7 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream, _has_contended_fields(false), _has_aot_runtime_setup_method(false), _has_strict_static_fields(false), + _has_strict_instance_fields(false), _has_null_restricted_static_fields(false), _must_be_atomic(true), _has_finalizer(false), @@ -5934,7 +5937,7 @@ void ClassFileParser::clear_class_metadata() { _class_annotations = _class_type_annotations = nullptr; _fields_annotations = _fields_type_annotations = nullptr; _record_components = nullptr; - _inline_layout_info_array = nullptr; + _value_field_layout_info_array = nullptr; } // Destructor to clean up @@ -5954,8 +5957,8 @@ ClassFileParser::~ClassFileParser() { MetadataFactory::free_array(_loader_data, _fields_status); } - if (_inline_layout_info_array != nullptr) { - MetadataFactory::free_array(_loader_data, _inline_layout_info_array); + if (_value_field_layout_info_array != nullptr) { + MetadataFactory::free_array(_loader_data, _value_field_layout_info_array); } if (_methods != nullptr) { @@ -6084,7 +6087,7 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream, } // Fixing ACC_SUPER/ACC_IDENTITY for old class files - if (!supports_inline_types()) { + if (!supports_value_types()) { const bool is_module = (flags & JVM_ACC_MODULE) != 0; const bool is_interface = (flags & JVM_ACC_INTERFACE) != 0; if (!is_module && !is_interface) { @@ -6410,17 +6413,17 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st _layout_info = new FieldLayoutInfo(); FieldLayoutBuilder lb(class_name(), loader_data(), super_klass(), _cp, /*_fields*/ _temp_field_info, - access_flags().is_identity_class() && _parsed_annotations->is_contended(), is_inline_type(), + access_flags().is_identity_class() && _parsed_annotations->is_contended(), is_concrete_value_class(), access_flags().is_abstract() && !access_flags().is_identity_class() && !access_flags().is_interface(), - _must_be_atomic, _layout_info, _inline_layout_info_array); + _must_be_atomic, _layout_info, _value_field_layout_info_array); lb.build_layout(); // If it turned out that we didn't inline any of the fields, we deallocate - // the array of InlineLayoutInfo since it isn't needed, and so it isn't + // the array of ValueFieldLayoutInfo since it isn't needed, and so it isn't // transferred to the allocated InstanceKlass. - if (_inline_layout_info_array != nullptr && !(_layout_info->_has_inlined_fields || _has_null_restricted_static_fields)) { - MetadataFactory::free_array(_loader_data, _inline_layout_info_array); - _inline_layout_info_array = nullptr; + if (_value_field_layout_info_array != nullptr && !(_layout_info->_has_inlined_fields || _has_null_restricted_static_fields)) { + MetadataFactory::free_array(_loader_data, _value_field_layout_info_array); + _value_field_layout_info_array = nullptr; } int injected_fields_count = _temp_field_info->length() - _java_fields_count; @@ -6471,17 +6474,17 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st void ClassFileParser::fetch_field_classes(ConstantPool* cp, TRAPS) { for (int i = 0; i < _temp_field_info->length(); i++) { FieldInfo& fieldinfo = _temp_field_info->at(i); - if (fieldinfo.access_flags().is_static() && !fieldinfo.field_flags().is_null_free_inline_type()) continue; + if (fieldinfo.access_flags().is_static() && !fieldinfo.field_flags().is_null_free_value_type()) continue; Symbol* sig = fieldinfo.signature(cp); if (Signature::has_envelope(sig)) { TempNewSymbol name = Signature::strip_envelope(sig); if (name == _class_name) { - if (fieldinfo.field_flags().is_null_free_inline_type() && !is_inline_type()) { - fieldinfo.field_flags_addr()->update_null_free_inline_type(false); + if (fieldinfo.field_flags().is_null_free_value_type() && !is_concrete_value_class()) { + fieldinfo.field_flags_addr()->update_null_free_value_type(false); } else { - // Dummy setting to trigger the allocation of the inline_layout_info array - - // the real pointer will be set later in ::fill_instance_klass, once the InlineKlass has been allocated. - set_inline_layout_info_klass(fieldinfo.index(), nullptr, CHECK); + // Dummy setting to trigger the allocation of the value_field_layout_info array - + // the real pointer will be set later in ::fill_instance_klass, once the ValueKlass has been allocated. + set_value_field_layout_info_klass(fieldinfo.index(), nullptr, CHECK); } continue; } @@ -6498,8 +6501,8 @@ void ClassFileParser::fetch_field_classes(ConstantPool* cp, TRAPS) { assert((klass == nullptr) == HAS_PENDING_EXCEPTION, "Must be the same"); if (klass != nullptr) { - if (klass->is_inline_klass()) { - set_inline_layout_info_klass(fieldinfo.index(), InlineKlass::cast(klass), CHECK); + if (klass->is_value_klass()) { + set_value_field_layout_info_klass(fieldinfo.index(), ValueKlass::cast(klass), CHECK); log_info(class, preload)("Preloading of class %s during loading of class %s " "(cause: field type in LoadableDescriptors attribute) succeeded", name->as_C_string(), _class_name->as_C_string()); @@ -6508,12 +6511,12 @@ void ClassFileParser::fetch_field_classes(ConstantPool* cp, TRAPS) { log_info(class, preload)("Preloading of class %s during loading of class %s " "(cause: field type in LoadableDescriptors attribute) but loaded class is not a value class", name->as_C_string(), _class_name->as_C_string()); - if (fieldinfo.field_flags().is_null_free_inline_type()) { + if (fieldinfo.field_flags().is_null_free_value_type()) { log_warning(class, preload)("After preloading of class %s during loading of class %s " "field was annotated with @NullRestricted but loaded class is not a value class, " "the annotation is ignored", name->as_C_string(), _class_name->as_C_string()); - fieldinfo.field_flags_addr()->update_null_free_inline_type(false); + fieldinfo.field_flags_addr()->update_null_free_value_type(false); } } } else { @@ -6521,12 +6524,12 @@ void ClassFileParser::fetch_field_classes(ConstantPool* cp, TRAPS) { "(cause: field type in LoadableDescriptors attribute) failed : %s", name->as_C_string(), _class_name->as_C_string(), PENDING_EXCEPTION->klass()->name()->as_C_string()); - if (fieldinfo.field_flags().is_null_free_inline_type()) { + if (fieldinfo.field_flags().is_null_free_value_type()) { log_warning(class, preload)("After preloading of class %s during loading of class %s failed," "field was annotated with @NullRestricted but class is unknown, " "the annotation is ignored", name->as_C_string(), _class_name->as_C_string()); - fieldinfo.field_flags_addr()->update_null_free_inline_type(false); + fieldinfo.field_flags_addr()->update_null_free_value_type(false); } // Loads triggered by the LoadableDescriptors attribute are speculative, failures must not @@ -6536,13 +6539,13 @@ void ClassFileParser::fetch_field_classes(ConstantPool* cp, TRAPS) { } else { oop loader = loader_data()->class_loader(); InstanceKlass* klass = SystemDictionary::find_instance_klass(THREAD, name, Handle(THREAD, loader)); - if (klass != nullptr && klass->is_inline_klass()) { - set_inline_layout_info_klass(fieldinfo.index(), InlineKlass::cast(klass), CHECK); + if (klass != nullptr && klass->is_value_klass()) { + set_value_field_layout_info_klass(fieldinfo.index(), ValueKlass::cast(klass), CHECK); ResourceMark rm(THREAD); log_info(class, preload)("During loading of class %s , class %s found in local system dictionary" "(field type not in LoadableDescriptors attribute)", _class_name->as_C_string(), name->as_C_string()); - } else if (fieldinfo.field_flags().is_null_free_inline_type()) { + } else if (fieldinfo.field_flags().is_null_free_value_type()) { ResourceMark rm(THREAD); if (klass == nullptr) { log_warning(class, preload)("During loading of class %s, class %s is unknown, " @@ -6555,7 +6558,7 @@ void ClassFileParser::fetch_field_classes(ConstantPool* cp, TRAPS) { "@NullRestricted, the annotation is ignored", _class_name->as_C_string(), name->as_C_string()); } - fieldinfo.field_flags_addr()->update_null_free_inline_type(false); + fieldinfo.field_flags_addr()->update_null_free_value_type(false); } } } @@ -6573,19 +6576,19 @@ void ClassFileParser::set_klass(InstanceKlass* klass) { _klass = klass; } -void ClassFileParser::set_inline_layout_info_klass(int field_index, InlineKlass* ik, TRAPS) { +void ClassFileParser::set_value_field_layout_info_klass(int field_index, ValueKlass* vk, TRAPS) { assert(field_index >= 0 && field_index < java_fields_count(), "IOOB: 0 <= %d < %d", field_index, (int)java_fields_count()); - // The array of InlineLayoutInfo is allocated on demand. This way the array is + // The array of ValueFieldLayoutInfo is allocated on demand. This way the array is // never allocated for an InstanceKlass which has no need for this information. - if (_inline_layout_info_array == nullptr) { - _inline_layout_info_array = MetadataFactory::new_array(_loader_data, - java_fields_count(), - CHECK); + if (_value_field_layout_info_array == nullptr) { + _value_field_layout_info_array = MetadataFactory::new_array(_loader_data, + java_fields_count(), + CHECK); } // Set the Klass for the field's index - _inline_layout_info_array->adr_at(field_index)->set_klass(ik); + _value_field_layout_info_array->adr_at(field_index)->set_klass(vk); } void ClassFileParser::set_klass_to_deallocate(InstanceKlass* klass) { diff --git a/src/hotspot/share/classfile/classFileParser.hpp b/src/hotspot/share/classfile/classFileParser.hpp index fe5b58dc4be0..945d965fe7a5 100644 --- a/src/hotspot/share/classfile/classFileParser.hpp +++ b/src/hotspot/share/classfile/classFileParser.hpp @@ -99,7 +99,7 @@ class FieldLayoutInfo : public ResourceObj { bool _is_naturally_atomic; bool _must_be_atomic; bool _has_inlined_fields; - bool _is_empty_inline_klass; + bool _is_empty_value_klass; FieldLayoutInfo() : oop_map_blocks(nullptr), _nonoop_acmp_map(nullptr), _oop_acmp_map(nullptr), _instance_size(-1), _nonstatic_field_size(-1), _static_field_size(-1), _payload_alignment(-1), _payload_offset(-1), _payload_size_in_bytes(-1), @@ -108,7 +108,7 @@ class FieldLayoutInfo : public ResourceObj { _nullable_non_atomic_layout_size_in_bytes(-1), _null_marker_offset(-1), _null_reset_value_offset(-1), _acmp_maps_offset(-1), _has_nonstatic_fields(false), _is_naturally_atomic(false), _must_be_atomic(false), - _has_inlined_fields(false), _is_empty_inline_klass(false) { } + _has_inlined_fields(false), _is_empty_value_klass(false) { } }; // Parser for for .class files @@ -178,7 +178,7 @@ class ClassFileParser { ClassAnnotationCollector* _parsed_annotations; FieldLayoutInfo* _layout_info; - Array* _inline_layout_info_array; + Array* _value_field_layout_info_array; GrowableArray* _temp_field_info; const intArray* _method_ordering; GrowableArray* _all_mirandas; @@ -230,6 +230,7 @@ class ClassFileParser { bool _has_contended_fields; bool _has_aot_runtime_setup_method; bool _has_strict_static_fields; + bool _has_strict_instance_fields; bool _has_null_restricted_static_fields; bool _must_be_atomic; @@ -253,7 +254,7 @@ class ClassFileParser { void set_klass(InstanceKlass* instance); - void set_inline_layout_info_klass(int field_index, InlineKlass* ik, TRAPS); + void set_value_field_layout_info_klass(int field_index, ValueKlass* vk, TRAPS); void set_class_bad_constant_seen(short bad_constant); short class_bad_constant_seen() { return _bad_constant_seen; } @@ -538,12 +539,12 @@ class ClassFileParser { void update_class_name(Symbol* new_name); - // Check if the class file supports inline types - bool supports_inline_types() const; + // Check if the class file supports value types + bool supports_value_types() const; void create_acmp_maps(InstanceKlass* ik, TRAPS); - void set_fast_acmp_members(InlineKlass* vk) const; - void set_fast_hashcode_members(InlineKlass* vk) const; + void set_fast_acmp_members(ValueKlass* vk) const; + void set_fast_hashcode_members(ValueKlass* vk) const; public: ClassFileParser(ClassFileStream* stream, @@ -574,8 +575,7 @@ class ClassFileParser { bool is_hidden() const { return _is_hidden; } bool is_interface() const { return _access_flags.is_interface(); } - // Being an inline type means being a concrete value class - bool is_inline_type() const { return !_access_flags.is_identity_class() && !_access_flags.is_interface() && !_access_flags.is_abstract(); } + bool is_concrete_value_class() const { return !_access_flags.is_identity_class() && !_access_flags.is_interface() && !_access_flags.is_abstract(); } bool is_identity_class() const { return _access_flags.is_identity_class(); } bool has_inlined_fields() const { return _layout_info->_has_inlined_fields; } diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp index 27a899481a8f..2c74d255d97e 100644 --- a/src/hotspot/share/classfile/classLoaderData.cpp +++ b/src/hotspot/share/classfile/classLoaderData.cpp @@ -66,11 +66,11 @@ #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/access.inline.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/jmethodIDTable.hpp" #include "oops/klass.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/oopHandle.inline.hpp" +#include "oops/valueKlass.inline.hpp" #include "oops/verifyOopClosure.hpp" #include "oops/weakHandle.inline.hpp" #include "runtime/arguments.hpp" @@ -432,11 +432,11 @@ void ClassLoaderData::classes_do(void f(InstanceKlass*)) { } } -void ClassLoaderData::inline_classes_do(void f(InlineKlass*)) { +void ClassLoaderData::value_classes_do(void f(ValueKlass*)) { // Lock-free access requires load_acquire for (Klass* k = AtomicAccess::load_acquire(&_klasses); k != nullptr; k = k->next_link()) { - if (k->is_inline_klass()) { - f(InlineKlass::cast(k)); + if (k->is_value_klass()) { + f(ValueKlass::cast(k)); } assert(k != k->next_link(), "no loops!"); } @@ -620,7 +620,7 @@ void ClassLoaderData::unload() { // if they are not already on the _klasses list. free_deallocate_list_C_heap_structures(); - inline_classes_do(InlineKlass::cleanup); + value_classes_do(ValueKlass::cleanup); // Clean up class dependencies and tell serviceability tools // these classes are unloading. This must be called @@ -903,10 +903,10 @@ void ClassLoaderData::free_deallocate_list() { MetadataFactory::free_metadata(this, (ConstantPool*)m); } else if (m->is_klass()) { JFR_ONLY(Jfr::on_deallocation(static_cast(m));) - if (!((Klass*)m)->is_inline_klass()) { + if (!((Klass*)m)->is_value_klass()) { MetadataFactory::free_metadata(this, (InstanceKlass*)m); } else { - MetadataFactory::free_metadata(this, (InlineKlass*)m); + MetadataFactory::free_metadata(this, (ValueKlass*)m); } } else { ShouldNotReachHere(); diff --git a/src/hotspot/share/classfile/classLoaderData.hpp b/src/hotspot/share/classfile/classLoaderData.hpp index 1b2468b6a93a..425194989d5c 100644 --- a/src/hotspot/share/classfile/classLoaderData.hpp +++ b/src/hotspot/share/classfile/classLoaderData.hpp @@ -210,7 +210,7 @@ class ClassLoaderData : public CHeapObj { void loaded_classes_do(KlassClosure* klass_closure); void classes_do(void f(InstanceKlass*)); - void inline_classes_do(void f(InlineKlass*)); + void value_classes_do(void f(ValueKlass*)); void methods_do(void f(Method*)); void modules_do(void f(ModuleEntry*)); void packages_do(void f(PackageEntry*)); diff --git a/src/hotspot/share/classfile/fieldLayoutBuilder.cpp b/src/hotspot/share/classfile/fieldLayoutBuilder.cpp index 49cc3ea337b1..7bdd4ea2c59f 100644 --- a/src/hotspot/share/classfile/fieldLayoutBuilder.cpp +++ b/src/hotspot/share/classfile/fieldLayoutBuilder.cpp @@ -30,15 +30,15 @@ #include "memory/resourceArea.hpp" #include "oops/array.hpp" #include "oops/fieldStreams.inline.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/instanceMirrorKlass.hpp" #include "oops/klass.inline.hpp" +#include "oops/valueKlass.inline.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "utilities/align.hpp" #include "utilities/powerOfTwo.hpp" -static LayoutKind field_layout_selection(FieldInfo field_info, Array* inline_layout_info_array, +static LayoutKind field_layout_selection(FieldInfo field_info, Array* value_field_layout_info_array, bool can_use_atomic_flat) { // The can_use_atomic_flat argument indicates if an atomic flat layout can be used for this field. @@ -65,15 +65,15 @@ static LayoutKind field_layout_selection(FieldInfo field_info, Arrayadr_at(field_info.index())->klass() == nullptr) { + if (value_field_layout_info_array == nullptr || value_field_layout_info_array->adr_at(field_info.index())->klass() == nullptr) { // field's type is not a known value class, using a reference return LayoutKind::REFERENCE; } - InlineLayoutInfo* inline_field_info = inline_layout_info_array->adr_at(field_info.index()); - InlineKlass* vk = inline_field_info->klass(); + ValueFieldLayoutInfo* value_field_layout_info = value_field_layout_info_array->adr_at(field_info.index()); + ValueKlass* vk = value_field_layout_info->klass(); - if (field_info.field_flags().is_null_free_inline_type()) { + if (field_info.field_flags().is_null_free_value_type()) { assert(field_info.access_flags().is_strict(), "null-free fields must be strict"); if (vk->must_be_atomic()) { if (vk->is_naturally_atomic(true /* null-free */) && vk->has_null_free_non_atomic_layout()) { @@ -93,7 +93,7 @@ static LayoutKind field_layout_selection(FieldInfo field_info, Arrayis_empty_inline_type() && vk->has_nullable_non_atomic_layout()) { + if (vk->is_empty_value_type() && vk->has_nullable_non_atomic_layout()) { return LayoutKind::NULLABLE_NON_ATOMIC_FLAT; } if (UseNullableAtomicValueFlattening && vk->has_nullable_atomic_layout()) { @@ -104,12 +104,12 @@ static LayoutKind field_layout_selection(FieldInfo field_info, Array* inline_layout_info_array, +static LayoutKind adjust_with_budget(FieldInfo field_info, Array* value_field_layout_info_array, LayoutKind lk, int& budget) { if (lk == LayoutKind::REFERENCE) return lk; assert(LayoutKindHelper::is_flat((lk)), "Must be"); - InlineLayoutInfo* inline_field_info = inline_layout_info_array->adr_at(field_info.index()); - InlineKlass* vk = inline_field_info->klass(); + ValueFieldLayoutInfo* value_field_layout_info = value_field_layout_info_array->adr_at(field_info.index()); + ValueKlass* vk = value_field_layout_info->klass(); int size = vk->layout_size_in_bytes(lk); if (size > budget) { return LayoutKind::REFERENCE; @@ -119,9 +119,9 @@ static LayoutKind adjust_with_budget(FieldInfo field_info, Array* ili) { - if (fieldinfo.field_flags().is_null_free_inline_type()) { - // A null-free inline type is always inlineable +static bool field_is_inlineable(FieldInfo fieldinfo, LayoutKind lk, Array* li) { + if (fieldinfo.field_flags().is_null_free_value_type()) { + // A null-free value type is always inlineable return true; } @@ -134,10 +134,10 @@ static bool field_is_inlineable(FieldInfo fieldinfo, LayoutKind lk, Arrayadr_at(field_index)->klass() != nullptr && - !ili->adr_at(field_index)->klass()->is_identity_class() && - !ili->adr_at(field_index)->klass()->is_abstract()) { + li != nullptr && + li->adr_at(field_index)->klass() != nullptr && + !li->adr_at(field_index)->klass()->is_identity_class() && + !li->adr_at(field_index)->klass()->is_abstract()) { // The field's klass is not an identity class or abstract return true; } @@ -148,7 +148,7 @@ static bool field_is_inlineable(FieldInfo fieldinfo, LayoutKind lk, Arrayappend(block); } -void FieldGroup::add_flat_field(int idx, InlineKlass* vk, LayoutKind lk) { +void FieldGroup::add_flat_field(int idx, ValueKlass* vk, LayoutKind lk) { const int size = vk->layout_size_in_bytes(lk); const int alignment = vk->layout_alignment(lk); LayoutRawBlock* block = new LayoutRawBlock(idx, LayoutRawBlock::FLAT, size, alignment); - block->set_inline_klass(vk); + block->set_value_klass(vk); block->set_layout_kind(lk); if (block->size() >= heapOopSize) { add_to_big_primitive_list(block); } else { - assert(!vk->contains_oops(), "Size of Inline klass with oops should be >= heapOopSize"); + assert(!vk->contains_oops(), "Size of Value klass with oops should be >= heapOopSize"); add_to_small_primitive_list(block); } } @@ -249,9 +249,9 @@ void FieldGroup::add_to_big_primitive_list(LayoutRawBlock* block) { _big_primitive_fields->append(block); } -FieldLayout::FieldLayout(GrowableArray* field_info, Array* inline_layout_info_array, ConstantPool* cp) : +FieldLayout::FieldLayout(GrowableArray* field_info, Array* value_field_layout_info_array, ConstantPool* cp) : _field_info(field_info), - _inline_layout_info_array(inline_layout_info_array), + _value_field_layout_info_array(value_field_layout_info_array), _cp(cp), _blocks(nullptr), _start(_blocks), @@ -459,9 +459,9 @@ LayoutRawBlock* FieldLayout::insert_field_block(LayoutRawBlock* slot, LayoutRawB } } if (LayoutKindHelper::is_nullable_flat(block->layout_kind())) { - int nm_offset = block->inline_klass()->null_marker_offset() - block->inline_klass()->payload_offset() + block->offset(); + int nm_offset = block->value_klass()->null_marker_offset() - block->value_klass()->payload_offset() + block->offset(); _field_info->adr_at(block->field_index())->set_null_marker_offset(nm_offset); - _inline_layout_info_array->adr_at(block->field_index())->set_null_marker_offset(nm_offset); + _value_field_layout_info_array->adr_at(block->field_index())->set_null_marker_offset(nm_offset); } return block; @@ -487,8 +487,8 @@ void FieldLayout::reconstruct_layout(const InstanceKlass* ik, bool& has_nonstati } LayoutRawBlock* block; if (fs.is_flat()) { - InlineLayoutInfo layout_info = ik->inline_layout_info(fs.index()); - InlineKlass* vk = layout_info.klass(); + ValueFieldLayoutInfo layout_info = ik->value_field_layout_info(fs.index()); + ValueKlass* vk = layout_info.klass(); block = new LayoutRawBlock(fs.index(), LayoutRawBlock::INHERITED, vk->layout_size_in_bytes(layout_info.kind()), vk->layout_alignment(layout_info.kind())); @@ -638,7 +638,7 @@ void FieldLayout::shift_fields(int shift) { if (LayoutKindHelper::is_nullable_flat(b->layout_kind())) { int new_nm_offset = _field_info->adr_at(b->field_index())->null_marker_offset() + shift; _field_info->adr_at(b->field_index())->set_null_marker_offset(new_nm_offset); - _inline_layout_info_array->adr_at(b->field_index())->set_null_marker_offset(new_nm_offset); + _value_field_layout_info_array->adr_at(b->field_index())->set_null_marker_offset(new_nm_offset); } } assert(b->block_kind() == LayoutRawBlock::EMPTY || b->offset() % b->alignment() == 0, "Must still be correctly aligned"); @@ -677,7 +677,7 @@ void FieldLayout::remove_null_marker() { ShouldNotReachHere(); // if we reach this point, the null marker was not found! } -void FieldLayout::print(outputStream* output, bool is_static, const InstanceKlass* super, Array* inline_fields, bool dummy_field_is_reused_as_null_marker) { +void FieldLayout::print(outputStream* output, bool is_static, const InstanceKlass* super, Array* value_fields, bool dummy_field_is_reused_as_null_marker) { ResourceMark rm; LayoutRawBlock* b = _blocks; while(b != _last) { @@ -704,8 +704,8 @@ void FieldLayout::print(outputStream* output, bool is_static, const InstanceKlas } case LayoutRawBlock::FLAT: { FieldInfo* fi = _field_info->adr_at(b->field_index()); - InlineKlass* ik = inline_fields->adr_at(fi->index())->klass(); - assert(ik != nullptr, ""); + ValueKlass* vk = value_fields->adr_at(fi->index())->klass(); + assert(vk != nullptr, ""); output->print_cr(" @%d %s %d/%d \"%s\" %s %s@%p %s", b->offset(), "FLAT", @@ -713,8 +713,8 @@ void FieldLayout::print(outputStream* output, bool is_static, const InstanceKlas b->alignment(), fi->name(_cp)->as_C_string(), fi->signature(_cp)->as_C_string(), - ik->name()->as_C_string(), - ik->class_loader_data(), + vk->name()->as_C_string(), + vk->class_loader_data(), LayoutKindHelper::layout_kind_as_string(b->layout_kind())); break; } @@ -776,15 +776,15 @@ void FieldLayout::print(outputStream* output, bool is_static, const InstanceKlas } FieldLayoutBuilder::FieldLayoutBuilder(const Symbol* classname, ClassLoaderData* loader_data, const InstanceKlass* super_klass, ConstantPool* constant_pool, - GrowableArray* field_info, bool is_contended, bool is_inline_type,bool is_abstract_value, - bool must_be_atomic, FieldLayoutInfo* info, Array* inline_layout_info_array) : + GrowableArray* field_info, bool is_contended, bool is_concrete_value, bool is_abstract_value, + bool must_be_atomic, FieldLayoutInfo* info, Array* value_field_layout_info_array) : _classname(classname), _loader_data(loader_data), _super_klass(super_klass), _constant_pool(constant_pool), _field_info(field_info), _info(info), - _inline_layout_info_array(inline_layout_info_array), + _value_field_layout_info_array(value_field_layout_info_array), _root_group(nullptr), _contended_groups(GrowableArray(8)), _static_fields(nullptr), @@ -811,9 +811,9 @@ FieldLayoutBuilder::FieldLayoutBuilder(const Symbol* classname, ClassLoaderData* _has_inlineable_fields(false), _has_inlined_fields(false), _is_contended(is_contended), - _is_inline_type(is_inline_type), + _is_concrete_value(is_concrete_value), _is_abstract_value(is_abstract_value), - _is_empty_inline_class(false) {} + _is_empty_value_class(false) {} FieldGroup* FieldLayoutBuilder::get_or_create_contended_group(int g) { assert(g > 0, "must only be called for named contended groups"); @@ -828,14 +828,14 @@ FieldGroup* FieldLayoutBuilder::get_or_create_contended_group(int g) { } void FieldLayoutBuilder::prologue() { - _layout = new FieldLayout(_field_info, _inline_layout_info_array, _constant_pool); + _layout = new FieldLayout(_field_info, _value_field_layout_info_array, _constant_pool); const InstanceKlass* super_klass = _super_klass; _layout->initialize_instance_layout(super_klass, _super_ends_with_oop); _nonstatic_oopmap_count = super_klass == nullptr ? 0 : super_klass->nonstatic_oop_map_count(); if (super_klass != nullptr) { _has_nonstatic_fields = super_klass->has_nonstatic_fields(); } - _static_layout = new FieldLayout(_field_info, _inline_layout_info_array, _constant_pool); + _static_layout = new FieldLayout(_field_info, _value_field_layout_info_array, _constant_pool); _static_layout->initialize_static_layout(); _static_fields = new FieldGroup(); _root_group = new FieldGroup(); @@ -857,13 +857,13 @@ int FieldLayoutBuilder::add_field_to_group(FieldInfo fieldinfo, int idx, FieldGr case T_OBJECT: case T_ARRAY: { - const bool is_inline_class = _is_inline_type || _is_abstract_value; + const bool is_value_compatible_class = _is_concrete_value || _is_abstract_value; // Atomic flat fields can always be used in identity classes. - // Use them only for inline classes if the container is itself atomic. - const bool use_atomic_flat = !is_inline_class || _must_be_atomic; - LayoutKind lk = field_layout_selection(fieldinfo, _inline_layout_info_array, use_atomic_flat); - lk = adjust_with_budget(fieldinfo, _inline_layout_info_array, lk, _flattening_budget); - if (field_is_inlineable(fieldinfo, lk, _inline_layout_info_array)) { + // Use them only for value classes if the container is itself atomic. + const bool use_atomic_flat = !is_value_compatible_class || _must_be_atomic; + LayoutKind lk = field_layout_selection(fieldinfo, _value_field_layout_info_array, use_atomic_flat); + lk = adjust_with_budget(fieldinfo, _value_field_layout_info_array, lk, _flattening_budget); + if (field_is_inlineable(fieldinfo, lk, _value_field_layout_info_array)) { _has_inlineable_fields = true; } @@ -880,15 +880,15 @@ int FieldLayoutBuilder::add_field_to_group(FieldInfo fieldinfo, int idx, FieldGr "Invalid layout kind for flat field: %s", LayoutKindHelper::layout_kind_as_string(lk)); const int field_index = (int)fieldinfo.index(); - assert(_inline_layout_info_array != nullptr, "Array must have been created"); - assert(_inline_layout_info_array->adr_at(field_index)->klass() != nullptr, "Klass must have been set"); + assert(_value_field_layout_info_array != nullptr, "Array must have been created"); + assert(_value_field_layout_info_array->adr_at(field_index)->klass() != nullptr, "Klass must have been set"); _has_inlined_fields = true; - InlineKlass* vk = _inline_layout_info_array->adr_at(field_index)->klass(); - if (is_inline_class && !vk->is_naturally_atomic(LayoutKindHelper::is_null_free_flat(lk))) { + ValueKlass* vk = _value_field_layout_info_array->adr_at(field_index)->klass(); + if (is_value_compatible_class && !vk->is_naturally_atomic(LayoutKindHelper::is_null_free_flat(lk))) { _has_non_naturally_atomic_fields = true; } group->add_flat_field(idx, vk, lk); - _inline_layout_info_array->adr_at(field_index)->set_kind(lk); + _value_field_layout_info_array->adr_at(field_index)->set_kind(lk); _nonstatic_oopmap_count += vk->nonstatic_oop_map_count(); _field_info->adr_at(idx)->field_flags_addr()->update_flat(true); _field_info->adr_at(idx)->set_layout_kind(lk); @@ -899,7 +899,7 @@ int FieldLayoutBuilder::add_field_to_group(FieldInfo fieldinfo, int idx, FieldGr } } -// Field sorting for regular (non-inline) classes: +// Field sorting for regular (non-value) classes: // - fields are sorted in static and non-static fields // - non-static fields are also sorted according to their contention group // (support of the @Contended annotation) @@ -938,19 +938,19 @@ void FieldLayoutBuilder::regular_field_sorting() { } } -// Field sorting for inline classes: -// - because inline classes are immutable, the @Contended annotation is ignored +// Field sorting for value classes: +// - because value classes are immutable, the @Contended annotation is ignored // when computing their layout (with only read operation, there's no false // sharing issue) // - this method also records the alignment of the field with the most // constraining alignment, this value is then used as the alignment -// constraint when flattening this inline type into another container +// constraint when flattening this value type into another container // - field flattening decisions are taken in this method (those decisions are // currently only based in the size of the fields to be flattened, the size // of the resulting instance is not considered) // -void FieldLayoutBuilder::inline_class_field_sorting() { - assert(_is_inline_type || _is_abstract_value, "Should only be used for inline classes"); +void FieldLayoutBuilder::value_class_field_sorting() { + assert(_is_concrete_value || _is_abstract_value, "Should only be used for value classes"); int alignment = -1; int idx = 0; for (GrowableArrayIterator it = _field_info->begin(); it != _field_info->end(); ++it, ++idx) { @@ -985,7 +985,7 @@ LayoutRawBlock* FieldLayoutBuilder::insert_contended_padding(LayoutRawBlock* slo // Computation of regular classes layout is an evolution of the previous default layout // (FieldAllocationStyle 1): -// - primitive fields (both primitive types and flat inline types) are allocated +// - primitive fields (both primitive types and flat value types) are allocated // first (from the biggest to the smallest) // - oop fields are allocated, either in existing gaps or at the end of // the layout. We allocate oops in a single block to have a single oop map entry. @@ -1051,21 +1051,21 @@ void FieldLayoutBuilder::compute_regular_layout() { epilogue(); } -// Computation of inline classes has a slightly different strategy than for +// Computation of value classes has a slightly different strategy than for // regular classes. Regular classes have their oop fields allocated at the end // of the layout to increase GC performance. Unfortunately, this strategy // increases the number of empty slots inside an instance. Because the purpose -// of inline classes is to be embedded into other containers, it is critical +// of value classes is to be embedded into other containers, it is critical // to keep their size as small as possible. For this reason, the allocation // strategy is: -// - big primitive fields (primitive types and flat inline types larger +// - big primitive fields (primitive types and flat value types larger // than an oop) are allocated first (from the biggest to the smallest) // - then oop fields // - then small primitive fields (from the biggest to the smallest) // -void FieldLayoutBuilder::compute_inline_class_layout() { +void FieldLayoutBuilder::compute_value_class_layout() { - // Test if the concrete inline class is an empty class (no instance fields) + // Test if the concrete value class is an empty class (no instance fields) // and insert a dummy field if needed if (!_is_abstract_value) { bool declares_nonstatic_fields = false; @@ -1080,7 +1080,7 @@ void FieldLayoutBuilder::compute_inline_class_layout() { bool has_inherited_fields = _super_klass != nullptr && _super_klass->has_nonstatic_fields(); if (!has_inherited_fields) { // Inject ".empty" dummy field - _is_empty_inline_class = true; + _is_empty_value_class = true; FieldInfo::FieldFlags fflags(0); fflags.update_injected(true); AccessFlags aflags; @@ -1096,7 +1096,7 @@ void FieldLayoutBuilder::compute_inline_class_layout() { } prologue(); - inline_class_field_sorting(); + value_class_field_sorting(); assert(_layout->start()->block_kind() == LayoutRawBlock::RESERVED, "Unexpected"); @@ -1160,7 +1160,7 @@ void FieldLayoutBuilder::compute_inline_class_layout() { _payload_offset = _layout->first_field_block()->offset(); _payload_size_in_bytes = _layout->last_block()->offset() - _layout->first_field_block()->offset(); } else { - assert(_is_abstract_value, "Concrete inline types must have at least one field"); + assert(_is_abstract_value, "Concrete value types must have at least one field"); _payload_offset = _layout->blocks()->size(); _payload_size_in_bytes = 0; } @@ -1207,7 +1207,7 @@ void FieldLayoutBuilder::compute_inline_class_layout() { LayoutRawBlock* b = _layout->first_field_block(); assert(b != nullptr, "A concrete value class must have at least one (possible dummy) field"); int null_marker_offset = -1; - if (_is_empty_inline_class) { + if (_is_empty_value_class) { // Reusing the dummy field as a field marker assert(_field_info->adr_at(b->field_index())->name(_constant_pool) == vmSymbols::empty_marker_name(), "b must be the dummy field"); null_marker_offset = b->offset(); @@ -1251,12 +1251,12 @@ void FieldLayoutBuilder::compute_inline_class_layout() { if (_null_marker_offset == -1) { // No nullable layout has been accepted // If the nullable layout is rejected, the NULL_MARKER block should be removed // from the layout, otherwise it will appear anyway if the layout is printer - if (!_is_empty_inline_class) { // empty values don't have a dedicated NULL_MARKER block + if (!_is_empty_value_class) { // empty values don't have a dedicated NULL_MARKER block _layout->remove_null_marker(); } } } - // If the inline class has an atomic or nullable atomic layout, + // If the value class has an atomic or nullable atomic layout, // we want the raw layout to have the same alignment as those atomic layouts so access codes // could remain simple (single instruction without intermediate copy). This might require // shifting all fields in the raw layout, but this operation is possible only if the class @@ -1278,13 +1278,13 @@ void FieldLayoutBuilder::compute_inline_class_layout() { _payload_offset = _layout->first_field_block()->offset(); assert(is_aligned(_payload_offset, required_alignment), "Fields should have been shifted to respect the required alignment"); if (has_nullable_atomic_layout() || has_nullable_non_atomic_layout()) { - assert(!_is_empty_inline_class, "Should not get here with empty values"); + assert(!_is_empty_value_class, "Should not get here with empty values"); _null_marker_offset = _layout->find_null_marker()->offset(); } _payload_alignment = required_alignment; } else { _null_free_atomic_layout_size_in_bytes = -1; - if (has_nullable_atomic_layout() && !has_nullable_non_atomic_layout() && !_is_empty_inline_class) { // empty values don't have a dedicated NULL_MARKER block + if (has_nullable_atomic_layout() && !has_nullable_non_atomic_layout() && !_is_empty_value_class) { // empty values don't have a dedicated NULL_MARKER block _layout->remove_null_marker(); _null_marker_offset = -1; } @@ -1294,7 +1294,7 @@ void FieldLayoutBuilder::compute_inline_class_layout() { _payload_alignment = required_alignment; } - // If the inline class has a nullable layout, the layout used in heap allocated standalone + // If the value class has a nullable layout, the layout used in heap allocated standalone // instances must also be the nullable layout, in order to be able to set the null marker to // non-null before copying the payload to other containers. if (has_nullable_atomic_layout() && payload_layout_size_in_bytes() < nullable_atomic_layout_size_in_bytes()) { @@ -1304,7 +1304,7 @@ void FieldLayoutBuilder::compute_inline_class_layout() { _payload_size_in_bytes = nullable_non_atomic_layout_size_in_bytes(); } - // If the inline class has a null-free atomic layout, then the layout used in heap allocated standalone + // If the value class has a null-free atomic layout, then the layout used in heap allocated standalone // instances must have at least equal to the atomic layout to allow safe read/write atomic // operation. if (has_null_free_atomic_layout() && payload_layout_size_in_bytes() < null_free_atomic_layout_size_in_bytes()) { @@ -1320,7 +1320,7 @@ void FieldLayoutBuilder::compute_inline_class_layout() { epilogue(); } -void FieldLayoutBuilder::add_flat_field_oopmap(OopMapBlocksBuilder* nonstatic_oop_maps, InlineKlass* vklass, int offset) { +void FieldLayoutBuilder::add_flat_field_oopmap(OopMapBlocksBuilder* nonstatic_oop_maps, ValueKlass* vklass, int offset) { int diff = offset - vklass->payload_offset(); const OopMapBlock* map = vklass->start_of_nonstatic_oop_maps(); const OopMapBlock* last_map = map + vklass->nonstatic_oop_map_count(); @@ -1338,7 +1338,7 @@ void FieldLayoutBuilder::register_embedded_oops_from_list(OopMapBlocksBuilder* n for (int i = 0; i < list->length(); i++) { LayoutRawBlock* f = list->at(i); if (f->block_kind() == LayoutRawBlock::FLAT) { - InlineKlass* vk = f->inline_klass(); + ValueKlass* vk = f->value_klass(); assert(vk != nullptr, "Should have been initialized"); if (vk->contains_oops()) { add_flat_field_oopmap(nonstatic_oop_maps, vk, f->offset()); @@ -1411,12 +1411,12 @@ static void split_after(GrowableArray* map, int idx, int head) { } void FieldLayoutBuilder::generate_acmp_maps() { - assert(_is_inline_type || _is_abstract_value, "Must be done only for value classes (abstract or not)"); + assert(_is_concrete_value || _is_abstract_value, "Must be done only for value classes (abstract or not)"); // create/initialize current class' maps _nonoop_acmp_map = new GrowableArray(); _oop_acmp_map = new GrowableArray(); - if (_is_empty_inline_class) return; + if (_is_empty_value_class) return; // last_idx remembers the position of the last insertion in order to speed up the next insertion. // Local fields are processed in ascending offset order, so an insertion is very likely be performed // next to the previous insertion. However, in some cases local fields and inherited fields can be @@ -1451,7 +1451,7 @@ void FieldLayoutBuilder::generate_acmp_maps() { } case LayoutRawBlock::FLAT: { - InlineKlass* vk = b->inline_klass(); + ValueKlass* vk = b->value_klass(); int field_offset = b->offset() - vk->payload_offset(); last_idx = insert_map_at_offset(_nonoop_acmp_map, _oop_acmp_map, vk, field_offset, last_idx); if (LayoutKindHelper::is_nullable_flat(b->layout_kind())) { @@ -1535,7 +1535,7 @@ void FieldLayoutBuilder::epilogue() { _info->_has_nonstatic_fields = _has_nonstatic_fields; _info->_has_inlined_fields = _has_inlined_fields; _info->_is_naturally_atomic = _is_naturally_atomic; - if (_is_inline_type) { + if (_is_concrete_value) { _info->_must_be_atomic = _must_be_atomic; _info->_payload_alignment = _payload_alignment; _info->_payload_offset = _payload_offset; @@ -1547,11 +1547,11 @@ void FieldLayoutBuilder::epilogue() { _info->_nullable_non_atomic_layout_size_in_bytes = _nullable_non_atomic_layout_size_in_bytes; _info->_null_marker_offset = _null_marker_offset; _info->_null_reset_value_offset = _static_layout->null_reset_value_offset(); - _info->_is_empty_inline_klass = _is_empty_inline_class; + _info->_is_empty_value_klass = _is_empty_value_class; } // Acmp maps are needed for both concrete and abstract value classes - if (_is_inline_type || _is_abstract_value) { + if (_is_concrete_value || _is_abstract_value) { _info->_acmp_maps_offset = _static_layout->acmp_maps_offset(); _info->_nonoop_acmp_map = _nonoop_acmp_map; _info->_oop_acmp_map = _oop_acmp_map; @@ -1589,7 +1589,7 @@ void FieldLayoutBuilder::epilogue() { static bool first_layout_print = true; - if (PrintFieldLayout || (PrintInlineLayout && (_has_inlineable_fields || _is_inline_type || _is_abstract_value))) { + if (PrintFieldLayout || (PrintValueLayout && (_has_inlineable_fields || _is_concrete_value || _is_abstract_value))) { ResourceMark rm; stringStream st; if (first_layout_print) { @@ -1604,12 +1604,12 @@ void FieldLayoutBuilder::epilogue() { st.print_cr("Layout of class %s@%p", _classname->as_C_string(), _loader_data); } st.print_cr("Instance fields:"); - const bool dummy_field_is_reused_as_null_marker = _is_empty_inline_class && _null_marker_offset != -1; - _layout->print(&st, false, _super_klass, _inline_layout_info_array, dummy_field_is_reused_as_null_marker); + const bool dummy_field_is_reused_as_null_marker = _is_empty_value_class && _null_marker_offset != -1; + _layout->print(&st, false, _super_klass, _value_field_layout_info_array, dummy_field_is_reused_as_null_marker); st.print_cr("Static fields:"); - _static_layout->print(&st, true, nullptr, _inline_layout_info_array, false); + _static_layout->print(&st, true, nullptr, _value_field_layout_info_array, false); st.print_cr("Instance size = %d bytes", _info->_instance_size * wordSize); - if (_is_inline_type) { + if (_is_concrete_value) { st.print_cr("First field offset = %d", _payload_offset); st.print_cr("%s layout: %d/%d", LayoutKindHelper::layout_kind_as_string(LayoutKind::BUFFERED), _payload_size_in_bytes, _payload_alignment); @@ -1666,8 +1666,8 @@ void FieldLayoutBuilder::epilogue() { } void FieldLayoutBuilder::build_layout() { - if (_is_inline_type || _is_abstract_value) { - compute_inline_class_layout(); + if (_is_concrete_value || _is_abstract_value) { + compute_value_class_layout(); } else { compute_regular_layout(); } diff --git a/src/hotspot/share/classfile/fieldLayoutBuilder.hpp b/src/hotspot/share/classfile/fieldLayoutBuilder.hpp index ad148e8441d3..985123fca746 100644 --- a/src/hotspot/share/classfile/fieldLayoutBuilder.hpp +++ b/src/hotspot/share/classfile/fieldLayoutBuilder.hpp @@ -29,8 +29,8 @@ #include "classfile/classLoaderData.hpp" #include "memory/allocation.hpp" #include "oops/fieldStreams.hpp" -#include "oops/inlineKlass.hpp" #include "oops/instanceKlass.hpp" +#include "oops/valueKlass.hpp" #include "utilities/growableArray.hpp" // Classes below are used to compute the field layout of classes. @@ -61,7 +61,7 @@ class LayoutRawBlock : public ResourceObj { EMPTY, // empty slot, space is taken from this to allocate fields RESERVED, // reserved for JVM usage (for instance object header) PADDING, // padding (because of alignment constraints or @Contended) - REGULAR, // primitive or oop field (including not flat inline type fields) + REGULAR, // primitive or oop field (including not flat value type fields) FLAT, // flat field INHERITED, // field(s) inherited from super classes NULL_MARKER // stores the null marker for a flat field @@ -70,7 +70,7 @@ class LayoutRawBlock : public ResourceObj { private: LayoutRawBlock* _next_block; LayoutRawBlock* _prev_block; - InlineKlass* _inline_klass; + ValueKlass* _value_klass; Kind _block_kind; LayoutKind _layout_kind; int _offset; @@ -104,11 +104,11 @@ class LayoutRawBlock : public ResourceObj { assert(_field_index == -1, "Must not be initialized"); _field_index = field_index; } - InlineKlass* inline_klass() const { - assert(_inline_klass != nullptr, "Must be initialized"); - return _inline_klass; + ValueKlass* value_klass() const { + assert(_value_klass != nullptr, "Must be initialized"); + return _value_klass; } - void set_inline_klass(InlineKlass* inline_klass) { _inline_klass = inline_klass; } + void set_value_klass(ValueKlass* value_klass) { _value_klass = value_klass; } LayoutKind layout_kind() const { return _layout_kind; } void set_layout_kind(LayoutKind kind) { _layout_kind = kind; } @@ -158,7 +158,7 @@ class FieldGroup : public ResourceObj { void add_primitive_field(int idx, BasicType type); void add_oop_field(int idx); - void add_flat_field(int idx, InlineKlass* vk, LayoutKind lk); + void add_flat_field(int idx, ValueKlass* vk, LayoutKind lk); void add_block(LayoutRawBlock** list, LayoutRawBlock* block); void sort_by_size(); private: @@ -185,7 +185,7 @@ class FieldGroup : public ResourceObj { class FieldLayout : public ResourceObj { private: GrowableArray* _field_info; - Array* _inline_layout_info_array; + Array* _value_field_layout_info_array; ConstantPool* _cp; LayoutRawBlock* _blocks; // the layout being computed LayoutRawBlock* _start; // points to the first block where a field can be inserted @@ -193,13 +193,13 @@ class FieldLayout : public ResourceObj { int _super_first_field_offset; int _super_alignment; int _super_min_align_required; - int _null_reset_value_offset; // offset of the reset value in class mirror, only for static layout of inline classes + int _null_reset_value_offset; // offset of the reset value in class mirror, only for static layout of value classes int _acmp_maps_offset; bool _super_has_nonstatic_fields; bool _has_inherited_fields; public: - FieldLayout(GrowableArray* field_info, Array* inline_layout_info_array, ConstantPool* cp); + FieldLayout(GrowableArray* field_info, Array* value_field_layout_info_array, ConstantPool* cp); void initialize_static_layout(); void initialize_instance_layout(const InstanceKlass* ik, bool& super_ends_with_oop); @@ -242,13 +242,13 @@ class FieldLayout : public ResourceObj { void shift_fields(int shift); LayoutRawBlock* find_null_marker(); void remove_null_marker(); - void print(outputStream* output, bool is_static, const InstanceKlass* super, Array* inline_fields, bool dummy_field_is_reused_as_null_marker); + void print(outputStream* output, bool is_static, const InstanceKlass* super, Array* value_fields, bool dummy_field_is_reused_as_null_marker); }; // FieldLayoutBuilder is the main entry point for layout computation. // This class has two methods to generate layout: one for identity classes -// and one for inline classes. The rationale for having two methods +// and one for value classes. The rationale for having two methods // is that each kind of class has a different set of goals regarding // its layout, so instead of mixing two layout strategies into a // single method, each kind has its own method (see comments below @@ -258,7 +258,7 @@ class FieldLayout : public ResourceObj { // 1 - Prologue: preparation of data structure and gathering of // layout information inherited from super classes // 2 - Field sorting: fields are sorted according to their -// kind (oop, primitive, inline class) and their contention +// kind (oop, primitive, value class) and their contention // annotation (if any) // 3 - Layout is computed from the set of lists generated during // step 2 @@ -267,7 +267,7 @@ class FieldLayout : public ResourceObj { // static field size, non-static field size, etc.) // // Steps 1 and 4 are common to all layout computations. Step 2 and 3 -// differ for inline classes and identity classes. +// differ for value classes and identity classes. // class FieldLayoutBuilder : public ResourceObj { @@ -278,7 +278,7 @@ class FieldLayoutBuilder : public ResourceObj { ConstantPool* _constant_pool; GrowableArray* _field_info; FieldLayoutInfo* _info; - Array* _inline_layout_info_array; + Array* _value_field_layout_info_array; FieldGroup* _root_group; GrowableArray _contended_groups; FieldGroup* _static_fields; @@ -307,16 +307,16 @@ class FieldLayoutBuilder : public ResourceObj { bool _has_inlined_fields; bool _is_contended; bool _super_ends_with_oop; - bool _is_inline_type; + bool _is_concrete_value; bool _is_abstract_value; - bool _is_empty_inline_class; + bool _is_empty_value_class; FieldGroup* get_or_create_contended_group(int g); public: FieldLayoutBuilder(const Symbol* classname, ClassLoaderData* loader_data, const InstanceKlass* super_klass, ConstantPool* constant_pool, - GrowableArray* field_info, bool is_contended, bool is_inline_type, bool is_abstract_value, - bool must_be_atomic, FieldLayoutInfo* info, Array* inline_layout_info_array); + GrowableArray* field_info, bool is_contended, bool is_concrete_value, bool is_abstract_value, + bool must_be_atomic, FieldLayoutInfo* info, Array* value_field_layout_info_array); int payload_offset() const { assert(_payload_offset != -1, "Uninitialized"); return _payload_offset; } int payload_layout_size_in_bytes() const { return _payload_size_in_bytes; } @@ -331,11 +331,11 @@ class FieldLayoutBuilder : public ResourceObj { bool has_nullable_non_atomic_layout() const { return _nullable_non_atomic_layout_size_in_bytes != -1; } int nullable_non_atomic_layout_size_in_bytes() const { return _nullable_non_atomic_layout_size_in_bytes; } int null_marker_offset() const { return _null_marker_offset; } - bool is_empty_inline_class() const { return _is_empty_inline_class; } + bool is_empty_value_class() const { return _is_empty_value_class; } void build_layout(); void compute_regular_layout(); - void compute_inline_class_layout(); + void compute_value_class_layout(); LayoutRawBlock* insert_contended_padding(LayoutRawBlock* slot); protected: @@ -343,8 +343,8 @@ class FieldLayoutBuilder : public ResourceObj { void epilogue(); int add_field_to_group(FieldInfo fieldinfo, int idx, FieldGroup* group); void regular_field_sorting(); - void inline_class_field_sorting(); - void add_flat_field_oopmap(OopMapBlocksBuilder* nonstatic_oop_map, InlineKlass* vk, int offset); + void value_class_field_sorting(); + void add_flat_field_oopmap(OopMapBlocksBuilder* nonstatic_oop_map, ValueKlass* vk, int offset); void register_embedded_oops_from_list(OopMapBlocksBuilder* nonstatic_oop_maps, GrowableArray* list); void register_embedded_oops(OopMapBlocksBuilder* nonstatic_oop_maps, FieldGroup* group); void generate_acmp_maps(); diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 0c5b84e8bff4..1a4200529d5a 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -47,7 +47,6 @@ #include "oops/fieldInfo.hpp" #include "oops/fieldStreams.inline.hpp" #include "oops/flatArrayKlass.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/instanceMirrorKlass.inline.hpp" #include "oops/klass.inline.hpp" @@ -60,6 +59,7 @@ #include "oops/refArrayOop.inline.hpp" #include "oops/symbol.hpp" #include "oops/typeArrayOop.inline.hpp" +#include "oops/valueKlass.inline.hpp" #include "prims/jvmtiExport.hpp" #include "prims/resolvedMethodTable.hpp" #include "runtime/continuationJavaClasses.inline.hpp" diff --git a/src/hotspot/share/classfile/placeholders.cpp b/src/hotspot/share/classfile/placeholders.cpp index fab090fd448c..6cfa2542d1d6 100644 --- a/src/hotspot/share/classfile/placeholders.cpp +++ b/src/hotspot/share/classfile/placeholders.cpp @@ -61,7 +61,7 @@ static InternalPlaceholderTable* _placeholders; // For DEFINE_CLASS, the head of the queue owns the // define token and the rest of the threads wait to return the // result the first thread gets. -// For DETECT_CIRCULARITY, set when loading super class, interfaces, or inline type +// For DETECT_CIRCULARITY, set when loading super class, interfaces, or value type // fields for class circularity checking. class SeenThread: public CHeapObj { private: diff --git a/src/hotspot/share/classfile/stackMapFrame.cpp b/src/hotspot/share/classfile/stackMapFrame.cpp index 0cf0f889e01f..f36ab17872f0 100644 --- a/src/hotspot/share/classfile/stackMapFrame.cpp +++ b/src/hotspot/share/classfile/stackMapFrame.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, 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,36 +54,29 @@ void StackMapFrame::unsatisfied_strict_fields_error(InstanceKlass* klass, int bc // obvious fallback value. Symbol* name = vmSymbols::unknown_class_name(); Symbol* sig = vmSymbols::unknown_class_name(); - int num_uninit_fields = 0; - - auto find_unset = [&] (const NameAndSig& key, const bool& value) { - if (!value) { - name = key._name; - sig = key._signature; - num_uninit_fields++; - } - }; - assert_unset_fields()->iterate_all(find_unset); + int num_uninit_fields = assert_unset_fields()->number_of_entries(); verifier()->verify_error( ErrorContext::bad_strict_fields(bci, this), - "All strict final fields must be initialized before super(): %d field(s), %s:%s in %s", + "All strict fields must be initialized before super(): %d field(s) in %s", num_uninit_fields, - name->as_C_string(), - sig->as_C_string(), klass->name()->as_C_string() ); + print_strict_fields(assert_unset_fields()); } void StackMapFrame::print_strict_fields(AssertUnsetFieldTable* table) { ResourceMark rm; - auto printfields = [&] (const NameAndSig& key, const bool& value) { - log_info(verification)("Strict field: %s%s (Satisfied: %s)", - key._name->as_C_string(), - key._signature->as_C_string(), - value ? "true" : "false"); - }; - table->iterate_all(printfields); + if (table != nullptr) { + auto printfields = [&] (const NameAndSig& key, const bool& value) { + log_info(verification)("Strict field: %s%s", + key._name->as_C_string(), + key._signature->as_C_string()); + }; + table->iterate_all(printfields); + } else { + log_info(verification)("No strict fields"); + } } StackMapFrame* StackMapFrame::frame_in_exception_handler(u1 flags) { @@ -229,6 +222,12 @@ bool StackMapFrame::is_assignable_to( return false; } + if ((_flags | target->flags()) != target->flags()) { + *ctx = ErrorContext::bad_flags(target->offset(), + (StackMapFrame*)this, (StackMapFrame*)target); + return false; + } + // Check that assert unset fields are compatible bool compatible = verify_unset_fields_compatibility(target->assert_unset_fields()); if (!compatible) { @@ -239,13 +238,7 @@ bool StackMapFrame::is_assignable_to( return false; } - if ((_flags | target->flags()) == target->flags()) { - return true; - } else { - *ctx = ErrorContext::bad_flags(target->offset(), - (StackMapFrame*)this, (StackMapFrame*)target); - return false; - } + return true; } VerificationType StackMapFrame::pop_stack_ex(VerificationType type, TRAPS) { diff --git a/src/hotspot/share/classfile/stackMapFrame.hpp b/src/hotspot/share/classfile/stackMapFrame.hpp index 227f3b618e0e..21db0634026a 100644 --- a/src/hotspot/share/classfile/stackMapFrame.hpp +++ b/src/hotspot/share/classfile/stackMapFrame.hpp @@ -41,21 +41,6 @@ enum { }; class StackMapFrame : public ResourceObj { - public: - static unsigned int nameandsig_hash(NameAndSig const& field) { - Symbol* name = field._name; - return (unsigned int) name->identity_hash(); - } - - static inline bool nameandsig_equals(NameAndSig const& f1, NameAndSig const& f2) { - return f1._name == f2._name && - f1._signature == f2._signature; - } - - // Maps a strict field's name and signature to whether or not it was initialized - typedef HashTable AssertUnsetFieldTable; private: int32_t _offset; @@ -133,7 +118,12 @@ class StackMapFrame : public ResourceObj { _max_stack(max_stack), _flags(flags), _locals(locals), _stack(stack), _assert_unset_fields(assert_unset_fields), - _verifier(v) { } + _verifier(v) { + // Must have the uninitialized_this flag set to be allowed to have unset fields. + if ((flags & FLAG_THIS_UNINIT) != FLAG_THIS_UNINIT) { + _assert_unset_fields = nullptr; + } + } static StackMapFrame* copy(StackMapFrame* smf) { return new StackMapFrame(*smf); @@ -163,6 +153,10 @@ class StackMapFrame : public ResourceObj { } static AssertUnsetFieldTable* copy_unset_fields(AssertUnsetFieldTable* unset_fields) { + if (unset_fields == nullptr) { + return nullptr; + } + AssertUnsetFieldTable* new_table = new AssertUnsetFieldTable(); auto copy_unset_field = [&] (const NameAndSig& key, const bool& value) { new_table->put(key, value); @@ -176,51 +170,63 @@ class StackMapFrame : public ResourceObj { } // Called when verifying putfields to mark strict instance fields as satisfied - bool satisfy_unset_field(Symbol* name, Symbol* signature) { - NameAndSig dummy_field(name, signature); - - if (_assert_unset_fields->contains(dummy_field)) { - _assert_unset_fields->put(dummy_field, true); - return true; + void satisfy_unset_field(Symbol* name, Symbol* signature) { + // The verifier creates the initial set of strict instance fields and + // validates the set of strict fields named in early_larval frames + // so there is no way to have a non-strict field in the set. We + // can unconditionally remove fields here, regardless of whether + // they are strict or not, or have been removed already, as the + // easiest and safest implementation. + if (_assert_unset_fields != nullptr) { + NameAndSig field(name, signature); + _assert_unset_fields->remove(field); } - return false; } // Verify that all strict fields have been initialized // Strict fields must be initialized before the super constructor is called - bool verify_unset_fields_satisfied() { - bool all_satisfied = true; - auto check_satisfied = [&] (const NameAndSig& key, const bool& value) { - all_satisfied &= value; - }; - _assert_unset_fields->iterate_all(check_satisfied); - return all_satisfied; - } - - // Merge incoming unset strict fields from StackMapTable with - // initial strict instance fields - AssertUnsetFieldTable* merge_unset_fields(AssertUnsetFieldTable* new_fields) { - auto merge_satisfied = [&] (const NameAndSig& key, const bool& value) { - if (!new_fields->contains(key)) { - new_fields->put(key, true); - } - }; - _assert_unset_fields->iterate_all(merge_satisfied); - return new_fields; + bool verify_unset_fields_satisfied() const { + // A frame without uninitializedThis or otherwise without any strict fields + // will have a null unset field table. + if (_assert_unset_fields == nullptr || _assert_unset_fields->number_of_entries() == 0) { + return true; + } + return false; } // Verify that strict fields are compatible between the current frame and the successor // Called during merging of frames bool verify_unset_fields_compatibility(AssertUnsetFieldTable* target_table) const { + // There are four permutations of the source and target unset fields: + // 1. Source and target unset fields are null + // Both frames have a null set of fields. null == null so this is a trivial merge + // 2. Source unset fields are null, target unset fields are non-null + // This is not possible as we are trying to go from either an initialized state + // back to an uninitialized state. + // 3. Source unset fields are non-null, target unset fields are null + // Error case, We are jumping from an uninitialized state to an initialized one + // or from a frame with unset strict field information to one that doesn't. + // 4. Source and target unset fields are non-null + // We are merging from one frame with unset strict fields information to another + // and must ensure the unset fields lists are compatible. + + // It is valid to inherit more debts, so if the current frame's unset fields + // list is null, any set of unset fields is compatible. + if (_assert_unset_fields == nullptr) { + return true; + } + + // The target frame is does not have uninitializedThis, meaning the unset fields must + // all be satisfied at this point. + if (target_table == nullptr) { + return verify_unset_fields_satisfied(); + } + bool compatible = true; auto is_unset = [&] (const NameAndSig& key, const bool& satisfied) { // Successor must have same (or more) unsatisfied debts as current frame. - if (!satisfied) { - bool* target_satisfied = target_table->get(key); - guarantee(target_satisfied != nullptr, "Must be present"); - if (*target_satisfied == true) { - compatible = false; - } + if (!target_table->contains(key)) { + compatible = false; } }; _assert_unset_fields->iterate_all(is_unset); diff --git a/src/hotspot/share/classfile/stackMapTable.cpp b/src/hotspot/share/classfile/stackMapTable.cpp index 8954de5610b0..1a8b24610140 100644 --- a/src/hotspot/share/classfile/stackMapTable.cpp +++ b/src/hotspot/share/classfile/stackMapTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, 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 @@ -167,7 +167,7 @@ StackMapReader::StackMapReader(ClassVerifier* v, StackMapStream* stream, char* code_data, int32_t code_len, StackMapFrame* init_frame, u2 max_locals, u2 max_stack, - StackMapFrame::AssertUnsetFieldTable* initial_strict_fields, TRAPS) : + AssertUnsetFieldTable* initial_strict_fields, TRAPS) : _verifier(v), _stream(stream), _code_data(code_data), _code_length(code_len), _parsed_frame_count(0), _prev_frame(init_frame), _max_locals(max_locals), @@ -190,6 +190,9 @@ StackMapReader::StackMapReader(ClassVerifier* v, StackMapStream* stream, break; } } + + // Hold onto a copy of initial unset fields for verification + _initial_unset_fields = StackMapFrame::copy_unset_fields(_assert_unset_fields_buffer); } int32_t StackMapReader::chop( @@ -253,23 +256,27 @@ VerificationType StackMapReader::parse_verification_type(u1* flags, bool parsing StackMapFrame* StackMapReader::next(TRAPS) { _parsed_frame_count++; + bool parsed_early_larval = false; check_size(CHECK_NULL); - StackMapFrame* frame = next_helper(CHECK_VERIFY_(_verifier, nullptr)); + StackMapFrame* frame = next_helper(parsed_early_larval, CHECK_VERIFY_(_verifier, nullptr)); if (frame != nullptr) { check_offset(frame); + if (frame->verifier()->has_error()) { return nullptr; } _prev_frame = frame; + _assert_unset_fields_buffer = frame->assert_unset_fields(); } return frame; } -StackMapFrame* StackMapReader::next_helper(TRAPS) { +StackMapFrame* StackMapReader::next_helper(bool& parsed_early_larval, TRAPS) { StackMapFrame* frame; int offset; VerificationType* locals = nullptr; u1 frame_type = _stream->get_u1(CHECK_NULL); + if (frame_type == EARLY_LARVAL) { // early_larval frames are only supported in classes that support strict fields (preview classes) if (!Verifier::supports_strict_fields(_verifier->current_class())) { @@ -278,44 +285,46 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) { "reserved frame type", CHECK_VERIFY_(_verifier, nullptr)); } - u2 num_unset_fields = _stream->get_u2(CHECK_NULL); - StackMapFrame::AssertUnsetFieldTable* new_fields = new StackMapFrame::AssertUnsetFieldTable(); + if (parsed_early_larval) { + _prev_frame->verifier()->verify_error( + ErrorContext::bad_strict_fields(_prev_frame->offset(), _prev_frame), + "Early larval frame must be followed by a base frame"); + return nullptr; + } - for (u2 i = 0; i < num_unset_fields; i++) { - u2 index = _stream->get_u2(CHECK_NULL); + u2 num_unset_fields = _stream->get_u2(CHECK_NULL); + AssertUnsetFieldTable* new_fields = nullptr; - if (!_cp->is_within_bounds(index) || !_cp->tag_at(index).is_name_and_type()) { - _prev_frame->verifier()->verify_error( - ErrorContext::bad_strict_fields(_prev_frame->offset(), _prev_frame), - "Invalid constant pool index in early larval frame: %d", index); - return nullptr; - } + if (num_unset_fields > 0) { + new_fields = new AssertUnsetFieldTable(); - Symbol* name = _cp->symbol_at(_cp->name_ref_index_at(index)); - Symbol* sig = _cp->symbol_at(_cp->signature_ref_index_at(index)); - NameAndSig tmp(name, sig); + for (u2 i = 0; i < num_unset_fields; i++) { + u2 index = _stream->get_u2(CHECK_NULL); - if (!_prev_frame->assert_unset_fields()->contains(tmp)) { - log_info(verification)("NameAndType %s%s(CP index: %d) is not found among initial strict instance fields", name->as_C_string(), sig->as_C_string(), index); - StackMapFrame::print_strict_fields(_prev_frame->assert_unset_fields()); - _prev_frame->verifier()->verify_error( + if (!_cp->is_within_bounds(index) || !_cp->tag_at(index).is_name_and_type()) { + _prev_frame->verifier()->verify_error( ErrorContext::bad_strict_fields(_prev_frame->offset(), _prev_frame), - "Strict fields not a subset of initial strict instance fields: %s:%s", name->as_C_string(), sig->as_C_string()); - return nullptr; - } else { - new_fields->put(tmp, false); - } - } + "Invalid constant pool index in early larval frame: %d", index); + return nullptr; + } - // Only modify strict instance fields if the frame has uninitialized this - if (_prev_frame->flag_this_uninit()) { - _assert_unset_fields_buffer = _prev_frame->merge_unset_fields(new_fields); - } else if (new_fields->number_of_entries() > 0) { - _prev_frame->verifier()->verify_error( - ErrorContext::bad_strict_fields(_prev_frame->offset(), _prev_frame), - "Cannot have uninitialized strict fields after class initialization"); - return nullptr; + Symbol* name = _cp->symbol_at(_cp->name_ref_index_at(index)); + Symbol* sig = _cp->symbol_at(_cp->signature_ref_index_at(index)); + NameAndSig tmp(name, sig); + + if (_initial_unset_fields == nullptr || !_initial_unset_fields->contains(tmp)) { + log_info(verification)("NameAndType %s%s(CP index: %d) is not found among initial strict instance fields", name->as_C_string(), sig->as_C_string(), index); + StackMapFrame::print_strict_fields(_initial_unset_fields); + _prev_frame->verifier()->verify_error( + ErrorContext::bad_strict_fields(_prev_frame->offset(), _prev_frame), + "Strict fields not a subset of initial strict instance fields: %s:%s", name->as_C_string(), sig->as_C_string()); + return nullptr; + } else { + new_fields->put(tmp, false); + } + } } + _assert_unset_fields_buffer = new_fields; // Continue reading frame data if (at_end()) { @@ -325,13 +334,21 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) { return nullptr; } - frame_type = _stream->get_u1(CHECK_NULL); - if (frame_type == EARLY_LARVAL) { - _prev_frame->verifier()->verify_error( - ErrorContext::bad_strict_fields(_prev_frame->offset(), _prev_frame), - "Early larval frame must be followed by a base frame"); - return nullptr; + // Only count as parsed if no errors were encountered + parsed_early_larval = true; + // Early_larval must wrap another frame - read that frame now + frame = next_helper(parsed_early_larval, CHECK_VERIFY_(_verifier, nullptr)); + if (frame != nullptr) { + if (!frame->flag_this_uninit()) { + // The early_larval frame has been parsed correctly but such frames require uninitializedThis + // which will only be detected once the nested frame has been processed. + frame->verifier()->verify_error( + ErrorContext::bad_strict_fields(frame->offset(), frame), + "Cannot have uninitialized strict fields without an uninitializedThis"); + return nullptr; + } } + return frame; } if (frame_type <= SAME_FRAME_END) { @@ -384,6 +401,7 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) { } check_verification_type_array_size( stack_size, _max_stack, CHECK_VERIFY_(_verifier, nullptr)); + frame = new StackMapFrame( offset, flags, _prev_frame->locals_size(), stack_size, _max_locals, _max_stack, locals, stack, @@ -427,6 +445,7 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) { } check_verification_type_array_size( stack_size, _max_stack, CHECK_VERIFY_(_verifier, nullptr)); + frame = new StackMapFrame( offset, flags, _prev_frame->locals_size(), stack_size, _max_locals, _max_stack, locals, stack, @@ -473,6 +492,7 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) { } else { offset = _prev_frame->offset() + offset_delta + 1; } + frame = new StackMapFrame( offset, flags, new_length, 0, _max_locals, _max_stack, locals, nullptr, @@ -509,6 +529,7 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) { } else { offset = _prev_frame->offset() + offset_delta + 1; } + frame = new StackMapFrame( offset, flags, real_length, 0, _max_locals, _max_stack, locals, nullptr, @@ -559,6 +580,7 @@ StackMapFrame* StackMapReader::next_helper(TRAPS) { } else { offset = _prev_frame->offset() + offset_delta + 1; } + frame = new StackMapFrame( offset, flags, real_locals_size, real_stack_size, _max_locals, _max_stack, locals, stack, diff --git a/src/hotspot/share/classfile/stackMapTable.hpp b/src/hotspot/share/classfile/stackMapTable.hpp index 1aa5ec993470..45a5b74b5750 100644 --- a/src/hotspot/share/classfile/stackMapTable.hpp +++ b/src/hotspot/share/classfile/stackMapTable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -129,7 +129,10 @@ class StackMapReader : StackObj { u2 _max_stack; // Contains assert_unset_fields generated from classfile - StackMapFrame::AssertUnsetFieldTable* _assert_unset_fields_buffer; + AssertUnsetFieldTable* _assert_unset_fields_buffer; + + // Cached set of initial unset fields + AssertUnsetFieldTable* _initial_unset_fields; // Check if reading first entry bool _first; @@ -140,7 +143,7 @@ class StackMapReader : StackObj { // Full frames need to handle this specially. bool _uninit_in_prev_frame_locals; - StackMapFrame* next_helper(TRAPS); + StackMapFrame* next_helper(bool& parsed_early_larval, TRAPS); void check_offset(StackMapFrame* frame); void check_size(TRAPS); int32_t chop(VerificationType* locals, int32_t length, int32_t chops); @@ -180,7 +183,7 @@ class StackMapReader : StackObj { char* code_data, int32_t code_len, StackMapFrame* init_frame, u2 max_locals, u2 max_stack, - StackMapFrame::AssertUnsetFieldTable* initial_strict_fields, TRAPS); + AssertUnsetFieldTable* initial_strict_fields, TRAPS); inline int32_t get_frame_count() const { return _frame_count; } inline StackMapFrame* prev_frame() const { return _prev_frame; } diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index dbbc4196c7f7..f27473eeddc4 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -56,7 +56,6 @@ #include "oops/access.inline.hpp" #include "oops/constantPool.inline.hpp" #include "oops/fieldStreams.inline.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/instanceKlass.hpp" #include "oops/klass.inline.hpp" #include "oops/method.inline.hpp" @@ -66,6 +65,7 @@ #include "oops/oopHandle.inline.hpp" #include "oops/symbol.hpp" #include "oops/typeArrayKlass.hpp" +#include "oops/valueKlass.inline.hpp" #include "prims/jvmtiExport.hpp" #include "prims/methodHandles.hpp" #include "runtime/arguments.hpp" @@ -434,7 +434,7 @@ static inline void log_circularity_error(Symbol* name, PlaceholderEntry* probe) } // Must be called for any superclass or superinterface resolution -// during class definition, or may be called for inline field layout processing +// during class definition, or may be called for value field layout processing // to detect class circularity errors. // superinterface callers: // parse_interfaces - from defineClass @@ -448,7 +448,7 @@ static inline void log_circularity_error(Symbol* name, PlaceholderEntry* probe) // If another thread is trying to resolve the class, it must do // superclass checks on its own thread to catch class circularity and // to avoid deadlock. -// inline field layout callers: +// value field layout callers: // The field's class must be loaded to determine layout. // // resolve_with_circularity_detection adds a DETECT_CIRCULARITY placeholder to the placeholder table before calling @@ -1109,9 +1109,9 @@ bool SystemDictionary::check_shared_class_super_types(InstanceKlass* ik, Handle return true; } -// Pre-load class referred to in fields with archived inline field metadata. These fields +// Pre-load class referred to in fields with archived value field metadata. These fields // must be checked against the resolved runtime class before the shared class can be used. -bool SystemDictionary::preload_from_required_inline_field(InstanceKlass* ik, Handle class_loader, Symbol* sig, int field_index, TRAPS) { +bool SystemDictionary::preload_from_required_value_field(InstanceKlass* ik, Handle class_loader, Symbol* sig, int field_index, TRAPS) { if (log_is_enabled(Info, class, preload)) { TempNewSymbol name = Signature::strip_envelope(sig); log_info(class, preload)("Preloading of class %s during loading of shared class %s. " @@ -1119,7 +1119,7 @@ bool SystemDictionary::preload_from_required_inline_field(InstanceKlass* ik, Han name->as_C_string(), ik->name()->as_C_string()); } - InstanceKlass* k = ik->get_inline_type_field_klass_or_null(field_index); + InstanceKlass* k = ik->get_value_type_field_klass_or_null(field_index); bool check = check_shared_class_dependency(ik, k, class_loader, false, THREAD); if (!check) { const bool has_pending_exception = HAS_PENDING_EXCEPTION; @@ -1161,7 +1161,7 @@ void SystemDictionary::try_preload_from_loadable_descriptors(InstanceKlass* ik, log_info(class, preload)("Preloading of class %s during loading of shared class %s. " "Cause: field type in LoadableDescriptors attribute", name->as_C_string(), ik->name()->as_C_string()); - InstanceKlass* k = ik->get_inline_type_field_klass_or_null(field_index); + InstanceKlass* k = ik->get_value_type_field_klass_or_null(field_index); if (k == nullptr) { SystemDictionary::resolve_with_circularity_detection(ik->name(), name, class_loader, false, THREAD); if (HAS_PENDING_EXCEPTION) { @@ -1212,7 +1212,7 @@ InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik, if (ik->has_inlined_fields() || ik->has_null_restricted_static_fields()) { for (AllFieldStream fs(ik); !fs.done(); fs.next()) { - if (fs.access_flags().is_static() && !fs.is_null_free_inline_type()) { + if (fs.access_flags().is_static() && !fs.is_null_free_value_type()) { continue; } @@ -1223,8 +1223,8 @@ InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik, continue; } - if (fs.is_flat() || fs.is_null_free_inline_type()) { - bool check = preload_from_required_inline_field(ik, class_loader, sig, field_index, CHECK_NULL); + if (fs.is_flat() || fs.is_null_free_value_type()) { + bool check = preload_from_required_value_field(ik, class_loader, sig, field_index, CHECK_NULL); if (!check) { ik->set_shared_loading_failed(); return nullptr; diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp index 7a5bb1ec64ab..0ac9c98af539 100644 --- a/src/hotspot/share/classfile/systemDictionary.hpp +++ b/src/hotspot/share/classfile/systemDictionary.hpp @@ -331,7 +331,7 @@ class SystemDictionary : AllStatic { static bool add_loader_constraint(Symbol* name, Klass* klass_being_linked, Handle loader1, Handle loader2); - static bool preload_from_required_inline_field(InstanceKlass* ik, Handle class_loader, Symbol* sig, int field_index, TRAPS); + static bool preload_from_required_value_field(InstanceKlass* ik, Handle class_loader, Symbol* sig, int field_index, TRAPS); static void try_preload_from_loadable_descriptors(InstanceKlass* ik, Handle class_loader, Symbol* sig, int field_index, TRAPS); static InstanceKlass* load_shared_class(InstanceKlass* ik, Handle class_loader, diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 230f50d50037..a3258f433dda 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -305,8 +305,8 @@ class SystemDictionaryShared::ExclusionCheckCandidates // the field holder. if (k->has_inlined_fields() || k->has_null_restricted_static_fields()) { for (AllFieldStream fs(k); !fs.done(); fs.next()) { - if (fs.is_flat() || fs.is_null_free_inline_type()) { - InlineKlass* field_klass = k->get_inline_type_field_klass(fs.index()); + if (fs.is_flat() || fs.is_null_free_value_type()) { + ValueKlass* field_klass = k->get_value_type_field_klass(fs.index()); add_candidate(InstanceKlass::cast(field_klass)); } } @@ -538,9 +538,9 @@ bool SystemDictionaryShared::check_dependencies_exclusion(InstanceKlass* k, Dump // field layouts will be consistent at runtime. if (k->has_inlined_fields() || k->has_null_restricted_static_fields()) { for (AllFieldStream fs(k); !fs.done(); fs.next()) { - if (fs.is_flat() || fs.is_null_free_inline_type()) { - InlineKlass* field_klass = k->get_inline_type_field_klass(fs.index()); - if (is_dependency_excluded(k, InstanceKlass::cast(field_klass), "inline field type")) { + if (fs.is_flat() || fs.is_null_free_value_type()) { + ValueKlass* field_klass = k->get_value_type_field_klass(fs.index()); + if (is_dependency_excluded(k, InstanceKlass::cast(field_klass), "value field type")) { return true; } } diff --git a/src/hotspot/share/classfile/verificationType.hpp b/src/hotspot/share/classfile/verificationType.hpp index 3d2146f1a96b..7aeec3efdc3a 100644 --- a/src/hotspot/share/classfile/verificationType.hpp +++ b/src/hotspot/share/classfile/verificationType.hpp @@ -68,7 +68,7 @@ class VerificationType { // Enum for the _data field enum : uint { - // Bottom three bits determine if the type is a reference, inline type, + // Bottom three bits determine if the type is a reference, value type, // primitive, uninitialized or a query-type. TypeMask = 0x00000007, @@ -185,7 +185,7 @@ class VerificationType { bool is_reference() const { return ((_u._data & TypeMask) == Reference); } bool is_category1() const { // This should return true for all one-word types, which are category1 - // primitives, references (including uninitialized refs) and inline types. + // primitives, references (including uninitialized refs) and value types. // Though the 'query' types should technically return 'false' here, if we // allow this to return true, we can perform the test using only // 2 operations rather than 8 (3 masks, 3 compares and 2 logical 'ands'). diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp index 626c28c17118..63e4d7bd857a 100644 --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -68,7 +68,7 @@ #define NOFAILOVER_MAJOR_VERSION 51 #define NONZERO_PADDING_BYTES_IN_SWITCH_MAJOR_VERSION 51 #define STATIC_METHOD_IN_INTERFACE_MAJOR_VERSION 52 -#define INLINE_TYPE_MAJOR_VERSION 56 +#define VALUE_TYPE_MAJOR_VERSION 56 #define MAX_ARRAY_DIMENSIONS 255 // Access to external entry for VerifyClassForMajorVersion - old byte code verifier @@ -507,12 +507,12 @@ void ErrorContext::reason_details(outputStream* ss) const { case BAD_STACKMAP: ss->print("Invalid stackmap specification."); break; - case WRONG_INLINE_TYPE: + case WRONG_VALUE_TYPE: ss->print("Type "); _type.details(ss); ss->print(" and type "); _expected.details(ss); - ss->print(" must be identical inline types."); + ss->print(" must be identical value types."); break; case UNKNOWN: default: @@ -732,17 +732,16 @@ void ClassVerifier::verify_method(const methodHandle& m, TRAPS) { assert(SignatureVerifier::is_valid_method_signature(m->signature()), "Invalid method signature"); - // Collect the initial strict instance fields - StackMapFrame::AssertUnsetFieldTable* strict_fields = new StackMapFrame::AssertUnsetFieldTable(); + // Collect the initial strict instance fields if there are any + AssertUnsetFieldTable* strict_fields = nullptr; if (m->is_object_constructor()) { for (AllFieldStream fs(m->method_holder()); !fs.done(); fs.next()) { if (fs.access_flags().is_strict() && !fs.access_flags().is_static()) { - NameAndSig new_field(fs.name(), fs.signature()); - if (IgnoreAssertUnsetFields) { - strict_fields->put(new_field, true); - } else { - strict_fields->put(new_field, false); + if (strict_fields == nullptr) { + strict_fields = new AssertUnsetFieldTable(); } + NameAndSig new_field(fs.name(), fs.signature()); + strict_fields->put(new_field, true); } } } @@ -751,7 +750,7 @@ void ClassVerifier::verify_method(const methodHandle& m, TRAPS) { // the "current frame" will modify this table when a putfield is encountered during verification. // When parsing the StackMapTable attribute, the reader will allocate new tables for frames if // they are EARLY_LARVAL, otherwise this read-only initial set will be shared. - StackMapFrame::AssertUnsetFieldTable* read_only_strict_fields = StackMapFrame::copy_unset_fields(strict_fields); + AssertUnsetFieldTable* read_only_strict_fields = StackMapFrame::copy_unset_fields(strict_fields); // Initial stack map frame: offset is 0, stack is initially empty. StackMapFrame current_frame(max_locals, max_stack, strict_fields, this); @@ -2419,12 +2418,7 @@ void ClassVerifier::verify_field_instructions(RawBytecodeStream* bcs, stack_object_type = current_type(); if (fd.access_flags().is_strict()) { - if (!current_frame->satisfy_unset_field(fd.name(), fd.signature())) { - log_info(verification)("Attempting to initialize field not found in initial strict instance fields: %s%s", - fd.name()->as_C_string(), fd.signature()->as_C_string()); - verify_error(ErrorContext::bad_strict_fields(bci, current_frame), - "Initializing unknown strict field: %s:%s", fd.name()->as_C_string(), fd.signature()->as_C_string()); - } + current_frame->satisfy_unset_field(fd.name(), fd.signature()); } } } else if (Verifier::supports_strict_fields(_klass)) { @@ -2533,6 +2527,14 @@ void ClassVerifier::verify_invoke_init( stackmap_table, CHECK_VERIFY(this)); } // in_try_block + // At this point, all unset fields were satisfied, a delegated constructor handled + // the strict fields and initialization, or a VerifyError was recorded earlier. + // In the case of a delegated constructor, it could have handled the strict + // fields successfully but the current frame still may have unsatisfied debts so + // the unset fields list should be cleared. + // Exception handling is now complete so it is safe to null out the unset fields. + current_frame->set_assert_unset_fields(nullptr); + current_frame->initialize_object(type, current_type()); *this_uninit = true; } else if (type.is_uninitialized()) { @@ -2734,7 +2736,7 @@ void ClassVerifier::verify_invoke_instructions( // or any superclass (including Object). else if (opcode == Bytecodes::_invokespecial && !is_same_or_direct_interface(current_class(), current_type(), ref_class_type) - && !ref_class_type.equals(VerificationType::reference_type(current_class()->super()->name()))) { // super() can never be an inline_type. + && !ref_class_type.equals(VerificationType::reference_type(current_class()->super()->name()))) { // super() can never be a value_type. // We know it is not current class, direct superinterface or immediate superclass. That means it // could be: diff --git a/src/hotspot/share/classfile/verifier.hpp b/src/hotspot/share/classfile/verifier.hpp index 97a546736a4a..322d1ed2610f 100644 --- a/src/hotspot/share/classfile/verifier.hpp +++ b/src/hotspot/share/classfile/verifier.hpp @@ -40,6 +40,21 @@ struct NameAndSig { NameAndSig(Symbol* n, Symbol* s) : _name(n), _signature(s) {} }; +inline unsigned int nameandsig_hash(NameAndSig const& field) { + Symbol* name = field._name; + return (unsigned int) name->identity_hash(); +} + +inline bool nameandsig_equals(NameAndSig const& f1, NameAndSig const& f2) { + return f1._name == f2._name && + f1._signature == f2._signature; +} + +// List of unset strict fields. The boolean value is a dummy so this acts as a set +typedef HashTable AssertUnsetFieldTable; + // The verifier class class Verifier : AllStatic { public: @@ -167,7 +182,7 @@ class ErrorContext { STACK_UNDERFLOW, // Attempt to pop and empty expression stack MISSING_STACKMAP, // No stackmap for this location and there should be BAD_STACKMAP, // Format error in stackmap - WRONG_INLINE_TYPE, // Mismatched inline type + WRONG_VALUE_TYPE, // Mismatched value type NO_FAULT, // No error UNKNOWN } FaultType; @@ -239,8 +254,8 @@ class ErrorContext { static ErrorContext bad_stackmap(int index, StackMapFrame* frame) { return ErrorContext(0, BAD_STACKMAP, TypeOrigin::frame(frame)); } - static ErrorContext bad_inline_type(int bci, TypeOrigin type, TypeOrigin exp) { - return ErrorContext(bci, WRONG_INLINE_TYPE, type, exp); + static ErrorContext bad_value_type(int bci, TypeOrigin type, TypeOrigin exp) { + return ErrorContext(bci, WRONG_VALUE_TYPE, type, exp); } bool is_valid() const { return _fault != NO_FAULT; } diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index 5094a3371bc6..825f0bc9a6c6 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -1026,6 +1026,17 @@ class methodHandle; do_name( getAndSetReference_name, "getAndSetReference") \ do_signature(getAndSetReference_signature, "(Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object;" ) \ \ + do_class(jdk_internal_math_Int128Math, "jdk/internal/math/Int128Math") \ + do_signature(int128t_addsub_signature, "(JJJJ)J") \ + do_intrinsic(_addInt128TLo, jdk_internal_math_Int128Math, addInt128TLo_name, int128t_addsub_signature, F_S) \ + do_name( addInt128TLo_name, "addLo") \ + do_intrinsic(_addInt128THi, jdk_internal_math_Int128Math, addInt128THi_name, int128t_addsub_signature, F_S) \ + do_name( addInt128THi_name, "addHi") \ + do_intrinsic(_subInt128TLo, jdk_internal_math_Int128Math, subInt128TLo_name, int128t_addsub_signature, F_S) \ + do_name( subInt128TLo_name, "subLo") \ + do_intrinsic(_subInt128THi, jdk_internal_math_Int128Math, subInt128THi_name, int128t_addsub_signature, F_S) \ + do_name( subInt128THi_name, "subHi") \ + \ /* Float16Math API intrinsification support */ \ /* Float16 signatures */ \ do_signature(float16_unary_math_op_sig, "(Ljava/lang/Class;" \ diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index d51b5ca68d1f..e97f522b9ab4 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -216,8 +216,8 @@ void AOTCodeCache::initialize() { return; // AOTCache must be specified to dump and use AOT code } - if (VerifyOops && InlineTypePassFieldsAsArgs) { - log_info(aot, codecache, init)("AOT Adapter Caching is not supported with VerifyOops + InlineTypePassFieldsAsArgs."); + if (VerifyOops && ValueTypePassFieldsAsArgs) { + log_info(aot, codecache, init)("AOT Adapter Caching is not supported with VerifyOops + ValueTypePassFieldsAsArgs."); FLAG_SET_ERGO(AOTAdapterCaching, false); } @@ -1929,8 +1929,8 @@ void AOTCodeAddressTable::init_extrs() { ADD_EXTERNAL_ADDRESS(SharedRuntime::throw_delayed_StackOverflowError); ADD_EXTERNAL_ADDRESS(StubRoutines::verify_oop_count_addr()); // used by generate_verify_oop() ADD_EXTERNAL_ADDRESS(StubRoutines::verify_oop_subroutine_entry_address()); - if (InlineTypeReturnedAsFields) { - ADD_EXTERNAL_ADDRESS(SharedRuntime::store_inline_type_fields_to_buf); + if (ValueTypeReturnedAsFields) { + ADD_EXTERNAL_ADDRESS(SharedRuntime::store_value_type_fields_to_buf); } } @@ -1939,7 +1939,7 @@ void AOTCodeAddressTable::init_extrs() { ADD_EXTERNAL_ADDRESS(SharedRuntime::handle_wrong_method); ADD_EXTERNAL_ADDRESS(SharedRuntime::handle_wrong_method_abstract); ADD_EXTERNAL_ADDRESS(SharedRuntime::handle_wrong_method_ic_miss); - ADD_EXTERNAL_ADDRESS(SharedRuntime::allocate_inline_types); + ADD_EXTERNAL_ADDRESS(SharedRuntime::allocate_value_types); #if defined(AARCH64) && !defined(ZERO) ADD_EXTERNAL_ADDRESS(JavaThread::aarch64_get_thread_helper); #endif @@ -2064,8 +2064,8 @@ void AOTCodeAddressTable::init_extrs() { ADD_EXTERNAL_ADDRESS(Runtime1::load_flat_array); ADD_EXTERNAL_ADDRESS(Runtime1::store_flat_array); ADD_EXTERNAL_ADDRESS(Runtime1::substitutability_check); - ADD_EXTERNAL_ADDRESS(Runtime1::buffer_inline_args); - ADD_EXTERNAL_ADDRESS(Runtime1::buffer_inline_args_no_receiver); + ADD_EXTERNAL_ADDRESS(Runtime1::buffer_value_args); + ADD_EXTERNAL_ADDRESS(Runtime1::buffer_value_args_no_receiver); ADD_EXTERNAL_ADDRESS(Runtime1::throw_identity_exception); ADD_EXTERNAL_ADDRESS(Runtime1::throw_illegal_monitor_state_exception); // already added @@ -2093,8 +2093,8 @@ void AOTCodeAddressTable::init_extrs() { ADD_EXTERNAL_ADDRESS(OptoRuntime::rethrow_C); ADD_EXTERNAL_ADDRESS(OptoRuntime::slow_arraycopy_C); ADD_EXTERNAL_ADDRESS(OptoRuntime::register_finalizer_C); - ADD_EXTERNAL_ADDRESS(OptoRuntime::load_unknown_inline_C); - ADD_EXTERNAL_ADDRESS(OptoRuntime::store_unknown_inline_C); + ADD_EXTERNAL_ADDRESS(OptoRuntime::load_unknown_value_C); + ADD_EXTERNAL_ADDRESS(OptoRuntime::store_unknown_value_C); ADD_EXTERNAL_ADDRESS(OptoRuntime::vthread_end_first_transition_C); ADD_EXTERNAL_ADDRESS(OptoRuntime::vthread_start_final_transition_C); ADD_EXTERNAL_ADDRESS(OptoRuntime::vthread_start_transition_C); diff --git a/src/hotspot/share/code/aotCodeCache.hpp b/src/hotspot/share/code/aotCodeCache.hpp index bd5a872e181c..a0ebb8145ebf 100644 --- a/src/hotspot/share/code/aotCodeCache.hpp +++ b/src/hotspot/share/code/aotCodeCache.hpp @@ -302,7 +302,7 @@ class AOTStubData : public StackObj { do_var(bool, UseSHA512Intrinsics) \ do_var(bool, UseIntPolyIntrinsics) \ do_var(bool, UseVectorizedMismatchIntrinsic) \ - do_var(bool, InlineTypeReturnedAsFields) \ + do_var(bool, ValueTypeReturnedAsFields) \ do_var(bool, VMContinuations) \ do_var(bool, VerifyOops) \ do_fun(int, CompressedKlassPointers_shift, CompressedKlassPointers::shift()) \ diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 70aea006e16c..4d136b769067 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -64,7 +64,7 @@ static_assert(!std::is_polymorphic::value, "no virtual metho static_assert(!std::is_polymorphic::value, "no virtual methods are allowed in code blobs"); static_assert(!std::is_polymorphic::value, "no virtual methods are allowed in code blobs"); static_assert(!std::is_polymorphic::value, "no virtual methods are allowed in code blobs"); -static_assert(!std::is_polymorphic::value, "no virtual methods are allowed in code blobs"); +static_assert(!std::is_polymorphic::value, "no virtual methods are allowed in code blobs"); static_assert(!std::is_polymorphic::value, "no virtual methods are allowed in code blobs"); static_assert(!std::is_polymorphic::value, "no virtual methods are allowed in code blobs"); static_assert(!std::is_polymorphic::value, "no virtual methods are allowed in code blobs"); @@ -95,7 +95,7 @@ const CodeBlob::Vptr* CodeBlob::vptr(CodeBlobKind kind) { &AdapterBlob::_vpntr, &VtableBlob::_vpntr, &MethodHandlesAdapterBlob::_vpntr, - &BufferedInlineTypeBlob::_vpntr, + &BufferedValueTypeBlob::_vpntr, &RuntimeStub::_vpntr, &DeoptimizationBlob::_vpntr, &SafepointBlob::_vpntr, @@ -471,10 +471,10 @@ AdapterBlob::AdapterBlob(int size, CodeBuffer* cb, int entry_offset[AdapterBlob: } #endif // ASSERT _c2i_offset = entry_offset[C2I]; - _c2i_inline_offset = entry_offset[C2I_Inline]; - _c2i_inline_ro_offset = entry_offset[C2I_Inline_RO]; + _c2i_value_offset = entry_offset[C2I_Value]; + _c2i_value_ro_offset = entry_offset[C2I_Value_RO]; _c2i_unverified_offset = entry_offset[C2I_Unverified]; - _c2i_unverified_inline_offset = entry_offset[C2I_Unverified_Inline]; + _c2i_unverified_value_offset = entry_offset[C2I_Unverified_Value]; _c2i_no_clinit_check_offset = entry_offset[C2I_No_Clinit_Check]; CodeCache::commit(this); } @@ -572,23 +572,23 @@ MethodHandlesAdapterBlob* MethodHandlesAdapterBlob::create(int buffer_size) { } //---------------------------------------------------------------------------------------------------- -// Implementation of BufferedInlineTypeBlob -BufferedInlineTypeBlob::BufferedInlineTypeBlob(int size, CodeBuffer* cb, int pack_fields_off, int pack_fields_jobject_off, int unpack_fields_off) : - BufferBlob("buffered inline type", CodeBlobKind::BufferedInlineType, cb, size, sizeof(BufferedInlineTypeBlob)), +// Implementation of BufferedValueTypeBlob +BufferedValueTypeBlob::BufferedValueTypeBlob(int size, CodeBuffer* cb, int pack_fields_off, int pack_fields_jobject_off, int unpack_fields_off) : + BufferBlob("buffered value type", CodeBlobKind::BufferedValueType, cb, size, sizeof(BufferedValueTypeBlob)), _pack_fields_off(pack_fields_off), _pack_fields_jobject_off(pack_fields_jobject_off), _unpack_fields_off(unpack_fields_off) { CodeCache::commit(this); } -BufferedInlineTypeBlob* BufferedInlineTypeBlob::create(CodeBuffer* cb, int pack_fields_off, int pack_fields_jobject_off, int unpack_fields_off) { +BufferedValueTypeBlob* BufferedValueTypeBlob::create(CodeBuffer* cb, int pack_fields_off, int pack_fields_jobject_off, int unpack_fields_off) { ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock - BufferedInlineTypeBlob* blob = nullptr; - unsigned int size = CodeBlob::allocation_size(cb, sizeof(BufferedInlineTypeBlob)); + BufferedValueTypeBlob* blob = nullptr; + unsigned int size = CodeBlob::allocation_size(cb, sizeof(BufferedValueTypeBlob)); { MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - blob = new (size) BufferedInlineTypeBlob(size, cb, pack_fields_off, pack_fields_jobject_off, unpack_fields_off); + blob = new (size) BufferedValueTypeBlob(size, cb, pack_fields_off, pack_fields_jobject_off, unpack_fields_off); } // Track memory usage statistic after releasing CodeCache_lock MemoryService::track_code_cache_memory_usage(); diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index 776f90e77a62..e95836c8dd34 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -60,7 +60,7 @@ enum class CodeBlobType { // AdapterBlob : Used to hold C2I/I2C adapters // VtableBlob : Used for holding vtable chunks // MethodHandlesAdapterBlob : Used to hold MethodHandles adapters -// BufferedInlineTypeBlob : used for pack/unpack handlers +// BufferedValueTypeBlob : used for pack/unpack handlers // RuntimeStub : Call to VM runtime methods // SingletonBlob : Super-class for all blobs that exist in only one instance // DeoptimizationBlob : Used for deoptimization @@ -86,7 +86,7 @@ enum class CodeBlobKind : u1 { Adapter, Vtable, MHAdapter, - BufferedInlineType, + BufferedValueType, RuntimeStub, Deoptimization, Safepoint, @@ -220,7 +220,7 @@ class CodeBlob { bool is_adapter_blob() const { return _kind == CodeBlobKind::Adapter; } bool is_vtable_blob() const { return _kind == CodeBlobKind::Vtable; } bool is_method_handles_adapter_blob() const { return _kind == CodeBlobKind::MHAdapter; } - bool is_buffered_inline_type_blob() const { return _kind == CodeBlobKind::BufferedInlineType; } + bool is_buffered_value_type_blob() const { return _kind == CodeBlobKind::BufferedValueType; } bool is_upcall_stub() const { return _kind == CodeBlobKind::Upcall; } // Casting @@ -391,7 +391,7 @@ class BufferBlob: public RuntimeBlob { friend class AdapterBlob; friend class VtableBlob; friend class MethodHandlesAdapterBlob; - friend class BufferedInlineTypeBlob; + friend class BufferedValueTypeBlob; friend class UpcallStub; friend class WhiteBox; @@ -434,10 +434,10 @@ class AdapterBlob: public BufferBlob { enum Entry { I2C, C2I, - C2I_Inline, - C2I_Inline_RO, + C2I_Value, + C2I_Value_RO, C2I_Unverified, - C2I_Unverified_Inline, + C2I_Unverified_Value, C2I_No_Clinit_Check, ENTRY_COUNT }; @@ -446,10 +446,10 @@ class AdapterBlob: public BufferBlob { // _i2c_offset is always 0 so no need to store it int _c2i_offset; - int _c2i_inline_offset; - int _c2i_inline_ro_offset; + int _c2i_value_offset; + int _c2i_value_ro_offset; int _c2i_unverified_offset; - int _c2i_unverified_inline_offset; + int _c2i_unverified_value_offset; int _c2i_no_clinit_check_offset; public: // Creation @@ -464,10 +464,10 @@ class AdapterBlob: public BufferBlob { static AdapterBlob* create(CodeBuffer* cb, int entry_offset[ENTRY_COUNT]); address i2c_entry() { return code_begin(); } address c2i_entry() { return i2c_entry() + _c2i_offset; } - address c2i_inline_entry() { return i2c_entry() + _c2i_inline_offset; } - address c2i_inline_ro_entry() { return i2c_entry() + _c2i_inline_ro_offset; } + address c2i_value_entry() { return i2c_entry() + _c2i_value_offset; } + address c2i_value_ro_entry() { return i2c_entry() + _c2i_value_ro_offset; } address c2i_unverified_entry() { return i2c_entry() + _c2i_unverified_offset; } - address c2i_unverified_inline_entry() { return i2c_entry() + _c2i_unverified_inline_offset; } + address c2i_unverified_value_entry() { return i2c_entry() + _c2i_unverified_value_offset; } address c2i_no_clinit_check_entry() { return _c2i_no_clinit_check_offset == -1 ? nullptr : i2c_entry() + _c2i_no_clinit_check_offset; } }; @@ -496,19 +496,19 @@ class MethodHandlesAdapterBlob: public BufferBlob { }; //---------------------------------------------------------------------------------------------------- -// BufferedInlineTypeBlob : used for pack/unpack handlers +// BufferedValueTypeBlob : used for pack/unpack handlers -class BufferedInlineTypeBlob: public BufferBlob { +class BufferedValueTypeBlob: public BufferBlob { private: const int _pack_fields_off; const int _pack_fields_jobject_off; const int _unpack_fields_off; - BufferedInlineTypeBlob(int size, CodeBuffer* cb, int pack_fields_off, int pack_fields_jobject_off, int unpack_fields_off); + BufferedValueTypeBlob(int size, CodeBuffer* cb, int pack_fields_off, int pack_fields_jobject_off, int unpack_fields_off); public: // Creation - static BufferedInlineTypeBlob* create(CodeBuffer* cb, int pack_fields_off, int pack_fields_jobject_off, int unpack_fields_off); + static BufferedValueTypeBlob* create(CodeBuffer* cb, int pack_fields_off, int pack_fields_jobject_off, int unpack_fields_off); address pack_fields() const { return code_begin() + _pack_fields_off; } address pack_fields_jobject() const { return code_begin() + _pack_fields_jobject_off; } diff --git a/src/hotspot/share/code/compiledIC.cpp b/src/hotspot/share/code/compiledIC.cpp index 69434488ca54..aefa3b8b9a6c 100644 --- a/src/hotspot/share/code/compiledIC.cpp +++ b/src/hotspot/share/code/compiledIC.cpp @@ -200,9 +200,9 @@ void CompiledIC::set_to_monomorphic(bool caller_is_c1) { bool to_compiled = code != nullptr && code->is_in_use() && !code->is_unloading(); if (to_compiled) { - entry = caller_is_c1 ? code->inline_entry_point() : code->entry_point(); + entry = caller_is_c1 ? code->value_entry_point() : code->entry_point(); } else { - entry = caller_is_c1 ? method->get_c2i_unverified_inline_entry() : method->get_c2i_unverified_entry(); + entry = caller_is_c1 ? method->get_c2i_unverified_value_entry() : method->get_c2i_unverified_entry(); } log_trace(inlinecache)("IC@" INTPTR_FORMAT ": monomorphic to %s: %s", @@ -346,13 +346,13 @@ void CompiledDirectCall::set(const methodHandle& callee_method, bool caller_is_c bool to_compiled = !to_interp_cont_enter && code != nullptr && code->is_in_use() && !code->is_unloading(); if (to_compiled) { - _call->set_destination_mt_safe(caller_is_c1 ? code->verified_inline_entry_point() : code->verified_entry_point()); + _call->set_destination_mt_safe(caller_is_c1 ? code->verified_value_entry_point() : code->verified_entry_point()); assert(is_call_to_compiled(), "should be compiled after set to compiled"); } else { // Patch call site to C2I adapter if code is deoptimized or unloaded. // We also need to patch the static call stub to set the rmethod register // to the callee_method so the c2i adapter knows how to build the frame - set_to_interpreted(callee_method, caller_is_c1 ? callee_method->get_c2i_inline_entry() : callee_method->get_c2i_entry()); + set_to_interpreted(callee_method, caller_is_c1 ? callee_method->get_c2i_value_entry() : callee_method->get_c2i_entry()); assert(is_call_to_interpreted(), "should be interpreted after set to interpreted"); } diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 30cd400058b5..5a4457f567a4 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -689,8 +689,8 @@ void nmethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map has_appendix = false; signature = callee->signature(); - // If inline types are passed as fields, use the extended signature - // which contains the types of all (oop) fields of the inline type. + // If value types are passed as fields, use the extended signature + // which contains the types of all (oop) fields of the value type. if (is_compiled_by_c2() && callee->has_scalarized_args()) { const GrowableArray* sig = callee->adapter()->get_sig_cc(); assert(sig != nullptr, "sig should never be null"); @@ -1200,9 +1200,9 @@ void nmethod::init_defaults(CodeBuffer *code_buffer, CodeOffsets* offsets) { CHECKED_CAST(_entry_offset, uint16_t, (offsets->value(CodeOffsets::Entry))); CHECKED_CAST(_verified_entry_offset, uint16_t, (offsets->value(CodeOffsets::Verified_Entry))); - _inline_entry_offset = _entry_offset; - _verified_inline_entry_offset = _verified_entry_offset; - _verified_inline_ro_entry_offset = _verified_entry_offset; + _value_entry_offset = _entry_offset; + _verified_value_entry_offset = _verified_entry_offset; + _verified_value_ro_entry_offset = _verified_entry_offset; _skipped_instructions_size = code_buffer->total_skipped_instructions_size(); } @@ -1402,9 +1402,9 @@ nmethod::nmethod(const nmethod &nm) : CodeBlob(nm._name, nm._kind, nm._size, nm. } _entry_offset = nm._entry_offset; _verified_entry_offset = nm._verified_entry_offset; - _inline_entry_offset = nm._inline_entry_offset; - _verified_inline_entry_offset = nm._verified_inline_entry_offset; - _verified_inline_ro_entry_offset = nm._verified_inline_ro_entry_offset; + _value_entry_offset = nm._value_entry_offset; + _verified_value_entry_offset = nm._verified_value_entry_offset; + _verified_value_ro_entry_offset = nm._verified_value_ro_entry_offset; _entry_bci = nm._entry_bci; _immutable_data_size = nm._immutable_data_size; @@ -1680,14 +1680,14 @@ nmethod::nmethod( } int metadata_size = align_up(code_buffer->total_metadata_size(), wordSize); - if (offsets->value(CodeOffsets::Inline_Entry) != CodeOffsets::no_such_entry_point) { - CHECKED_CAST(_inline_entry_offset , uint16_t, offsets->value(CodeOffsets::Inline_Entry)); + if (offsets->value(CodeOffsets::Value_Entry) != CodeOffsets::no_such_entry_point) { + CHECKED_CAST(_value_entry_offset , uint16_t, offsets->value(CodeOffsets::Value_Entry)); } - if (offsets->value(CodeOffsets::Verified_Inline_Entry) != CodeOffsets::no_such_entry_point) { - CHECKED_CAST(_verified_inline_entry_offset , uint16_t, offsets->value(CodeOffsets::Verified_Inline_Entry)); + if (offsets->value(CodeOffsets::Verified_Value_Entry) != CodeOffsets::no_such_entry_point) { + CHECKED_CAST(_verified_value_entry_offset , uint16_t, offsets->value(CodeOffsets::Verified_Value_Entry)); } - if (offsets->value(CodeOffsets::Verified_Inline_Entry_RO) != CodeOffsets::no_such_entry_point) { - CHECKED_CAST(_verified_inline_ro_entry_offset, uint16_t, offsets->value(CodeOffsets::Verified_Inline_Entry_RO)); + if (offsets->value(CodeOffsets::Verified_Value_Entry_RO) != CodeOffsets::no_such_entry_point) { + CHECKED_CAST(_verified_value_ro_entry_offset, uint16_t, offsets->value(CodeOffsets::Verified_Value_Entry_RO)); } assert(_mutable_data_size == _relocation_size + metadata_size, @@ -3911,10 +3911,10 @@ const char* nmethod::nmethod_section_label(address pos) const { const char* label = nullptr; if (pos == code_begin()) label = "[Instructions begin]"; if (pos == entry_point()) label = "[Entry Point]"; - if (pos == inline_entry_point()) label = "[Inline Entry Point]"; + if (pos == value_entry_point()) label = "[Value Entry Point]"; if (pos == verified_entry_point()) label = "[Verified Entry Point]"; - if (pos == verified_inline_entry_point()) label = "[Verified Inline Entry Point]"; - if (pos == verified_inline_ro_entry_point()) label = "[Verified Inline Entry Point (RO)]"; + if (pos == verified_value_entry_point()) label = "[Verified Value Entry Point]"; + if (pos == verified_value_ro_entry_point()) label = "[Verified Value Entry Point (RO)]"; if (pos == consts_begin() && pos != insts_begin()) label = "[Constants]"; // Check stub_code before checking exception_handler or deopt_handler. if (pos == this->stub_begin()) label = "[Stub Code]"; @@ -3938,10 +3938,10 @@ void nmethod::print_nmethod_labels(outputStream* stream, address block_begin, bo int n = 0; // Multiple entry points may be at the same position. Print them all. n += maybe_print_entry_label(stream, block_begin, entry_point(), "[Entry Point]"); - n += maybe_print_entry_label(stream, block_begin, inline_entry_point(), "[Inline Entry Point]"); + n += maybe_print_entry_label(stream, block_begin, value_entry_point(), "[Value Entry Point]"); n += maybe_print_entry_label(stream, block_begin, verified_entry_point(), "[Verified Entry Point]"); - n += maybe_print_entry_label(stream, block_begin, verified_inline_entry_point(), "[Verified Inline Entry Point]"); - n += maybe_print_entry_label(stream, block_begin, verified_inline_ro_entry_point(), "[Verified Inline Entry Point (RO)]"); + n += maybe_print_entry_label(stream, block_begin, verified_value_entry_point(), "[Verified Value Entry Point]"); + n += maybe_print_entry_label(stream, block_begin, verified_value_ro_entry_point(), "[Verified Value Entry Point (RO)]"); if (n == 0) { const char* label = nmethod_section_label(block_begin); if (label != nullptr) { @@ -3959,15 +3959,15 @@ void nmethod::print_nmethod_labels(outputStream* stream, address block_begin, bo // Print the name of the method (only once) address low = MIN3(entry_point(), verified_entry_point(), - inline_entry_point()); - // The verified inline entry point and verified inline RO entry point are not always - // used. When they are unused. CodeOffsets::Verified_Inline_Entry(_RO) is -1. Hence, + value_entry_point()); + // The verified value entry point and verified value RO entry point are not always + // used. When they are unused. CodeOffsets::Verified_Value_Entry(_RO) is -1. Hence, // the calculated entry point is smaller than the block they are offsetting into. - if (verified_inline_entry_point() >= block_begin) { - low = MIN2(low, verified_inline_entry_point()); + if (verified_value_entry_point() >= block_begin) { + low = MIN2(low, verified_value_entry_point()); } - if (verified_inline_ro_entry_point() >= block_begin) { - low = MIN2(low, verified_inline_ro_entry_point()); + if (verified_value_ro_entry_point() >= block_begin) { + low = MIN2(low, verified_value_ro_entry_point()); } assert(low != nullptr, "sanity"); if (block_begin == low) { @@ -3984,10 +3984,10 @@ void nmethod::print_nmethod_labels(outputStream* stream, address block_begin, bo if (block_begin == verified_entry_point()) { sig_cc = ces.sig_cc(); regs = ces.regs_cc(); - } else if (block_begin == verified_inline_entry_point()) { + } else if (block_begin == verified_value_entry_point()) { sig_cc = ces.sig(); regs = ces.regs(); - } else if (block_begin == verified_inline_ro_entry_point()) { + } else if (block_begin == verified_value_ro_entry_point()) { sig_cc = ces.sig_cc_ro(); regs = ces.regs_cc_ro(); } else { @@ -3995,7 +3995,7 @@ void nmethod::print_nmethod_labels(outputStream* stream, address block_begin, bo } bool has_this = !m->is_static(); - if (ces.has_inline_recv() && block_begin == verified_entry_point()) { + if (ces.has_value_recv() && block_begin == verified_entry_point()) { // argument is scalarized for verified_entry_point() has_this = false; } diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 8a06037a1619..f301847f1f99 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -209,9 +209,9 @@ class nmethod : public CodeBlob { address _osr_entry_point; // entry point for on stack replacement uint16_t _entry_offset; // entry point with class check uint16_t _verified_entry_offset; // entry point without class check - uint16_t _inline_entry_offset; // inline type entry point (unpack all inline type args) with class check - uint16_t _verified_inline_entry_offset; // inline type entry point (unpack all inline type args) without class check - uint16_t _verified_inline_ro_entry_offset; // inline type entry point (unpack receiver only) without class check + uint16_t _value_entry_offset; // value type entry point (unpack all value type args) with class check + uint16_t _verified_value_entry_offset; // value type entry point (unpack all value type args) without class check + uint16_t _verified_value_ro_entry_offset; // value type entry point (unpack receiver only) without class check int _entry_bci; // != InvocationEntryBci if this nmethod is an on-stack replacement method int _immutable_data_size; @@ -683,9 +683,9 @@ class nmethod : public CodeBlob { // entry points address entry_point() const { return code_begin() + _entry_offset; } // normal entry point address verified_entry_point() const { return code_begin() + _verified_entry_offset; } // if klass is correct - address inline_entry_point() const { return code_begin() + _inline_entry_offset; } // inline type entry point (unpack all inline type args) - address verified_inline_entry_point() const { return code_begin() + _verified_inline_entry_offset; } // inline type entry point (unpack all inline type args) without class check - address verified_inline_ro_entry_point() const { return code_begin() + _verified_inline_ro_entry_offset; } // inline type entry point (only unpack receiver) without class check + address value_entry_point() const { return code_begin() + _value_entry_offset; } // value type entry point (unpack all value type args) + address verified_value_entry_point() const { return code_begin() + _verified_value_entry_offset; } // value type entry point (unpack all value type args) without class check + address verified_value_ro_entry_point() const { return code_begin() + _verified_value_ro_entry_offset; } // value type entry point (only unpack receiver) without class check enum : signed char { not_installed = -1, // in construction, only the owner doing the construction is // allowed to advance state @@ -825,7 +825,7 @@ class nmethod : public CodeBlob { const char* state() const; bool inlinecache_check_contains(address addr) const { - return (addr >= code_begin() && (addr < verified_entry_point() || addr < verified_inline_entry_point())); + return (addr >= code_begin() && (addr < verified_entry_point() || addr < verified_value_entry_point())); } void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f); diff --git a/src/hotspot/share/gc/g1/g1Allocator.cpp b/src/hotspot/share/gc/g1/g1Allocator.cpp index 5815b0b48599..3fb60fec888c 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.cpp +++ b/src/hotspot/share/gc/g1/g1Allocator.cpp @@ -68,8 +68,7 @@ G1Allocator::~G1Allocator() { } #ifdef ASSERT -bool G1Allocator::has_mutator_alloc_region() { - uint node_index = current_node_index(); +bool G1Allocator::has_mutator_alloc_region(uint node_index) { return mutator_alloc_region(node_index)->get() != nullptr; } #endif @@ -153,7 +152,7 @@ void G1Allocator::release_gc_alloc_regions(G1EvacInfo* evacuation_info) { num_survivor_regions += survivor_gc_alloc_region(node_index)->num_regions_used(); survivor_gc_alloc_region(node_index)->release(); } - evacuation_info->set_allocation_regions(num_survivor_regions + + evacuation_info->set_num_allocation_regions(num_survivor_regions + old_gc_alloc_region()->num_regions_used()); // If we have an old GC alloc region to release, we'll save it in diff --git a/src/hotspot/share/gc/g1/g1Allocator.hpp b/src/hotspot/share/gc/g1/g1Allocator.hpp index e340e2b40d1a..0312e3d25d29 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.hpp +++ b/src/hotspot/share/gc/g1/g1Allocator.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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 @@ -94,7 +94,7 @@ class G1Allocator : public CHeapObj { #ifdef ASSERT // Do we currently have an active mutator region to allocate into? - bool has_mutator_alloc_region(); + bool has_mutator_alloc_region(uint node_index); #endif void init_mutator_alloc_regions(); diff --git a/src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp b/src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp index 7f0e5e86cd91..a3f4bab75672 100644 --- a/src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp +++ b/src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp @@ -270,8 +270,8 @@ void G1BlockOffsetTable::verify_for_block(HeapWord* blk_start, HeapWord* blk_end Atomic* value = current_card; if (offset_array(prev) != offset_array(value)) { assert(offset_array(value) >= offset_array(prev), "monotonic"); - size_t n_cards_back = BOTConstants::entry_to_cards_back(offset_array(value)); - assert(start_card == (current_card - n_cards_back), "inv"); + size_t num_cards_back = BOTConstants::entry_to_cards_back(offset_array(value)); + assert(start_card == (current_card - num_cards_back), "inv"); } } } diff --git a/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp b/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp index 1236d24bb03a..8a3c0a51235f 100644 --- a/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp +++ b/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp @@ -37,8 +37,8 @@ inline HeapWord* G1BlockOffsetTable::block_start_reaching_into_card(const void* while (offset >= CardTable::card_size_in_words()) { // The excess of the offset from N_words indicates a power of Base // to go back by. - size_t n_cards_back = BOTConstants::entry_to_cards_back(offset); - entry -= n_cards_back; + size_t num_cards_back = BOTConstants::entry_to_cards_back(offset); + entry -= num_cards_back; offset = offset_array(entry); } assert(offset < CardTable::card_size_in_words(), "offset too large"); diff --git a/src/hotspot/share/gc/g1/g1CardSet.cpp b/src/hotspot/share/gc/g1/g1CardSet.cpp index 0f66e739362f..4fb566ac1fd2 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.cpp +++ b/src/hotspot/share/gc/g1/g1CardSet.cpp @@ -242,9 +242,9 @@ class G1CardSetHashTable : public CHeapObj { using CHTScanTask = CardSetHash::ScanTask; const static uint BucketClaimSize = 16; - // The claim size for group cardsets should be smaller to facilitate - // better work distribution. The group cardsets should be larger than - // the per region cardsets. + // The claim size for multi-region card set groups should be smaller to + // improve work distribution. The multi-region card set groups' card set + // should contain more entries than the single-region card set groups'. const static uint GroupBucketClaimSize = 4; // Did we insert at least one card in the table? Atomic _inserted_card; @@ -498,7 +498,7 @@ void G1CardSet::release_and_must_free_container(ContainerPtr container) { free_mem_object(container); } -class G1ReleaseCardsets : public StackObj { +class G1ReleaseCardSets : public StackObj { G1CardSet* _card_set; using ContainerPtr = G1CardSet::ContainerPtr; @@ -520,7 +520,7 @@ class G1ReleaseCardsets : public StackObj { } public: - explicit G1ReleaseCardsets(G1CardSet* card_set) : _card_set(card_set) { } + explicit G1ReleaseCardSets(G1CardSet* card_set) : _card_set(card_set) { } void operator ()(Atomic* container_addr) { coarsen_to_full(container_addr); @@ -650,7 +650,7 @@ bool G1CardSet::coarsen_container(Atomic* container_addr, assert(!should_free, "must have had more than one reference"); // Free containers if cur_container is ContainerHowl if (container_type(cur_container) == ContainerHowl) { - G1ReleaseCardsets rel(this); + G1ReleaseCardSets rel(this); container_ptr(cur_container)->iterate(rel, _config->num_buckets_in_howl()); } return true; @@ -782,8 +782,8 @@ G1AddCardResult G1CardSet::add_card(uintptr_t card) { { uint region_idx = card_region >> config()->log2_card_regions_per_heap_region(); G1HeapRegion* r = G1CollectedHeap::heap()->region_at(region_idx); - assert(!r->rem_set()->has_cset_group() || - r->rem_set()->cset_group()->card_set() != this, "Should not be sharing a cardset"); + assert(!r->rem_set()->has_card_set_group() || + r->rem_set()->card_set_group()->card_set() != this, "Should not be sharing a card set"); } #endif diff --git a/src/hotspot/share/gc/g1/g1CardSet.hpp b/src/hotspot/share/gc/g1/g1CardSet.hpp index 21a2f5f045e3..8834de60f443 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.hpp +++ b/src/hotspot/share/gc/g1/g1CardSet.hpp @@ -82,7 +82,7 @@ class G1CardSetConfiguration { double cards_in_bitmap_threshold_percent, uint max_buckets_in_howl, double cards_in_howl_threshold_percent, - uint max_cards_in_cardset, + uint max_cards_in_card_set, uint log2_card_region_per_region); ~G1CardSetConfiguration(); @@ -188,7 +188,7 @@ class G1CardSet : public CHeapObj { friend class G1CardSetMtTestTask; friend class G1CardSetTest; friend class G1CheckCardClosure; - friend class G1ReleaseCardsets; + friend class G1ReleaseCardSets; friend class G1TransferCard; // When splitting addresses into region and card within that region, the logical diff --git a/src/hotspot/share/gc/g1/g1CardSetContainers.hpp b/src/hotspot/share/gc/g1/g1CardSetContainers.hpp index 78551479e066..880c02a71ed9 100644 --- a/src/hotspot/share/gc/g1/g1CardSetContainers.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetContainers.hpp @@ -264,7 +264,7 @@ class G1CardSetHowl : public G1CardSetContainer { // 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); + void iterate_card_set(ContainerPtr const container, uint index, CardOrRangeVisitor& found, G1CardSetConfiguration* config); ContainerPtr at(EntryCountType index) const; diff --git a/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp b/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp index 3c6fb9d1a025..c9e7a046ea7a 100644 --- a/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp @@ -335,7 +335,7 @@ 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(at(i), i, found, config); + iterate_card_set(at(i), i, found, config); } } @@ -347,7 +347,7 @@ inline void G1CardSetHowl::iterate(ContainerPtrVisitor& found, uint num_card_set } template -inline void G1CardSetHowl::iterate_cardset(ContainerPtr const container, uint index, CardOrRangeVisitor& found, G1CardSetConfiguration* config) { +inline void G1CardSetHowl::iterate_card_set(ContainerPtr const container, uint index, CardOrRangeVisitor& found, G1CardSetConfiguration* config) { switch (G1CardSet::container_type(container)) { case G1CardSet::ContainerInlinePtr: { if (found.start_iterate(G1GCPhaseTimes::MergeRSHowlInline)) { diff --git a/src/hotspot/share/gc/g1/g1CardTableClaimTable.cpp b/src/hotspot/share/gc/g1/g1CardTableClaimTable.cpp index 27b41ef165ff..35e3665b1b9a 100644 --- a/src/hotspot/share/gc/g1/g1CardTableClaimTable.cpp +++ b/src/hotspot/share/gc/g1/g1CardTableClaimTable.cpp @@ -64,12 +64,12 @@ void G1CardTableClaimTable::reset_all_to_claimed() { void G1CardTableClaimTable::heap_region_iterate_from_worker_offset(G1HeapRegionClosure* cl, uint worker_id, uint max_workers) { // Every worker will actually look at all regions, skipping over regions that // are completed. - const size_t n_regions = _max_reserved_regions; - const uint start_index = (uint)(worker_id * n_regions / max_workers); + const size_t max_num_regions = _max_reserved_regions; + const uint start_index = (uint)(worker_id * max_num_regions / max_workers); - for (uint count = 0; count < n_regions; count++) { - const uint index = (start_index + count) % n_regions; - assert(index < n_regions, "sanity"); + for (uint count = 0; count < max_num_regions; count++) { + const uint index = (start_index + count) % max_num_regions; + assert(index < max_num_regions, "sanity"); // Skip over fully processed regions if (!has_unclaimed_cards(index)) { continue; diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 833d07cb6852..56204aee4864 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -53,6 +53,7 @@ #include "gc/g1/g1InitLogger.hpp" #include "gc/g1/g1MemoryPool.hpp" #include "gc/g1/g1MonotonicArenaFreeMemoryTask.hpp" +#include "gc/g1/g1NUMA.hpp" #include "gc/g1/g1OopClosures.inline.hpp" #include "gc/g1/g1ParallelCleaning.hpp" #include "gc/g1/g1ParScanThreadState.inline.hpp" @@ -476,7 +477,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(uint node_index, size_t word_ } bool succeeded; - result = do_collection_pause(word_size, gc_count_before, &succeeded, GCCause::_g1_inc_collection_pause); + result = do_collection_pause(node_index, word_size, gc_count_before, &succeeded, + GCCause::_g1_inc_collection_pause); if (succeeded) { log_trace(gc, alloc)("%s: Successfully scheduled collection returning " PTR_FORMAT, Thread::current()->name(), p2i(result)); @@ -728,7 +730,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size) { } bool succeeded; - result = do_collection_pause(word_size, gc_count_before, &succeeded, GCCause::_g1_humongous_allocation); + result = do_collection_pause(G1NUMA::AnyNodeIndex, word_size, gc_count_before, &succeeded, + GCCause::_g1_humongous_allocation); if (succeeded) { log_trace(gc, alloc)("%s: Successfully scheduled collection returning " PTR_FORMAT, Thread::current()->name(), p2i(result)); @@ -766,18 +769,18 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size) { return nullptr; } -HeapWord* G1CollectedHeap::attempt_allocation_at_safepoint(size_t word_size, +HeapWord* G1CollectedHeap::attempt_allocation_at_safepoint(uint node_index, + size_t word_size, bool expect_null_mutator_alloc_region) { assert_at_safepoint_on_vm_thread(); - assert(!_allocator->has_mutator_alloc_region() || !expect_null_mutator_alloc_region, - "the current alloc region was unexpectedly found to be non-null"); - - // Fix NUMA node association for the duration of this allocation - const uint node_index = _allocator->current_node_index(); if (!is_humongous(word_size)) { + assert(!_allocator->has_mutator_alloc_region(node_index) || !expect_null_mutator_alloc_region, + "the requested alloc region was unexpectedly found to be non-null"); return _allocator->attempt_allocation_locked(node_index, word_size); } else { + assert(node_index == G1NUMA::AnyNodeIndex, + "Humongous allocation must not have a specific NUMA node index: %u", node_index); HeapWord* result = humongous_obj_allocate(word_size); if (result != nullptr && // We just allocated the humongous object, so the given allocation size is 0. @@ -1009,7 +1012,8 @@ bool G1CollectedHeap::gc_overhead_limit_exceeded() { return _gc_overhead_counter >= GCOverheadLimitThreshold; } -HeapWord* G1CollectedHeap::satisfy_failed_allocation_helper(size_t word_size, +HeapWord* G1CollectedHeap::satisfy_failed_allocation_helper(uint node_index, + size_t word_size, bool do_gc, bool maximal_compaction, bool expect_null_mutator_alloc_region) { @@ -1024,7 +1028,8 @@ HeapWord* G1CollectedHeap::satisfy_failed_allocation_helper(size_t word_size, if (!gc_overhead_limit_exceeded()) { // Let's attempt the allocation first. HeapWord* result = - attempt_allocation_at_safepoint(word_size, + attempt_allocation_at_safepoint(node_index, + word_size, expect_null_mutator_alloc_region); if (result != nullptr) { return result; @@ -1034,7 +1039,7 @@ HeapWord* G1CollectedHeap::satisfy_failed_allocation_helper(size_t word_size, // incremental pauses. Therefore, at least for now, we'll favor // expansion over collection. (This might change in the future if we can // do something smarter than full collection to satisfy a failed alloc.) - result = expand_and_allocate(word_size); + result = expand_and_allocate(node_index, word_size); if (result != nullptr) { return result; } @@ -1058,7 +1063,7 @@ HeapWord* G1CollectedHeap::satisfy_failed_allocation_helper(size_t word_size, return nullptr; } -HeapWord* G1CollectedHeap::satisfy_failed_allocation(size_t word_size) { +HeapWord* G1CollectedHeap::satisfy_failed_allocation(uint node_index, size_t word_size) { assert_at_safepoint_on_vm_thread(); // Update GC overhead limits after the initial garbage collection leading to this @@ -1067,7 +1072,8 @@ HeapWord* G1CollectedHeap::satisfy_failed_allocation(size_t word_size) { // Attempts to allocate followed by Full GC. HeapWord* result = - satisfy_failed_allocation_helper(word_size, + satisfy_failed_allocation_helper(node_index, + word_size, true, /* do_gc */ false, /* maximal_compaction */ false /* expect_null_mutator_alloc_region */); @@ -1077,7 +1083,8 @@ HeapWord* G1CollectedHeap::satisfy_failed_allocation(size_t word_size) { } // Attempts to allocate followed by Full GC that will collect all soft references. - result = satisfy_failed_allocation_helper(word_size, + result = satisfy_failed_allocation_helper(node_index, + word_size, true, /* do_gc */ true, /* maximal_compaction */ true /* expect_null_mutator_alloc_region */); @@ -1087,7 +1094,8 @@ HeapWord* G1CollectedHeap::satisfy_failed_allocation(size_t word_size) { } // Attempts to allocate, no GC - result = satisfy_failed_allocation_helper(word_size, + result = satisfy_failed_allocation_helper(node_index, + word_size, false, /* do_gc */ false, /* maximal_compaction */ true /* expect_null_mutator_alloc_region */); @@ -1112,7 +1120,7 @@ HeapWord* G1CollectedHeap::satisfy_failed_allocation(size_t word_size) { // successful, perform the allocation and return the address of the // allocated block, or else null. -HeapWord* G1CollectedHeap::expand_and_allocate(size_t word_size) { +HeapWord* G1CollectedHeap::expand_and_allocate(uint node_index, size_t word_size) { assert_at_safepoint_on_vm_thread(); _verifier->verify_region_sets_optional(); @@ -1125,7 +1133,8 @@ HeapWord* G1CollectedHeap::expand_and_allocate(size_t word_size) { if (expand(expand_bytes, _workers)) { _hrm.verify_optional(); _verifier->verify_region_sets_optional(); - return attempt_allocation_at_safepoint(word_size, + return attempt_allocation_at_safepoint(node_index, + word_size, false /* expect_null_mutator_alloc_region */); } return nullptr; @@ -1321,7 +1330,7 @@ G1CollectedHeap::G1CollectedHeap() : _rem_set(nullptr), _card_set_config(), _card_set_freelist_pool(G1CardSetConfiguration::num_mem_object_types()), - _young_regions_cset_group(card_set_config(), &_card_set_freelist_pool, G1CSetCandidateGroup::YoungId), + _young_regions_card_set_group(card_set_config(), &_card_set_freelist_pool, G1CardSetGroup::YoungId), _cm(nullptr), _cr(nullptr), _task_queues(nullptr), @@ -1351,15 +1360,15 @@ G1CollectedHeap::G1CollectedHeap() : // Override the default _stack_chunk_max_size so that no humongous stack chunks are created _stack_chunk_max_size = _humongous_object_threshold_in_words; - uint n_queues = ParallelGCThreads; - _task_queues = new G1ScannerTasksQueueSet(n_queues); + uint num_queues = ParallelGCThreads; + _task_queues = new G1ScannerTasksQueueSet(num_queues); - for (uint i = 0; i < n_queues; i++) { + for (uint i = 0; i < num_queues; i++) { G1ScannerTasksQueue* q = new G1ScannerTasksQueue(); _task_queues->register_queue(i, q); } - _partial_array_state_manager = new PartialArrayStateManager(n_queues); + _partial_array_state_manager = new PartialArrayStateManager(num_queues); _gc_tracer_stw->initialize(); } @@ -1540,7 +1549,7 @@ jint G1CollectedHeap::initialize() { G1HeapRegionRemSet::initialize(_reserved); - G1FreeRegionList::set_unrealistically_long_length(max_num_regions() + 1); + G1FreeRegionList::set_unrealistically_large_num_regions(max_num_regions() + 1); _bot = new G1BlockOffsetTable(reserved(), bot_storage); @@ -2115,7 +2124,8 @@ bool G1CollectedHeap::try_collect(size_t allocation_word_size, assert(allocation_word_size == 0, "must be"); // Schedule a standard evacuation pause. We're setting word_size // to 0 which means that we are not requesting a post-GC allocation. - VM_G1CollectForAllocation op(0, /* word_size */ + VM_G1CollectForAllocation op(G1NUMA::AnyNodeIndex, + 0, /* word_size */ counters_before.total_collections(), cause); VMThread::execute(&op); @@ -2457,7 +2467,7 @@ G1HeapSummary G1CollectedHeap::create_g1_heap_summary() { G1EvacSummary G1CollectedHeap::create_g1_evac_summary(G1EvacStats* stats) { return G1EvacSummary(stats->allocated(), stats->wasted(), stats->undo_wasted(), stats->unused(), stats->used(), stats->region_end_waste(), - stats->regions_filled(), stats->num_plab_filled(), + stats->num_filled_regions(), stats->num_plab_filled(), stats->direct_allocated(), stats->num_direct_allocated(), stats->failure_used(), stats->failure_waste()); } @@ -2527,12 +2537,13 @@ void G1CollectedHeap::verify_numa_regions(const char* desc) { } } -HeapWord* G1CollectedHeap::do_collection_pause(size_t word_size, +HeapWord* G1CollectedHeap::do_collection_pause(uint node_index, + size_t word_size, uint gc_count_before, bool* succeeded, GCCause::Cause gc_cause) { assert_heap_not_locked_and_not_at_safepoint(); - VM_G1CollectForAllocation op(word_size, gc_count_before, gc_cause); + VM_G1CollectForAllocation op(node_index, word_size, gc_count_before, gc_cause); VMThread::execute(&op); HeapWord* result = op.result(); @@ -2850,11 +2861,11 @@ void G1CollectedHeap::set_young_gen_card_set_stats(const G1MonotonicArenaMemoryS void G1CollectedHeap::record_obj_copy_mem_stats() { size_t total_old_allocated = _old_evac_stats.allocated() + _old_evac_stats.direct_allocated(); - uint total_allocated = _survivor_evac_stats.regions_filled() + _old_evac_stats.regions_filled(); + uint num_allocated_regions = _survivor_evac_stats.num_filled_regions() + _old_evac_stats.num_filled_regions(); log_debug(gc)("Allocated %u survivor %u old percent total %1.2f%% (%u%%)", - _survivor_evac_stats.regions_filled(), _old_evac_stats.regions_filled(), - percent_of(total_allocated, num_committed_regions() - total_allocated), + _survivor_evac_stats.num_filled_regions(), _old_evac_stats.num_filled_regions(), + percent_of(num_allocated_regions, num_committed_regions() - num_allocated_regions), G1ReservePercent); policy()->old_gen_alloc_tracker()-> @@ -2902,12 +2913,12 @@ void G1CollectedHeap::free_humongous_region(G1HeapRegion* hr, free_region(hr, free_list); } -void G1CollectedHeap::remove_from_old_gen_sets(const uint old_regions_removed, - const uint humongous_regions_removed) { - if (old_regions_removed > 0 || humongous_regions_removed > 0) { +void G1CollectedHeap::remove_from_old_gen_sets(const uint num_old_regions_removed, + const uint num_humongous_regions_removed) { + if (num_old_regions_removed > 0 || num_humongous_regions_removed > 0) { MutexLocker x(G1OldSets_lock, Mutex::_no_safepoint_check_flag); - _old_set.bulk_remove(old_regions_removed); - _humongous_set.bulk_remove(humongous_regions_removed); + _old_set.bulk_remove(num_old_regions_removed); + _humongous_set.bulk_remove(num_humongous_regions_removed); } } @@ -3149,7 +3160,7 @@ bool G1CollectedHeap::has_more_regions(G1HeapRegionAttr dest) { if (dest.is_old()) { return true; } else { - return num_survivor_regions() < policy()->max_survivor_regions(); + return num_survivor_regions() < policy()->max_num_survivor_regions(); } } @@ -3176,16 +3187,16 @@ G1HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, G1HeapRegio if (type.is_survivor()) { new_alloc_region->set_survivor(); _survivor.add(new_alloc_region); - // The remembered set/group cardset for this region will be installed at the + // The card set group for this region will be installed at the // end of GC. Cannot do that right now because we still need the current young - // gen cardset group. + // gen card set group. // However, register with the attribute table to collect remembered set entries - // immediately as it is the only source for determining the need for remembered + // immediately as it is the definitive source for determining the need for remembered // set tracking during GC. register_new_survivor_region_with_region_attr(new_alloc_region); } else { new_alloc_region->set_old(); - // Update remembered set/cardset. + // Update remembered set state. _policy->remset_tracker()->update_at_allocate(new_alloc_region); // Synchronize with region attribute table. update_region_attr(new_alloc_region); diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 1497c61f59dd..e5945604ffb8 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -469,7 +469,8 @@ class G1CollectedHeap : public CollectedHeap { // at the end of a successful GC). expect_null_mutator_alloc_region // specifies whether the mutator alloc region is expected to be null // or not. - HeapWord* attempt_allocation_at_safepoint(size_t word_size, + HeapWord* attempt_allocation_at_safepoint(uint node_index, + size_t word_size, bool expect_null_mutator_alloc_region); // These methods are the "callbacks" from the G1AllocRegion class. @@ -508,7 +509,7 @@ class G1CollectedHeap : public CollectedHeap { // Callback from VM_G1CollectForAllocation operation. // This function does everything necessary/possible to satisfy a // failed allocation request (including collection, expansion, etc.) - HeapWord* satisfy_failed_allocation(size_t word_size); + HeapWord* satisfy_failed_allocation(uint node_index, size_t word_size); // Internal helpers used during full GC to split it up to // increase readability. bool abort_concurrent_cycle(); @@ -520,7 +521,8 @@ class G1CollectedHeap : public CollectedHeap { void print_heap_after_full_collection(); // Helper method for satisfy_failed_allocation() - HeapWord* satisfy_failed_allocation_helper(size_t word_size, + HeapWord* satisfy_failed_allocation_helper(uint node_index, + size_t word_size, bool do_gc, bool maximal_compaction, bool expect_null_mutator_alloc_region); @@ -529,7 +531,7 @@ class G1CollectedHeap : public CollectedHeap { // to support an allocation of the given "word_size". If // successful, perform the allocation and return the address of the // allocated block, or else null. - HeapWord* expand_and_allocate(size_t word_size); + HeapWord* expand_and_allocate(uint node_index, size_t word_size); void verify_numa_regions(const char* desc); @@ -753,7 +755,8 @@ class G1CollectedHeap : public CollectedHeap { // it has to be read while holding the Heap_lock. Currently, both // methods that call do_collection_pause() release the Heap_lock // before the call, so it's easy to read gc_count_before just before. - HeapWord* do_collection_pause(size_t word_size, + HeapWord* do_collection_pause(uint node_index, + size_t word_size, uint gc_count_before, bool* succeeded, GCCause::Cause gc_cause); @@ -790,13 +793,13 @@ class G1CollectedHeap : public CollectedHeap { G1MonotonicArenaFreePool _card_set_freelist_pool; - // Group cardsets - G1CSetCandidateGroup _young_regions_cset_group; + // Young-region card set group + G1CardSetGroup _young_regions_card_set_group; public: G1CardSetConfiguration* card_set_config() { return &_card_set_config; } - G1CSetCandidateGroup* young_regions_cset_group() { return &_young_regions_cset_group; } + G1CardSetGroup* young_regions_card_set_group() { return &_young_regions_card_set_group; } // After a collection pause, reset eden and the collection set. void clear_eden(); @@ -1034,8 +1037,8 @@ class G1CollectedHeap : public CollectedHeap { bool last_gc_was_periodic() { return _gc_lastcause == GCCause::_g1_periodic_collection; } - void remove_from_old_gen_sets(const uint old_regions_removed, - const uint humongous_regions_removed); + void remove_from_old_gen_sets(const uint num_old_regions_removed, + const uint num_humongous_regions_removed); void prepend_to_freelist(G1FreeRegionList* list); void decrement_summary_bytes(size_t bytes); @@ -1231,9 +1234,9 @@ class G1CollectedHeap : public CollectedHeap { inline uint target_num_eden_regions() const; uint num_eden_regions() const { return _eden.num_regions(); } - uint num_eden_regions(uint node_index) const { return _eden.regions_on_node(node_index); } + uint num_eden_regions(uint node_index) const { return _eden.num_regions_on_node(node_index); } uint num_survivor_regions() const { return _survivor.num_regions(); } - uint num_survivor_regions(uint node_index) const { return _survivor.regions_on_node(node_index); } + uint num_survivor_regions(uint node_index) const { return _survivor.num_regions_on_node(node_index); } size_t eden_regions_used_bytes() const { return _eden.used_bytes(); } size_t survivor_regions_used_bytes() const { return _survivor.used_bytes(); } uint num_young_regions() const { return _eden.num_regions() + _survivor.num_regions(); } diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index efe8fe916591..63b6241402e6 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -36,13 +36,13 @@ #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" -uint G1CollectionSet::num_groups() const { +uint G1CollectionSet::num_selected_groups() const { assert(_inc_build_state == CSetBuildType::Inactive, "must be"); - return _groups.length(); + return _selected_groups.length(); } -uint G1CollectionSet::num_groups_in_increment() const { - return num_groups() - _groups_inc_part_start; +uint G1CollectionSet::num_selected_groups_in_increment() const { + return num_selected_groups() - _selected_groups_inc_part_start; } G1CollectorState* G1CollectionSet::collector_state() const { @@ -60,14 +60,14 @@ G1CollectionSet::G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy) : _regions(nullptr), _max_num_regions(0), _num_regions(0), - _groups(), + _selected_groups(), _num_eden_regions(0), _num_survivor_regions(0), _num_initial_old_regions(0), _optional_groups(), DEBUG_ONLY(_inc_build_state(CSetBuildType::Inactive) COMMA) _regions_inc_part_start(0), - _groups_inc_part_start(0) { + _selected_groups_inc_part_start(0) { } G1CollectionSet::~G1CollectionSet() { @@ -99,7 +99,7 @@ void G1CollectionSet::initialize(uint max_num_regions) { } void G1CollectionSet::abandon() { - _g1h->young_regions_cset_group()->clear(true /* uninstall_cset_group */); + _g1h->young_regions_card_set_group()->clear(true /* uninstall_card_set_group */); clear(); abandon_all_candidates(); @@ -112,8 +112,8 @@ void G1CollectionSet::abandon_all_candidates() { } void G1CollectionSet::prepare_for_scan () { - _g1h->young_regions_cset_group()->card_set()->reset_table_scanner_for_groups(); - _groups.prepare_for_scan(); + _g1h->young_regions_card_set_group()->card_set()->reset_table_scanner_for_groups(); + _selected_groups.prepare_for_scan(); } void G1CollectionSet::add_old_region(G1HeapRegion* hr) { @@ -123,7 +123,7 @@ void G1CollectionSet::add_old_region(G1HeapRegion* hr) { "Precondition, actively building cset or adding optional later on"); assert(hr->is_old(), "the region should be old"); - assert(!hr->rem_set()->has_cset_group(), "Should have already uninstalled group remset"); + assert(!hr->rem_set()->has_card_set_group(), "Should have already uninstalled card set group"); _g1h->register_old_collection_set_region_with_region_attr(hr); @@ -139,13 +139,13 @@ void G1CollectionSet::add_old_region(G1HeapRegion* hr) { void G1CollectionSet::start() { assert(num_regions() == 0, "Collection set must be empty before starting a new collection set."); - assert(num_groups() == 0, "Collection set groups must be empty before starting a new collection set."); + assert(num_selected_groups() == 0, "Card set groups must be empty before starting a new collection set."); assert(_optional_groups.length() == 0, - "Collection set optional groups must be empty before starting a new collection set."); + "Optional card set groups must be empty before starting a new collection set."); continue_incremental_building(); - G1CSetCandidateGroup* young_group = _g1h->young_regions_cset_group(); + G1CardSetGroup* young_group = _g1h->young_regions_card_set_group(); young_group->clear(); } @@ -153,7 +153,7 @@ void G1CollectionSet::continue_incremental_building() { assert(_inc_build_state == CSetBuildType::Inactive, "Precondition"); _regions_inc_part_start = num_regions(); - _groups_inc_part_start = num_groups(); + _selected_groups_inc_part_start = num_selected_groups(); DEBUG_ONLY(_inc_build_state = CSetBuildType::Active;) } @@ -165,7 +165,7 @@ void G1CollectionSet::stop_incremental_building() { void G1CollectionSet::clear() { assert_at_safepoint_on_vm_thread(); _num_regions.store_relaxed(0); - _groups.clear(); + _selected_groups.clear(); assert(_optional_groups.length() == 0, "must be"); } @@ -218,9 +218,8 @@ void G1CollectionSet::add_young_region_common(G1HeapRegion* hr) { assert(hr->is_young(), "invariant"); assert(_inc_build_state == CSetBuildType::Active, "Precondition"); - // Add to remembered set/cset group. _g1h->policy()->remset_tracker()->update_at_allocate(hr); - _g1h->young_regions_cset_group()->add(hr); + _g1h->young_regions_card_set_group()->add(hr); // Synchronize with the region attribute table. _g1h->register_young_region_with_region_attr(hr); @@ -363,16 +362,16 @@ double G1CollectionSet::finalize_young_part(double target_pause_time_ms, G1Survi return remaining_time_ms; } -// The current mechanism for evacuating pinned old regions is as below: -// * pinned regions in the marking collection set candidate list (available during mixed gc) are evacuated like -// pinned young regions to avoid the complexity of dealing with pinned regions that are part of a -// collection group sharing a single cardset. These regions will be partially evacuated and added to the -// retained collection set by the evacuation failure handling mechanism. -// * evacuating pinned regions out of retained collection set candidates would also just take up time -// with no actual space freed in old gen. Better to concentrate on others. So we skip over pinned -// regions in retained collection set candidates. Retained collection set candidates are aged out, ie. -// made to regular old regions without remembered sets after a few attempts to save computation costs -// of keeping them candidates for very long living pinned regions. +// Handling of pinned regions within groups during selection: +// * card set groups in the _from_marking_groups that contain pinned regions are selected as if there +// were no pinned regions in them. +// These pinned regions will simply cause an evacuation failure that is handled as normal. +// * pinned regions within card set groups in the _retained_groups are skipped during selection. +// Since currently card set groups from this list only ever contain one region, trying to evacuate +// them will just waste time (everything but potentially pinned objects were already evacuated). +// These card set groups are aged out, i.e. turned to regular old regions without a card set group +// after a few attempts to select them to save computation costs keeping them in this list for a +// long time. void G1CollectionSet::finalize_old_part(double time_remaining_ms) { Ticks start_time = Ticks::now(); @@ -406,13 +405,13 @@ static void print_finish_message(const char* reason, bool from_marking) { from_marking ? "marking" : "retained", reason); } -void G1CollectionSet::add_optional_group(G1CSetCandidateGroup* group, +void G1CollectionSet::add_optional_group(G1CardSetGroup* group, uint& num_optional_regions, double& predicted_optional_time_ms, double predicted_time_ms) { _optional_groups.append(group); prepare_optional_group(group, num_optional_regions); - num_optional_regions += group->length(); + num_optional_regions += group->num_regions(); predicted_optional_time_ms += predicted_time_ms; } @@ -429,23 +428,23 @@ double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms) double optional_threshold_ms = time_remaining_ms * _policy->optional_prediction_fraction(); - uint min_num_old_cset_regions = _policy->calc_min_old_cset_length(candidates()->last_marking_candidates_length()); - uint max_num_old_cset_regions = MAX2(min_num_old_cset_regions, _policy->calc_max_old_cset_length()); + uint min_num_old_cset_regions = _policy->calc_min_num_old_cset_regions(candidates()->num_last_marking_candidate_regions()); + uint max_num_old_cset_regions = MAX2(min_num_old_cset_regions, _policy->calc_max_num_old_cset_regions()); bool check_time_remaining = _policy->use_adaptive_num_young_regions(); - G1CSetCandidateGroupList* from_marking_groups = &candidates()->from_marking_groups(); + G1CardSetGroupList* from_marking_groups = &candidates()->from_marking_groups(); bool make_first_group_optional = G1ForceOptionalEvacuation; log_debug(gc, ergo, cset)("Start adding marking candidates to collection set. " - "Min %u regions, max %u regions, available %u regions (%u groups), " + "Min %u regions, max %u regions, available %u regions (%u card set groups), " "time remaining %1.2fms, optional threshold %1.2fms", min_num_old_cset_regions, max_num_old_cset_regions, from_marking_groups->num_regions(), from_marking_groups->length(), time_remaining_ms, optional_threshold_ms); - G1CSetCandidateGroupList selected_groups; + G1CardSetGroupList selected_groups; - for (G1CSetCandidateGroup* group : *from_marking_groups) { + for (G1CardSetGroup* group : *from_marking_groups) { if (num_initial_regions + num_optional_regions >= max_num_old_cset_regions) { // Added maximum number of old regions to the CSet. print_finish_message("Maximum number of regions reached", true); @@ -472,12 +471,12 @@ double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms) add_group_to_collection_set(group); selected_groups.append(group); - num_initial_regions += group->length(); + num_initial_regions += group->num_regions(); predicted_initial_time_ms += predicted_time_ms; // Record the number of regions added with no time remaining if (time_remaining_ms == 0.0) { - num_expensive_regions += group->length(); + num_expensive_regions += group->num_regions(); } } else if (!check_time_remaining) { // In the non-auto-tuning case, we'll finish adding regions @@ -496,7 +495,7 @@ double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms) } } - // Remove selected groups from list of candidate groups. + // Remove selected groups from the collection set candidates. if (num_initial_groups > 0) { candidates()->remove(&selected_groups); } @@ -530,7 +529,7 @@ void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms) double predicted_initial_time_ms = 0.0; double predicted_optional_time_ms = 0.0; - uint const min_num_regions = _policy->min_retained_old_cset_length(); + uint const min_num_regions = _policy->min_num_retained_old_cset_regions(); // We want to make sure that on the one hand we process the retained regions asap, // but on the other hand do not take too many of them as optional regions. // So we split the time budget into budget we will unconditionally take into the @@ -539,7 +538,7 @@ void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms) double optional_time_remaining_ms = _policy->max_time_for_retaining(); time_remaining_ms = MIN2(time_remaining_ms, optional_time_remaining_ms); - G1CSetCandidateGroupList* retained_groups = &candidates()->retained_groups(); + G1CardSetGroupList* retained_groups = &candidates()->retained_groups(); log_debug(gc, ergo, cset)("Start adding retained candidates to collection set. " "Min %u regions, available %u regions (%u groups), " @@ -547,17 +546,17 @@ void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms) min_num_regions, retained_groups->num_regions(), retained_groups->length(), time_remaining_ms, optional_time_remaining_ms); - G1CSetCandidateGroupList remove_from_retained; - G1CSetCandidateGroupList groups_to_abandon; + G1CardSetGroupList remove_from_retained; + G1CardSetGroupList groups_to_abandon; - for (G1CSetCandidateGroup* group : *retained_groups) { - assert(group->length() == 1, "Retained groups should have only 1 region"); + for (G1CardSetGroup* group : *retained_groups) { + assert(group->num_regions() == 1, "Retained groups should have only 1 region"); double predicted_time_ms = group->predict_group_total_time_ms(); bool fits_in_remaining_time = predicted_time_ms <= time_remaining_ms; - G1CollectionSetCandidateInfo* ci = group->at(0); // We only have one region in the group. + G1CardSetGroupItem* ci = group->at(0); // We only have one region in the group. G1HeapRegion* r = ci->_r; // If we can't reclaim that region ignore it for now. @@ -580,13 +579,13 @@ void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms) if (num_initial_regions < min_num_regions || fits_in_remaining_time) { predicted_initial_time_ms += predicted_time_ms; if (!fits_in_remaining_time) { - num_expensive_regions += group->length(); + num_expensive_regions += group->num_regions(); } add_group_to_collection_set(group); remove_from_retained.append(group); - num_initial_regions += group->length(); + num_initial_regions += group->num_regions(); } else if (predicted_time_ms <= optional_time_remaining_ms) { // Prepare optional collection region. add_optional_group(group, @@ -614,7 +613,7 @@ void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms) // for the regions in these groups. candidates()->remove(&remove_from_retained); - groups_to_abandon.clear(true /* uninstall_cset_group */); + groups_to_abandon.clear(true /* uninstall_card_set_group */); assert(num_optional_regions >= prev_num_optional_regions, "Sanity"); uint selected_optional_regions = num_optional_regions - prev_num_optional_regions; @@ -632,28 +631,28 @@ double G1CollectionSet::select_candidates_from_optional_groups(double time_remai "Should only be called when there are optional regions"); double total_prediction_ms = 0.0; - G1CSetCandidateGroupList selected; - for (G1CSetCandidateGroup* group : _optional_groups) { + G1CardSetGroupList selected; + for (G1CardSetGroup* group : _optional_groups) { double predicted_time_ms = group->predict_group_total_time_ms(); if (predicted_time_ms > time_remaining_ms) { log_debug(gc, ergo, cset)("Prediction %.3fms for group with %u regions does not fit remaining time: %.3fms.", - predicted_time_ms, group->length(), time_remaining_ms); + predicted_time_ms, group->num_regions(), time_remaining_ms); break; } total_prediction_ms += predicted_time_ms; time_remaining_ms -= predicted_time_ms; - num_regions_selected += group->length(); + num_regions_selected += group->num_regions(); add_group_to_collection_set(group); selected.append(group); } - log_debug(gc, ergo, cset)("Completed with groups, selected %u region in %u groups", + log_debug(gc, ergo, cset)("Selected %u regions in %u card set groups", num_regions_selected, selected.length()); - // Remove selected groups from candidate list. + // Remove selected groups from collection set candidates and optional groups. if (selected.length() > 0) { _optional_groups.remove(&selected); candidates()->remove(&selected); @@ -676,8 +675,8 @@ uint G1CollectionSet::select_optional_groups(double time_remaining_ms) { return num_regions_selected; } -void G1CollectionSet::prepare_optional_group(G1CSetCandidateGroup* gr, uint cur_index) { - for (G1CollectionSetCandidateInfo ci : *gr) { +void G1CollectionSet::prepare_optional_group(G1CardSetGroup* gr, uint cur_index) { + for (G1CardSetGroupItem ci : *gr) { G1HeapRegion* r = ci._r; assert(r->is_old(), "the region should be old"); @@ -688,14 +687,14 @@ void G1CollectionSet::prepare_optional_group(G1CSetCandidateGroup* gr, uint cur_ } } -void G1CollectionSet::add_group_to_collection_set(G1CSetCandidateGroup* gr) { - for (G1CollectionSetCandidateInfo ci : *gr) { +void G1CollectionSet::add_group_to_collection_set(G1CardSetGroup* gr) { + for (G1CardSetGroupItem ci : *gr) { G1HeapRegion* r = ci._r; - r->uninstall_cset_group(); + r->uninstall_card_set_group(); assert(r->rem_set()->is_complete(), "must be"); add_region_to_collection_set(r); } - _groups.append(gr); + _selected_groups.append(gr); } void G1CollectionSet::add_region_to_collection_set(G1HeapRegion* r) { @@ -706,7 +705,7 @@ void G1CollectionSet::add_region_to_collection_set(G1HeapRegion* r) { void G1CollectionSet::finalize_initial_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor) { assert(_regions_inc_part_start == 0, "must be"); - assert(_groups_inc_part_start == 0, "must be"); + assert(_selected_groups_inc_part_start == 0, "must be"); double time_remaining_ms = finalize_young_part(target_pause_time_ms, survivor); finalize_old_part(time_remaining_ms); @@ -738,7 +737,7 @@ void G1CollectionSet::abandon_optional_collection_set(G1ParScanThreadStateSet* p }; _optional_groups.iterate(reset); - // Remove groups from list without deleting the groups or clearing the associated cardsets. + // Remove all card set groups from the list without deleting the groups or clearing the associated card sets. _optional_groups.remove_selected(_optional_groups.length(), _optional_groups.num_regions()); } diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.hpp index eee985f259d9..8ece39559751 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp @@ -42,11 +42,11 @@ class G1HeapRegionClosure; // The collection set. // -// The set of regions and candidate groups that were evacuated during an -// evacuation pause. +// The set of regions with their corresponding card set groups that are evacuated during the +// next evacuation pause. // // At the end of a collection, before freeing it, this set contains all regions -// and collection set groups that were evacuated during this collection: +// with their card set groups that were evacuated during this collection: // // - survivor regions from the last collection (if any) // - eden regions allocated by the mutator @@ -130,7 +130,7 @@ class G1HeapRegionClosure; // || ... after step b6) // |SSS| ... after step 7), with three survivor regions // -// Candidate groups are kept in sync with the contents of the collection set regions. +// Card set groups are kept in sync with the contents of the collection set regions. class G1CollectionSet { G1CollectedHeap* _g1h; G1Policy* _policy; @@ -138,7 +138,7 @@ class G1CollectionSet { // All old gen collection set candidate regions. G1CollectionSetCandidates _candidates; - // The actual collection set as a set of region indices. + // The actual collection set as an array of region indices. // // All regions in _regions below _num_regions are assumed to be part of the // collection set. @@ -146,16 +146,19 @@ class G1CollectionSet { // concurrent readers. This means synchronization using release and acquire // on the writer and reader respectively only are sufficient. // - // This corresponds to the regions referenced by the candidate groups further below. + // These regions correspond to the regions referenced by the card set groups + // in the current collection set. + // + // Keeping the regions in an array allows efficient parallelization of work. uint* _regions; uint _max_num_regions; Atomic _num_regions; - // Old gen groups selected for evacuation. - G1CSetCandidateGroupList _groups; + // Card set groups selected for evacuation. + G1CardSetGroupList _selected_groups; - uint num_groups() const; + uint num_selected_groups() const; uint _num_eden_regions; uint _num_survivor_regions; @@ -164,7 +167,7 @@ class G1CollectionSet { // When doing mixed collections we can add old regions to the collection set, which // will be collected only if there is enough time. We call these optional (old) // groups. Regions are reachable via this list as well. - G1CSetCandidateGroupList _optional_groups; + G1CardSetGroupList _optional_groups; #ifdef ASSERT enum class CSetBuildType { @@ -176,8 +179,8 @@ class G1CollectionSet { #endif // Index into the _regions indicating the start of the current collection set increment. uint _regions_inc_part_start; - // Index into the _groups indicating the start of the current collection set increment. - uint _groups_inc_part_start; + // Index into the _selected_groups indicating the start of the current collection set increment. + uint _selected_groups_inc_part_start; G1CollectorState* collector_state() const; G1GCPhaseTimes* phase_times(); @@ -192,9 +195,9 @@ class G1CollectionSet { void prepare_for_collection(uint num_eden_cset_regions, uint num_survivor_cset_regions); - void prepare_optional_group(G1CSetCandidateGroup* gr, uint cur_index); + void prepare_optional_group(G1CardSetGroup* gr, uint cur_index); - void add_group_to_collection_set(G1CSetCandidateGroup* gr); + void add_group_to_collection_set(G1CardSetGroup* gr); void add_region_to_collection_set(G1HeapRegion* r); @@ -227,7 +230,7 @@ class G1CollectionSet { // Adds the given group to the optional groups list (_optional_groups) // and updates all related bookkeeping. - void add_optional_group(G1CSetCandidateGroup* group, + void add_optional_group(G1CardSetGroup* group, uint& num_optional_regions, double& predicted_optional_time_ms, double predicted_time_ms); @@ -263,9 +266,9 @@ class G1CollectionSet { bool only_contains_young_regions() const { return (num_initial_old_regions() + num_optional_regions()) == 0; } template - inline void merge_cardsets_for_collection_groups(CardOrRangeVisitor& cl, uint worker_id, uint num_workers); + inline void merge_collection_set_card_set_groups(CardOrRangeVisitor& cl, uint worker_id, uint num_workers); - uint num_groups_in_increment() const; + uint num_selected_groups_in_increment() const; // Reset the contents of the collection set. void clear(); diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp index f9ec42b94320..01c237a6444f 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp @@ -30,23 +30,23 @@ #include "gc/g1/g1HeapRegionRemSet.hpp" template -inline void G1CollectionSet::merge_cardsets_for_collection_groups(CardOrRangeVisitor& cl, uint worker_id, uint num_workers) { - uint offset = _groups_inc_part_start; +inline void G1CollectionSet::merge_collection_set_card_set_groups(CardOrRangeVisitor& cl, uint worker_id, uint num_workers) { + uint offset = _selected_groups_inc_part_start; if (offset == 0) { - G1HeapRegionRemSet::iterate_for_merge(_g1h->young_regions_cset_group()->card_set(), cl); + G1HeapRegionRemSet::iterate_for_merge(_g1h->young_regions_card_set_group()->card_set(), cl); } - const uint next_group_increment = num_groups_in_increment(); - if (next_group_increment == 0) { + const uint next_selected_group_increment = num_selected_groups_in_increment(); + if (next_selected_group_increment == 0) { return; } - uint start_pos = (worker_id * next_group_increment) / num_workers; + uint start_pos = (worker_id * next_selected_group_increment) / num_workers; uint cur_pos = start_pos; do { - G1HeapRegionRemSet::iterate_for_merge(_groups.at(offset + cur_pos)->card_set(), cl); + G1HeapRegionRemSet::iterate_for_merge(_selected_groups.at(offset + cur_pos)->card_set(), cl); cur_pos++; - if (cur_pos == next_group_increment) { + if (cur_pos == next_selected_group_increment) { cur_pos = 0; } } while (cur_pos != start_pos); diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp index 84af28726a48..fecf93ad4a96 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp @@ -27,8 +27,8 @@ #include "gc/g1/g1HeapRegionRemSet.inline.hpp" #include "utilities/growableArray.hpp" -G1CSetCandidateGroup::G1CSetCandidateGroup(G1CardSetConfiguration* config, G1MonotonicArenaFreePool* card_set_freelist_pool, uint group_id) : - _candidates(4, mtGCCardSet), +G1CardSetGroup::G1CardSetGroup(G1CardSetConfiguration* config, G1MonotonicArenaFreePool* card_set_freelist_pool, uint group_id) : + _items(4, mtGCCardSet), _card_set_mm(config, card_set_freelist_pool), _card_set(config, &_card_set_mm), _reclaimable_bytes(size_t(0)), @@ -36,67 +36,67 @@ G1CSetCandidateGroup::G1CSetCandidateGroup(G1CardSetConfiguration* config, G1Mon _group_id(group_id) { } -G1CSetCandidateGroup::G1CSetCandidateGroup() : - G1CSetCandidateGroup(G1CollectedHeap::heap()->card_set_config(), G1CollectedHeap::heap()->card_set_freelist_pool(), InvalidId) +G1CardSetGroup::G1CardSetGroup() : + G1CardSetGroup(G1CollectedHeap::heap()->card_set_config(), G1CollectedHeap::heap()->card_set_freelist_pool(), InvalidId) { } -void G1CSetCandidateGroup::add(G1HeapRegion* hr) { +void G1CardSetGroup::add(G1HeapRegion* hr) { precond(hr->is_young() == (_group_id == YoungId)); - if (_candidates.is_empty() && _group_id != YoungId) { + if (_items.is_empty() && _group_id != YoungId) { precond(_group_id == InvalidId); _group_id = FirstNonYoungId + hr->hrm_index(); } - G1CollectionSetCandidateInfo c(hr); - _candidates.append(c); - hr->install_cset_group(this); + G1CardSetGroupItem c(hr); + _items.append(c); + hr->install_card_set_group(this); } -void G1CSetCandidateGroup::calculate_efficiency() { +void G1CardSetGroup::calculate_efficiency() { _reclaimable_bytes = 0; - uint num_candidates = _candidates.length(); - for (uint i = 0; i < num_candidates; i++) { + uint num_items = _items.length(); + for (uint i = 0; i < num_items; i++) { G1HeapRegion* hr = region_at(i); _reclaimable_bytes += hr->reclaimable_bytes(); } _gc_efficiency = _reclaimable_bytes / predict_group_total_time_ms(); } -double G1CSetCandidateGroup::liveness_percent() const { - assert(length() > 0, "must be"); - size_t capacity = length() * G1HeapRegion::GrainBytes; +double G1CardSetGroup::liveness_percent() const { + assert(num_regions() > 0, "must be"); + size_t capacity = num_regions() * G1HeapRegion::GrainBytes; return ((capacity - _reclaimable_bytes) * 100.0) / capacity; } -void G1CSetCandidateGroup::clear(bool uninstall_cset_group) { +void G1CardSetGroup::clear(bool uninstall_card_set_group) { clear_card_set(); - if (uninstall_cset_group) { - for (G1CollectionSetCandidateInfo ci : _candidates) { + if (uninstall_card_set_group) { + for (G1CardSetGroupItem ci : _items) { G1HeapRegion* r = ci._r; - r->uninstall_cset_group(); + r->uninstall_card_set_group(); r->rem_set()->set_state_untracked(); } } - _candidates.clear(); + _items.clear(); if (_group_id != YoungId) { _group_id = InvalidId; } } -void G1CSetCandidateGroup::clear_card_set() { +void G1CardSetGroup::clear_card_set() { _card_set.clear(); } -double G1CSetCandidateGroup::predict_group_total_time_ms() const { +double G1CardSetGroup::predict_group_total_time_ms() const { G1Policy* p = G1CollectedHeap::heap()->policy(); double predicted_copy_time_ms = 0.0; double predict_code_root_scan_time_ms = 0.0; size_t predict_bytes_to_copy = 0.0; - for (G1CollectionSetCandidateInfo ci : _candidates) { + for (G1CardSetGroupItem ci : _items) { G1HeapRegion* r = ci._r; - assert(r->rem_set()->cset_group() == this, "Must be!"); + assert(r->rem_set()->card_set_group() == this, "Must be!"); predict_bytes_to_copy += p->predict_bytes_to_copy(r); predicted_copy_time_ms += p->predict_region_copy_time_ms(r, false /* for_young_only_phase */); @@ -106,16 +106,16 @@ double G1CSetCandidateGroup::predict_group_total_time_ms() const { size_t card_rs_length = _card_set.occupied(); double merge_scan_time_ms = p->predict_merge_scan_time(card_rs_length); - double non_young_other_time_ms = p->predict_non_young_other_time_ms(length()); + double non_young_other_time_ms = p->predict_non_young_other_time_ms(num_regions()); double total_time_ms = merge_scan_time_ms + predict_code_root_scan_time_ms + predicted_copy_time_ms + non_young_other_time_ms; - log_trace(gc, ergo, cset) ("Prediction for group %u (%u regions): total_time %.2fms card_rs_length %zu merge_scan_time %.2fms code_root_scan_time_ms %.2fms evac_time_ms %.2fms other_time %.2fms bytes_to_copy %zu", + log_trace(gc, ergo, cset) ("Prediction for card set group %u (%u regions): total_time %.2fms card_rs_length %zu merge_scan_time %.2fms code_root_scan_time_ms %.2fms evac_time_ms %.2fms other_time %.2fms bytes_to_copy %zu", group_id(), - length(), + num_regions(), total_time_ms, card_rs_length, merge_scan_time_ms, @@ -127,9 +127,9 @@ double G1CSetCandidateGroup::predict_group_total_time_ms() const { return total_time_ms; } -int G1CSetCandidateGroup::compare_gc_efficiency(G1CSetCandidateGroup** gr1, G1CSetCandidateGroup** gr2) { - G1CSetCandidateGroup* group_1 = *gr1; - G1CSetCandidateGroup* group_2 = *gr2; +int G1CardSetGroup::compare_gc_efficiency(G1CardSetGroup** gr1, G1CardSetGroup** gr2) { + G1CardSetGroup* group_1 = *gr1; + G1CardSetGroup* group_2 = *gr2; double gc_eff1 = group_1->gc_efficiency(); double gc_eff2 = group_2->gc_efficiency(); @@ -148,40 +148,40 @@ int G1CSetCandidateGroup::compare_gc_efficiency(G1CSetCandidateGroup** gr1, G1CS return 0; } -G1CSetCandidateGroupList::G1CSetCandidateGroupList() : _groups(8, mtGC), _num_regions(0) { } +G1CardSetGroupList::G1CardSetGroupList() : _groups(8, mtGC), _num_regions(0) { } -void G1CSetCandidateGroupList::append(G1CSetCandidateGroup* group) { - assert(group->length() > 0, "Do not add empty groups"); +void G1CardSetGroupList::append(G1CardSetGroup* group) { + assert(group->num_regions() > 0, "Do not add empty groups"); assert(!_groups.contains(group), "Already added to list"); _groups.append(group); - _num_regions.store_relaxed(num_regions() + group->length()); + _num_regions.store_relaxed(num_regions() + group->num_regions()); } -G1CSetCandidateGroup* G1CSetCandidateGroupList::at(uint index) { +G1CardSetGroup* G1CardSetGroupList::at(uint index) { return _groups.at(index); } -void G1CSetCandidateGroupList::clear(bool uninstall_cset_group) { - for (G1CSetCandidateGroup* gr : _groups) { - gr->clear(uninstall_cset_group); +void G1CardSetGroupList::clear(bool uninstall_card_set_group) { + for (G1CardSetGroup* gr : _groups) { + gr->clear(uninstall_card_set_group); delete gr; } _groups.clear(); _num_regions.store_relaxed(0); } -void G1CSetCandidateGroupList::prepare_for_scan() { - for (G1CSetCandidateGroup* gr : _groups) { +void G1CardSetGroupList::prepare_for_scan() { + for (G1CardSetGroup* gr : _groups) { gr->card_set()->reset_table_scanner_for_groups(); } } -void G1CSetCandidateGroupList::remove_selected(uint count, uint num_regions_to_remove) { +void G1CardSetGroupList::remove_selected(uint count, uint num_regions_to_remove) { _groups.remove_till(count); _num_regions.store_relaxed(num_regions() - num_regions_to_remove); } -void G1CSetCandidateGroupList::remove(G1CSetCandidateGroupList* other) { +void G1CardSetGroupList::remove(G1CardSetGroupList* other) { guarantee((uint)_groups.length() >= other->length(), "Other should be a subset of this list"); if (other->length() == 0) { @@ -189,14 +189,14 @@ void G1CSetCandidateGroupList::remove(G1CSetCandidateGroupList* other) { return; } - // Create a list from scratch, copying over the elements from the candidate + // Create a list from scratch, copying over the elements from the original // list not in the other list. Finally deallocate and overwrite the old list. int new_length = _groups.length() - other->length(); _num_regions.store_relaxed(num_regions() - other->num_regions()); - GrowableArray new_list(new_length, mtGC); + GrowableArray new_list(new_length, mtGC); uint other_idx = 0; - for (G1CSetCandidateGroup* gr : _groups) { + for (G1CardSetGroup* gr : _groups) { if (other_idx == other->length() || gr != other->at(other_idx)) { new_list.append(gr); } else { @@ -209,15 +209,15 @@ void G1CSetCandidateGroupList::remove(G1CSetCandidateGroupList* other) { assert(_groups.length() == new_length, "Must be"); } -void G1CSetCandidateGroupList::sort_by_efficiency() { - _groups.sort(G1CSetCandidateGroup::compare_gc_efficiency); +void G1CardSetGroupList::sort_by_efficiency() { + _groups.sort(G1CardSetGroup::compare_gc_efficiency); } #ifndef PRODUCT -void G1CSetCandidateGroupList::verify() const { - G1CSetCandidateGroup* prev = nullptr; +void G1CardSetGroupList::verify() const { + G1CardSetGroup* prev = nullptr; - for (G1CSetCandidateGroup* gr : _groups) { + for (G1CardSetGroup* gr : _groups) { assert(prev == nullptr || prev->gc_efficiency() >= gr->gc_efficiency(), "Stored gc efficiency must be descending"); prev = gr; @@ -229,8 +229,8 @@ G1CollectionSetCandidates::G1CollectionSetCandidates() : _contains_map(nullptr), _from_marking_groups(), _retained_groups(), - _max_regions(0), - _last_marking_candidates_length(0) + _max_num_regions(0), + _num_last_marking_candidate_regions(0) { } G1CollectionSetCandidates::~G1CollectionSetCandidates() { @@ -244,24 +244,24 @@ bool G1CollectionSetCandidates::is_from_marking(G1HeapRegion* r) const { return _contains_map[r->hrm_index()] == CandidateOrigin::Marking; } -void G1CollectionSetCandidates::initialize(uint max_regions) { +void G1CollectionSetCandidates::initialize(uint max_num_regions) { assert(_contains_map == nullptr, "already initialized"); - _max_regions = max_regions; - _contains_map = NEW_C_HEAP_ARRAY(CandidateOrigin, max_regions, mtGC); + _max_num_regions = max_num_regions; + _contains_map = NEW_C_HEAP_ARRAY(CandidateOrigin, max_num_regions, mtGC); clear(); } void G1CollectionSetCandidates::clear() { - _retained_groups.clear(true /* uninstall_cset_group */); - _from_marking_groups.clear(true /* uninstall_cset_group */); - for (uint i = 0; i < _max_regions; i++) { + _retained_groups.clear(true /* uninstall_card_set_group */); + _from_marking_groups.clear(true /* uninstall_card_set_group */); + for (uint i = 0; i < _max_num_regions; i++) { _contains_map[i] = CandidateOrigin::Invalid; } - _last_marking_candidates_length = 0; + _num_last_marking_candidate_regions = 0; } void G1CollectionSetCandidates::sort_marking_by_efficiency() { - for (G1CSetCandidateGroup* gr : _from_marking_groups) { + for (G1CardSetGroup* gr : _from_marking_groups) { gr->calculate_efficiency(); } _from_marking_groups.sort_by_efficiency(); @@ -281,29 +281,29 @@ void G1CollectionSetCandidates::set_candidates_from_marking(GrowableArrayCHeappolicy(); - // During each Mixed GC, we must collect at least G1Policy::calc_min_old_cset_length regions to meet + // During each Mixed GC, we must collect at least G1Policy::calc_min_num_old_cset_regions regions to meet // the G1MixedGCCountTarget. For the first collection in a Mixed GC cycle, we can add all regions - // required to meet this threshold to the same remset group. We are certain these will be collected in + // required to meet this threshold to the same card set group. We are certain these will be collected in // the same Mixed GC. - uint group_limit = p->calc_min_old_cset_length(num_candidates); + uint group_limit = p->calc_min_num_old_cset_regions(num_candidates); - G1CSetCandidateGroup* current = nullptr; + G1CardSetGroup* current = nullptr; - current = new G1CSetCandidateGroup(); + current = new G1CardSetGroup(); for (uint i = 0; i < num_candidates; i++) { G1HeapRegion* r = candidates->at(i); assert(!contains(r), "must not contain region %u", r->hrm_index()); _contains_map[r->hrm_index()] = CandidateOrigin::Marking; - if (current->length() == group_limit) { - if (group_limit != G1OldCSetGroupSize) { - group_limit = G1OldCSetGroupSize; + if (current->num_regions() == group_limit) { + if (group_limit != G1OldCardSetGroupSize) { + group_limit = G1OldCardSetGroupSize; } _from_marking_groups.append(current); - current = new G1CSetCandidateGroup(); + current = new G1CardSetGroup(); } current->add(r); } @@ -312,32 +312,32 @@ void G1CollectionSetCandidates::set_candidates_from_marking(GrowableArrayCHeaplength() > 0, "Should not have empty groups"); + for (G1CardSetGroup* group : *other) { + assert(group->num_regions() > 0, "Should not have empty groups"); // Regions in the same group have the same source (i.e from_marking or retained). G1HeapRegion* r = group->region_at(0); if (is_from_marking(r)) { @@ -362,7 +362,7 @@ void G1CollectionSetCandidates::add_retained_region_unsorted(G1HeapRegion* r) { assert(!contains(r), "Must not already contain region %u", r->hrm_index()); _contains_map[r->hrm_index()] = CandidateOrigin::Retained; - G1CSetCandidateGroup* gr = new G1CSetCandidateGroup(); + G1CardSetGroup* gr = new G1CardSetGroup(); gr->add(r); gr->calculate_efficiency(); @@ -370,27 +370,27 @@ void G1CollectionSetCandidates::add_retained_region_unsorted(G1HeapRegion* r) { } bool G1CollectionSetCandidates::is_empty() const { - return length() == 0; + return num_regions() == 0; } bool G1CollectionSetCandidates::has_more_marking_candidates() const { - return marking_regions_length() != 0; + return num_marking_regions() != 0; } -uint G1CollectionSetCandidates::marking_regions_length() const { +uint G1CollectionSetCandidates::num_marking_regions() const { return _from_marking_groups.num_regions(); } -uint G1CollectionSetCandidates::retained_regions_length() const { +uint G1CollectionSetCandidates::num_retained_regions() const { return _retained_groups.num_regions(); } #ifndef PRODUCT -void G1CollectionSetCandidates::verify_helper(G1CSetCandidateGroupList* list, uint& from_marking, CandidateOrigin* verify_map) { +void G1CollectionSetCandidates::verify_helper(G1CardSetGroupList* list, uint& from_marking, CandidateOrigin* verify_map) { list->verify(); - for (G1CSetCandidateGroup* gr : *list) { - for (G1CollectionSetCandidateInfo ci : *gr) { + for (G1CardSetGroup* gr : *list) { + for (G1CardSetGroupItem ci : *gr) { G1HeapRegion* r = ci._r; if (is_from_marking(r)) { @@ -409,22 +409,22 @@ void G1CollectionSetCandidates::verify_helper(G1CSetCandidateGroupList* list, ui void G1CollectionSetCandidates::verify() { uint from_marking = 0; - CandidateOrigin* verify_map = NEW_C_HEAP_ARRAY(CandidateOrigin, _max_regions, mtGC); - for (uint i = 0; i < _max_regions; i++) { + CandidateOrigin* verify_map = NEW_C_HEAP_ARRAY(CandidateOrigin, _max_num_regions, mtGC); + for (uint i = 0; i < _max_num_regions; i++) { verify_map[i] = CandidateOrigin::Invalid; } verify_helper(&_from_marking_groups, from_marking, verify_map); - assert(from_marking == marking_regions_length(), "must be"); + assert(from_marking == num_marking_regions(), "must be"); uint from_marking_retained = 0; verify_helper(&_retained_groups, from_marking_retained, verify_map); assert(from_marking_retained == 0, "must be"); - assert(length() >= marking_regions_length(), "must be"); + assert(num_regions() >= num_marking_regions(), "must be"); // Check whether the _contains_map is consistent with the list. - for (uint i = 0; i < _max_regions; i++) { + for (uint i = 0; i < _max_num_regions; i++) { assert(_contains_map[i] == verify_map[i] || (_contains_map[i] != CandidateOrigin::Invalid && verify_map[i] == CandidateOrigin::Verify), "Candidate origin does not match for region %u, is %u but should be %u", @@ -439,7 +439,7 @@ void G1CollectionSetCandidates::verify() { bool G1CollectionSetCandidates::contains(const G1HeapRegion* r) const { const uint index = r->hrm_index(); - assert(index < _max_regions, "must be"); + assert(index < _max_num_regions, "must be"); return _contains_map[index] != CandidateOrigin::Invalid; } diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp index 368022a586c1..93aafd829824 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp @@ -34,16 +34,16 @@ #include "utilities/growableArray.hpp" class G1CollectionSetCandidates; -class G1CSetCandidateGroupList; +class G1CardSetGroupList; class G1HeapRegion; class G1HeapRegionClosure; -struct G1CollectionSetCandidateInfo { +struct G1CardSetGroupItem { G1HeapRegion* _r; uint _num_unreclaimed; // Number of GCs this region has been found unreclaimable. - G1CollectionSetCandidateInfo() : G1CollectionSetCandidateInfo(nullptr) { } - G1CollectionSetCandidateInfo(G1HeapRegion* r) : _r(r), _num_unreclaimed(0) { } + G1CardSetGroupItem() : G1CardSetGroupItem(nullptr) { } + G1CardSetGroupItem(G1HeapRegion* r) : _r(r), _num_unreclaimed(0) { } bool update_num_unreclaimed() { ++_num_unreclaimed; @@ -51,31 +51,31 @@ struct G1CollectionSetCandidateInfo { } }; -using G1CSetCandidateGroupIterator = GrowableArrayIterator; +using G1CardSetGroupIterator = GrowableArrayIterator; -// G1CSetCandidateGroup groups candidate regions that will be selected for evacuation at the same time. -// Grouping occurs both for candidates from marking or regions retained during evacuation failure, but a group -// can not contain regions from both types of regions. +// G1CardSetGroup groups regions that share a single G1CardSet. // -// Humongous objects are excluded from the candidate groups because regions associated with these -// objects are never selected for evacuation. +// Applications of this grouping are +// * all young gen regions +// * candidate regions determined by marking +// * regions retained due to evacuation failure +// * regions covered by humongous start regions // -// All regions in the group share a G1CardSet instance, which tracks remembered set entries for the -// regions in the group. We do not have track to cross-region references for regions that are in the -// same group saving memory. -class G1CSetCandidateGroup : public CHeapObj{ - GrowableArray _candidates; +// The shared card set records remembered set entries for all regions in the group +// as a whole. No references between these regions are recorded. This saves memory, +// but requires reclamation of multi-region card set groups together as a single unit. +class G1CardSetGroup : public CHeapObj{ + GrowableArray _items; G1CardSetMemoryManager _card_set_mm; - // The set of cards in the Java heap + // The set of cards in the Java heap for this card set group. G1CardSet _card_set; size_t _reclaimable_bytes; double _gc_efficiency; - // The _group_id identifies a candidate group in logging and in the - // FromCardCache. A group id must be assigned to at most one cset group - // at any time. + // The _group_id identifies the card set group for logging and for use in the + // FromCardCache. A group id must be unique among all currently used card set groups. uint _group_id; public: @@ -84,15 +84,15 @@ class G1CSetCandidateGroup : public CHeapObj{ static constexpr uint FirstNonYoungId = YoungId + 1; static constexpr uint InvalidId = UINT_MAX; - G1CSetCandidateGroup(); - G1CSetCandidateGroup(G1CardSetConfiguration* config, G1MonotonicArenaFreePool* card_set_freelist_pool, uint group_id); - ~G1CSetCandidateGroup() { - assert(length() == 0, "post condition!"); + G1CardSetGroup(); + G1CardSetGroup(G1CardSetConfiguration* config, G1MonotonicArenaFreePool* card_set_freelist_pool, uint group_id); + ~G1CardSetGroup() { + assert(num_regions() == 0, "post condition!"); } void add(G1HeapRegion* hr); - uint length() const { return (uint)_candidates.length(); } + uint num_regions() const { return (uint)_items.length(); } G1CardSet* card_set() { return &_card_set; } const G1CardSet* card_set() const { return &_card_set; } @@ -100,16 +100,16 @@ class G1CSetCandidateGroup : public CHeapObj{ void calculate_efficiency(); double liveness_percent() const; - // Comparison function to order regions in decreasing GC efficiency order. This - // will cause regions with a lot of live objects and large remembered sets to end + // Comparison function to order card set groups in decreasing GC efficiency order. This + // will cause card set groups with a lot of live objects and large card sets to end // up at the end of the list. - static int compare_gc_efficiency(G1CSetCandidateGroup** gr1, G1CSetCandidateGroup** gr2); + static int compare_gc_efficiency(G1CardSetGroup** gr1, G1CardSetGroup** gr2); double gc_efficiency() const { return _gc_efficiency; } - G1HeapRegion* region_at(uint i) const { return _candidates.at(i)._r; } + G1HeapRegion* region_at(uint i) const { return _items.at(i)._r; } - G1CollectionSetCandidateInfo* at(uint i) { return &_candidates.at(i); } + G1CardSetGroupItem* at(uint i) { return &_items.at(i); } double predict_group_total_time_ms() const; @@ -124,14 +124,14 @@ class G1CSetCandidateGroup : public CHeapObj{ // Clear the group-owned card set. void clear_card_set(); - void clear(bool uninstall_cset_group = false); + void clear(bool uninstall_card_set_group = false); - G1CSetCandidateGroupIterator begin() const { - return _candidates.begin(); + G1CardSetGroupIterator begin() const { + return _items.begin(); } - G1CSetCandidateGroupIterator end() const { - return _candidates.end(); + G1CardSetGroupIterator end() const { + return _items.end(); } uint group_id() const { @@ -140,23 +140,24 @@ class G1CSetCandidateGroup : public CHeapObj{ } }; -using G1CSetCandidateGroupListIterator = GrowableArrayIterator; +using G1CardSetGroupListIterator = GrowableArrayIterator; -class G1CSetCandidateGroupList { - GrowableArray _groups; +class G1CardSetGroupList { + GrowableArray _groups; Atomic _num_regions; public: - G1CSetCandidateGroupList(); - void append(G1CSetCandidateGroup* group); + G1CardSetGroupList(); + void append(G1CardSetGroup* group); - // Delete all groups from the list. The card set cleanup for regions within + // Delete all groups from the list. The card set group uninstall for regions within // the groups could have been done elsewhere (e.g. when adding groups to the - // collection set or to retained regions). The uninstall_cset_group is set to - // true if cleanup needs to happen as we clear the groups from the list. - void clear(bool uninstall_cset_group = false); + // collection set or to the retained card set group list). The uninstall_card_set_group + // parameter should be set to true if the card set groups must be uninstalled from + // the regions, and their state set to Untracked. + void clear(bool uninstall_card_set_group = false); - G1CSetCandidateGroup* at(uint index); + G1CardSetGroup* at(uint index); uint length() const { return (uint)_groups.length(); } @@ -164,28 +165,28 @@ class G1CSetCandidateGroupList { void remove_selected(uint count, uint num_regions); - // Removes any candidate groups stored in this list and also in the other list. The other - // list may only contain candidate groups in this list, sorted by gc efficiency. It need - // not be a prefix of this list. + // Removes any card set groups stored in this and in the other list. The other + // list may only contain card set groups in this list, sorted by gc efficiency. The + // other list need not be a prefix of this list. // E.g. if this list is "A B G H", the other list may be "A G H", but not "F" (not in // this list) or "A H G" (wrong order). - void remove(G1CSetCandidateGroupList* other); + void remove(G1CardSetGroupList* other); void prepare_for_scan(); void sort_by_efficiency(); - GrowableArray* groups() { + GrowableArray* groups() { return &_groups; } void verify() const PRODUCT_RETURN; - G1CSetCandidateGroupListIterator begin() const { + G1CardSetGroupListIterator begin() const { return _groups.begin(); } - G1CSetCandidateGroupListIterator end() const { + G1CardSetGroupListIterator end() const { return _groups.end(); } @@ -193,39 +194,37 @@ class G1CSetCandidateGroupList { void iterate(Func&& f) const; }; -// Tracks all collection set candidates, i.e. region groups that could/should be evacuated soon. +// Tracks collection set candidate regions organized in two card set group lists. Their +// groups are sorted by decreasing gc efficiency. // -// These candidate groups are tracked in two list of region groups, sorted by decreasing -// "gc efficiency". -// -// * from_marking_groups: the set of region groups selected by concurrent marking to be +// * from_marking_groups: the set of card set groups selected by the concurrent cycle to be // evacuated to keep overall heap occupancy stable. // They are guaranteed to be evacuated and cleared out during // the mixed phase. // -// * retained_groups: set of region groups selected for evacuation during evacuation -// failure. +// * retained_groups: contains the card set groups from regions whose evacuation in +// previous garbage collections failed. // Any young collection will try to evacuate them. // class G1CollectionSetCandidates : public CHeapObj { enum class CandidateOrigin : uint8_t { Invalid, - Marking, // This region has been determined as candidate by concurrent marking. + Marking, // This region has been determined as candidate by the concurrent cycle. Retained, // This region has been added because it has been retained after evacuation. Verify // Special value for verification. }; CandidateOrigin* _contains_map; - G1CSetCandidateGroupList _from_marking_groups; // Set of regions selected by concurrent marking. + G1CardSetGroupList _from_marking_groups; // Set of groups selected by the concurrent cycle. // Set of regions retained due to evacuation failure. Groups added to this list // should contain only one region each, making it easier to evacuate retained regions // in any young collection. - G1CSetCandidateGroupList _retained_groups; - uint _max_regions; + G1CardSetGroupList _retained_groups; + uint _max_num_regions; // The number of regions from the last merge of candidates from the marking. - uint _last_marking_candidates_length; + uint _num_last_marking_candidate_regions; bool is_from_marking(G1HeapRegion* r) const; @@ -233,20 +232,19 @@ class G1CollectionSetCandidates : public CHeapObj { G1CollectionSetCandidates(); ~G1CollectionSetCandidates(); - G1CSetCandidateGroupList& from_marking_groups() { return _from_marking_groups; } - G1CSetCandidateGroupList& retained_groups() { return _retained_groups; } + G1CardSetGroupList& from_marking_groups() { return _from_marking_groups; } + G1CardSetGroupList& retained_groups() { return _retained_groups; } - void initialize(uint max_regions); + void initialize(uint max_num_regions); void clear(); - // Merge collection set candidates from marking into the current marking candidates - // (which needs to be empty). + // Merge collection set candidate regions from marking into the current from_marking candidate + // group list (which needs to be empty). void set_candidates_from_marking(GrowableArrayCHeap* selected); - // The most recent length of the list that had been merged last via - // set_candidates_from_marking(). Used for calculating minimum collection set - // regions. - uint last_marking_candidates_length() const { return _last_marking_candidates_length; } + // The number of regions most recently merged using set_candidates_from_marking(). Used for calculating + // minimum collection set regions. + uint num_last_marking_candidate_regions() const { return _num_last_marking_candidate_regions; } void sort_by_efficiency(); @@ -255,9 +253,9 @@ class G1CollectionSetCandidates : public CHeapObj { // Add the given region to the set of retained regions without regards to the // gc efficiency sorting. The retained regions must be re-sorted manually later. void add_retained_region_unsorted(G1HeapRegion* r); - // Remove the given groups from the candidates. All given regions must be part + // Remove the given groups from this list. All given card set groups must be part // of the candidates. - void remove(G1CSetCandidateGroupList* other); + void remove(G1CardSetGroupList* other); bool contains(const G1HeapRegion* r) const; @@ -266,16 +264,16 @@ class G1CollectionSetCandidates : public CHeapObj { bool is_empty() const; bool has_more_marking_candidates() const; - uint marking_regions_length() const; - uint retained_regions_length() const; + uint num_marking_regions() const; + uint num_retained_regions() const; private: - void verify_helper(G1CSetCandidateGroupList* list, uint& from_marking, CandidateOrigin* verify_map) PRODUCT_RETURN; + void verify_helper(G1CardSetGroupList* list, uint& from_marking, CandidateOrigin* verify_map) PRODUCT_RETURN; public: void verify() PRODUCT_RETURN; - uint length() const { return marking_regions_length() + retained_regions_length(); } + uint num_regions() const { return num_marking_regions() + num_retained_regions(); } template void iterate_regions(Func&& f) const; diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.inline.hpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.inline.hpp index b5080fee51c2..fdbabf30338b 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,9 +30,9 @@ #include "utilities/growableArray.hpp" template -void G1CSetCandidateGroupList::iterate(Func&& f) const { - for (G1CSetCandidateGroup* group : _groups) { - for (G1CollectionSetCandidateInfo ci : *group) { +void G1CardSetGroupList::iterate(Func&& f) const { + for (G1CardSetGroup* group : _groups) { + for (G1CardSetGroupItem ci : *group) { G1HeapRegion* r = ci._r; f(r); } diff --git a/src/hotspot/share/gc/g1/g1CommittedRegionMap.cpp b/src/hotspot/share/gc/g1/g1CommittedRegionMap.cpp index 9e5b2fda5c98..c0304ec9339b 100644 --- a/src/hotspot/share/gc/g1/g1CommittedRegionMap.cpp +++ b/src/hotspot/share/gc/g1/g1CommittedRegionMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,29 +38,29 @@ G1HeapRegionRange::G1HeapRegionRange(uint start, uint end) : G1CommittedRegionMap::G1CommittedRegionMap() : _active(mtGC), _inactive(mtGC), - _num_active(0), - _num_inactive(0) { } + _num_active_regions(0), + _num_inactive_regions(0) { } void G1CommittedRegionMap::initialize(uint num_regions) { _active.initialize(num_regions); _inactive.initialize(num_regions); } -uint G1CommittedRegionMap::num_active() const { - return _num_active; +uint G1CommittedRegionMap::num_active_regions() const { + return _num_active_regions; } -uint G1CommittedRegionMap::num_inactive() const { - return _num_inactive; +uint G1CommittedRegionMap::num_inactive_regions() const { + return _num_inactive_regions; } -uint G1CommittedRegionMap::max_length() const { +uint G1CommittedRegionMap::max_num_regions() const { return (uint) _active.size(); } void G1CommittedRegionMap::activate(uint start, uint end) { - verify_active_count(start, end, 0); - verify_inactive_count(start, end, 0); + verify_num_active_regions(start, end, 0); + verify_num_inactive_regions(start, end, 0); log_debug(gc, heap, region)("Activate regions [%u, %u)", start, end); @@ -68,8 +68,8 @@ void G1CommittedRegionMap::activate(uint start, uint end) { } void G1CommittedRegionMap::reactivate(uint start, uint end) { - verify_active_count(start, end, 0); - verify_inactive_count(start, end, (end - start)); + verify_num_active_regions(start, end, 0); + verify_num_inactive_regions(start, end, (end - start)); log_debug(gc, heap, region)("Reactivate regions [%u, %u)", start, end); @@ -78,8 +78,8 @@ void G1CommittedRegionMap::reactivate(uint start, uint end) { } void G1CommittedRegionMap::deactivate(uint start, uint end) { - verify_active_count(start, end, (end - start)); - verify_inactive_count(start, end, 0); + verify_num_active_regions(start, end, (end - start)); + verify_num_inactive_regions(start, end, 0); log_debug(gc, heap, region)("Deactivate regions [%u, %u)", start, end); @@ -88,8 +88,8 @@ void G1CommittedRegionMap::deactivate(uint start, uint end) { } void G1CommittedRegionMap::uncommit(uint start, uint end) { - verify_active_count(start, end, 0); - verify_inactive_count(start, end, (end-start)); + verify_num_active_regions(start, end, 0); + verify_num_inactive_regions(start, end, (end-start)); log_debug(gc, heap, region)("Uncommit regions [%u, %u)", start, end); @@ -99,9 +99,9 @@ void G1CommittedRegionMap::uncommit(uint start, uint end) { G1HeapRegionRange G1CommittedRegionMap::next_active_range(uint offset) const { // Find first active index from offset. uint start = (uint) _active.find_first_set_bit(offset); - if (start == max_length()) { + if (start == max_num_regions()) { // Early out when no active regions are found. - return G1HeapRegionRange(max_length(), max_length()); + return G1HeapRegionRange(max_num_regions(), max_num_regions()); } uint end = (uint) _active.find_first_clear_bit(start); @@ -116,9 +116,9 @@ G1HeapRegionRange G1CommittedRegionMap::next_committable_range(uint offset) cons // Find first free region from offset. uint start = (uint) _active.find_first_clear_bit(offset); - if (start == max_length()) { + if (start == max_num_regions()) { // Early out when no free regions are found. - return G1HeapRegionRange(max_length(), max_length()); + return G1HeapRegionRange(max_num_regions(), max_num_regions()); } uint end = (uint) _active.find_first_set_bit(start); @@ -131,9 +131,9 @@ G1HeapRegionRange G1CommittedRegionMap::next_inactive_range(uint offset) const { // Find first inactive region from offset. uint start = (uint) _inactive.find_first_set_bit(offset); - if (start == max_length()) { + if (start == max_num_regions()) { // Early when no inactive regions are found. - return G1HeapRegionRange(max_length(), max_length()); + return G1HeapRegionRange(max_num_regions(), max_num_regions()); } uint end = (uint) _inactive.find_first_clear_bit(start); @@ -146,28 +146,28 @@ void G1CommittedRegionMap::active_set_range(uint start, uint end) { guarantee_mt_safety_active(); _active.par_set_range(start, end, BitMap::unknown_range); - _num_active += (end - start); + _num_active_regions += (end - start); } void G1CommittedRegionMap::active_clear_range(uint start, uint end) { guarantee_mt_safety_active(); _active.par_clear_range(start, end, BitMap::unknown_range); - _num_active -= (end - start); + _num_active_regions -= (end - start); } void G1CommittedRegionMap::inactive_set_range(uint start, uint end) { guarantee_mt_safety_inactive(); _inactive.par_set_range(start, end, BitMap::unknown_range); - _num_inactive += (end - start); + _num_inactive_regions += (end - start); } void G1CommittedRegionMap::inactive_clear_range(uint start, uint end) { guarantee_mt_safety_inactive(); _inactive.par_clear_range(start, end, BitMap::unknown_range); - _num_inactive -= (end - start); + _num_inactive_regions -= (end - start); } void G1CommittedRegionMap::guarantee_mt_safety_active() const { @@ -214,20 +214,20 @@ void G1CommittedRegionMap::guarantee_mt_safety_inactive() const { #ifdef ASSERT void G1CommittedRegionMap::verify_active_range(uint start, uint end) const { - assert(active(start), "First region (%u) is not active", start); - assert(active(end - 1), "Last region (%u) is not active", end - 1); - assert(end == _active.size() || !active(end), "Region (%u) is active but not included in range", end); + assert(is_active(start), "First region (%u) is not active", start); + assert(is_active(end - 1), "Last region (%u) is not active", end - 1); + assert(end == _active.size() || !is_active(end), "Region (%u) is active but not included in range", end); } void G1CommittedRegionMap::verify_inactive_range(uint start, uint end) const { - assert(inactive(start), "First region (%u) is not inactive", start); - assert(inactive(end - 1), "Last region (%u) in range is not inactive", end - 1); - assert(end == _inactive.size() || !inactive(end), "Region (%u) is inactive but not included in range", end); + assert(is_inactive(start), "First region (%u) is not inactive", start); + assert(is_inactive(end - 1), "Last region (%u) in range is not inactive", end - 1); + assert(end == _inactive.size() || !is_inactive(end), "Region (%u) is inactive but not included in range", end); } void G1CommittedRegionMap::verify_free_range(uint start, uint end) const { - assert(!active(start), "First region (%u) is active", start); - assert(!active(end - 1), "Last region (%u) in range is active", end - 1); + assert(!is_active(start), "First region (%u) is active", start); + assert(!is_active(end - 1), "Last region (%u) in range is active", end - 1); } void G1CommittedRegionMap::verify_no_inactive_regons() const { @@ -235,12 +235,12 @@ void G1CommittedRegionMap::verify_no_inactive_regons() const { assert(first_inactive == _inactive.size(), "Should be no inactive regions, but was at index: %zu", first_inactive); } -void G1CommittedRegionMap::verify_active_count(uint start, uint end, uint expected) const { +void G1CommittedRegionMap::verify_num_active_regions(uint start, uint end, uint expected) const { uint found = (uint) _active.count_one_bits(start, end); assert(found == expected, "Unexpected number of active regions, found: %u, expected: %u", found, expected); } -void G1CommittedRegionMap::verify_inactive_count(uint start, uint end, uint expected) const { +void G1CommittedRegionMap::verify_num_inactive_regions(uint start, uint end, uint expected) const { uint found = (uint) _inactive.count_one_bits(start, end); assert(found == expected, "Unexpected number of inactive regions, found: %u, expected: %u", found, expected); } diff --git a/src/hotspot/share/gc/g1/g1CommittedRegionMap.hpp b/src/hotspot/share/gc/g1/g1CommittedRegionMap.hpp index 595a6f7f9c9a..7df886160072 100644 --- a/src/hotspot/share/gc/g1/g1CommittedRegionMap.hpp +++ b/src/hotspot/share/gc/g1/g1CommittedRegionMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ class G1HeapRegionRange : public StackObj { uint start() const { return _start; } uint end() const { return _end; } - uint length() const { return _end - _start; } + uint num_regions() const { return _end - _start; } }; // The G1CommittedRegionMap keeps track of which regions are currently committed. @@ -64,12 +64,12 @@ class G1CommittedRegionMap : public CHeapObj { // The union of these two bitmaps are the regions that are currently committed. // The number of regions active and available for use. - uint _num_active; + uint _num_active_regions; // The number of regions ready to be uncommitted. - uint _num_inactive; + uint _num_inactive_regions; - uint max_length() const; + uint max_num_regions() const; // Helpers to mark and do accounting for the bitmaps. Depending on when called // these helpers require to own different locks. See guarantee_mt_safety_* for @@ -83,13 +83,13 @@ class G1CommittedRegionMap : public CHeapObj { G1CommittedRegionMap(); void initialize(uint num_regions); - uint num_active() const; - uint num_inactive() const; + uint num_active_regions() const; + uint num_inactive_regions() const; // Check if a region is marked active. - inline bool active(uint index) const; + inline bool is_active(uint index) const; // Check if a region is marked inactive. - inline bool inactive(uint index) const; + inline bool is_inactive(uint index) const; // Mark a range of regions as active. void activate(uint start, uint end); @@ -117,8 +117,8 @@ class G1CommittedRegionMap : public CHeapObj { void verify_free_range(uint start, uint end) const NOT_DEBUG_RETURN; void verify_inactive_range(uint start, uint end) const NOT_DEBUG_RETURN; void verify_no_inactive_regons() const NOT_DEBUG_RETURN; - void verify_active_count(uint start, uint end, uint expected) const NOT_DEBUG_RETURN; - void verify_inactive_count(uint start, uint end, uint expected) const NOT_DEBUG_RETURN; + void verify_num_active_regions(uint start, uint end, uint expected) const NOT_DEBUG_RETURN; + void verify_num_inactive_regions(uint start, uint end, uint expected) const NOT_DEBUG_RETURN; }; #endif // SHARE_GC_G1_G1COMMITTEDREGIONMAP_HPP diff --git a/src/hotspot/share/gc/g1/g1CommittedRegionMap.inline.hpp b/src/hotspot/share/gc/g1/g1CommittedRegionMap.inline.hpp index d5e3eb0679f0..6f3611443c08 100644 --- a/src/hotspot/share/gc/g1/g1CommittedRegionMap.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CommittedRegionMap.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,11 +29,11 @@ #include "utilities/bitMap.inline.hpp" -inline bool G1CommittedRegionMap::active(uint index) const { +inline bool G1CommittedRegionMap::is_active(uint index) const { return _active.par_at(index); } -inline bool G1CommittedRegionMap::inactive(uint index) const { +inline bool G1CommittedRegionMap::is_inactive(uint index) const { return _inactive.at(index); } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index ccac7e01db07..a895c976075b 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -688,8 +688,8 @@ void G1ConcurrentMark::set_concurrency(uint active_tasks) { // Need to update the three data structures below according to the // number of active threads for this phase. _terminator.reset_for_reuse(active_tasks); - _first_overflow_barrier_sync.set_n_workers(active_tasks); - _second_overflow_barrier_sync.set_n_workers(active_tasks); + _first_overflow_barrier_sync.set_num_workers(active_tasks); + _second_overflow_barrier_sync.set_num_workers(active_tasks); } void G1ConcurrentMark::set_concurrency_and_phase(uint active_tasks, bool concurrent) { @@ -838,10 +838,10 @@ class G1ClearBitMapTask : public WorkerTask { bool _suspendible; // If the task is suspendible, workers must join the STS. public: - G1ClearBitMapTask(G1ConcurrentMark* cm, uint n_workers, bool suspendible) : + G1ClearBitMapTask(G1ConcurrentMark* cm, uint num_workers, bool suspendible) : WorkerTask("G1 Clear Bitmap"), _cl(cm, suspendible), - _hr_claimer(n_workers), + _hr_claimer(num_workers), _suspendible(suspendible) { } @@ -941,11 +941,11 @@ class G1PreConcurrentStartTask::NoteStartOfMarkTask : public G1AbstractSubTask { // The work done per region is very small, therefore we choose this magic number to cap the number // of threads used when there are few regions. const double regions_per_thread = 1000; - return _claimer.n_regions() / regions_per_thread; + return _claimer.num_regions() / regions_per_thread; } void set_max_workers(uint max_workers) override { - _claimer.set_n_workers(max_workers); + _claimer.set_num_workers(max_workers); } void do_work(uint worker_id) override { @@ -1947,31 +1947,29 @@ G1HeapRegion* G1ConcurrentMark::claim_region(uint worker_id) { } #ifndef PRODUCT -class VerifyNoCSetOops { +class G1VerifyNoCollectionSetOops { G1CollectedHeap* _g1h; - const char* _phase; - int _info; + const char* _location; + int _index; public: - VerifyNoCSetOops(const char* phase, int info = -1) : + G1VerifyNoCollectionSetOops(const char* location, int index = -1) : _g1h(G1CollectedHeap::heap()), - _phase(phase), - _info(info) + _location(location), + _index(index) { } void operator()(G1TaskQueueEntry task_entry) const { - if (task_entry.is_partial_array_state()) { - oop obj = task_entry.to_partial_array_state()->source(); - guarantee(_g1h->is_in_reserved(obj), "Partial Array " PTR_FORMAT " must be in heap.", p2i(obj)); - return; - } - guarantee(oopDesc::is_oop(task_entry.to_oop()), - "Non-oop " PTR_FORMAT ", phase: %s, info: %d", - p2i(task_entry.to_oop()), _phase, _info); - G1HeapRegion* r = _g1h->heap_region_containing(task_entry.to_oop()); + oop obj = task_entry.is_partial_array_state() + ? task_entry.to_partial_array_state()->source() + : task_entry.to_oop(); + guarantee(oopDesc::is_oop(obj), + "Non-oop " PTR_FORMAT ", location: %s, index: %d", + p2i(obj), _location, _index); + G1HeapRegion* r = _g1h->heap_region_containing(obj); guarantee(!(r->in_collection_set() || r->has_index_in_opt_cset()), "obj " PTR_FORMAT " from %s (%d) in region %u in (optional) collection set", - p2i(task_entry.to_oop()), _phase, _info, r->hrm_index()); + p2i(obj), _location, _index, r->hrm_index()); } }; @@ -1983,15 +1981,17 @@ void G1ConcurrentMark::verify_no_collection_set_oops() { } // Verify entries on the global mark stack - _global_mark_stack.iterate(VerifyNoCSetOops("Stack")); + _global_mark_stack.iterate(G1VerifyNoCollectionSetOops("Stack")); // Verify entries on the task queues for (uint i = 0; i < _max_num_tasks; ++i) { G1CMTaskQueue* queue = _task_queues->queue(i); - queue->iterate(VerifyNoCSetOops("Queue", i)); + queue->iterate(G1VerifyNoCollectionSetOops("Queue", i)); } - // Verify the global finger + // Verify the global finger. Unlike the task fingers, it only moves in whole + // regions as tasks claim them, so it must be at a region bottom. That region + // may be in the collection set: nothing in it has been scanned yet. HeapWord* global_finger = finger(); if (global_finger != nullptr && global_finger < _heap.end()) { // Since we always iterate over all regions, we might get a null G1HeapRegion @@ -2008,10 +2008,11 @@ void G1ConcurrentMark::verify_no_collection_set_oops() { G1CMTask* task = _tasks[i]; HeapWord* task_finger = task->finger(); if (task_finger != nullptr && task_finger < _heap.end()) { - // See above note on the global finger verification. + // Since we always iterate over all regions, we might get a null G1HeapRegion + // here. G1HeapRegion* r = _g1h->heap_region_containing_or_null(task_finger); guarantee(r == nullptr || task_finger == r->bottom() || - !r->in_collection_set() || !r->has_index_in_opt_cset(), + !(r->in_collection_set() || r->has_index_in_opt_cset()), "task finger: " PTR_FORMAT " region: " HR_FORMAT, p2i(task_finger), HR_FORMAT_PARAMS(r)); } @@ -3157,9 +3158,9 @@ bool G1PrintRegionLivenessInfoClosure::do_heap_region(G1HeapRegion* r) { size_t remset_bytes = r->rem_set()->mem_size(); size_t code_roots_bytes = r->rem_set()->code_roots_mem_size(); const char* remset_type = r->rem_set()->get_short_state_str(); - uint cset_group_id = r->rem_set()->has_cset_group() - ? r->rem_set()->cset_group_id() - : G1CSetCandidateGroup::NoGroupId; + uint card_set_group_id = r->rem_set()->has_card_set_group() + ? r->rem_set()->card_set_group_id() + : G1CardSetGroup::NoGroupId; _total_used_bytes += used_bytes; _total_capacity_bytes += capacity_bytes; @@ -3179,7 +3180,7 @@ bool G1PrintRegionLivenessInfoClosure::do_heap_region(G1HeapRegion* r) { type, p2i(bottom), p2i(end), used_bytes, live_bytes, remset_type, code_roots_bytes, - cset_group_id); + card_set_group_id); return false; } @@ -3194,7 +3195,7 @@ G1PrintRegionLivenessInfoClosure::~G1PrintRegionLivenessInfoClosure() { // add static memory usages to remembered set sizes _total_remset_bytes += G1HeapRegionRemSet::static_mem_size(); - log_cset_candidate_groups(); + log_card_set_groups(); // Print the footer of the output. log_trace(gc, liveness)(G1PPRL_LINE_PREFIX); @@ -3214,7 +3215,7 @@ G1PrintRegionLivenessInfoClosure::~G1PrintRegionLivenessInfoClosure() { bytes_to_mb(_total_code_roots_bytes)); } -void G1PrintRegionLivenessInfoClosure::log_cset_candidate_group_add_total(G1CSetCandidateGroup* group, const char* type) { +void G1PrintRegionLivenessInfoClosure::log_card_set_group_add_total(G1CardSetGroup* group, const char* type) { log_trace(gc, liveness)(G1PPRL_LINE_PREFIX G1PPRL_GID_FORMAT G1PPRL_LEN_FORMAT @@ -3223,23 +3224,23 @@ void G1PrintRegionLivenessInfoClosure::log_cset_candidate_group_add_total(G1CSet G1PPRL_BYTE_FORMAT G1PPRL_TYPE_H_FORMAT, group->group_id(), - group->length(), - group->length() > 0 ? group->gc_efficiency() : 0.0, - group->length() > 0 ? group->liveness_percent() : 0.0, + group->num_regions(), + group->num_regions() > 0 ? group->gc_efficiency() : 0.0, + group->num_regions() > 0 ? group->liveness_percent() : 0.0, group->card_set()->mem_size(), type); _total_remset_bytes += group->card_set()->mem_size(); } -void G1PrintRegionLivenessInfoClosure::log_cset_candidate_grouplist(G1CSetCandidateGroupList& gl, const char* type) { - for (G1CSetCandidateGroup* group : gl) { - log_cset_candidate_group_add_total(group, type); +void G1PrintRegionLivenessInfoClosure::log_card_set_group_list(G1CardSetGroupList& gl, const char* type) { + for (G1CardSetGroup* group : gl) { + log_card_set_group_add_total(group, type); } } -void G1PrintRegionLivenessInfoClosure::log_cset_candidate_groups() { +void G1PrintRegionLivenessInfoClosure::log_card_set_groups() { log_trace(gc, liveness)(G1PPRL_LINE_PREFIX); - log_trace(gc, liveness)(G1PPRL_LINE_PREFIX" Collection Set Candidate Groups"); + log_trace(gc, liveness)(G1PPRL_LINE_PREFIX " Card Set Groups"); log_trace(gc, liveness)(G1PPRL_LINE_PREFIX " Types: Y=Young, M=From Marking Regions, R=Retained Regions"); log_trace(gc, liveness)(G1PPRL_LINE_PREFIX G1PPRL_GID_H_FORMAT @@ -3248,7 +3249,7 @@ void G1PrintRegionLivenessInfoClosure::log_cset_candidate_groups() { G1PPRL_BYTE_H_FORMAT G1PPRL_BYTE_H_FORMAT G1PPRL_TYPE_H_FORMAT, - "groud-id", "num-regions", + "group-id", "num-regions", "gc-eff", "liveness", "remset", "type"); @@ -3265,9 +3266,9 @@ void G1PrintRegionLivenessInfoClosure::log_cset_candidate_groups() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - log_cset_candidate_group_add_total(g1h->young_regions_cset_group(), "Y"); + log_card_set_group_add_total(g1h->young_regions_card_set_group(), "Y"); G1CollectionSetCandidates* candidates = g1h->policy()->candidates(); - log_cset_candidate_grouplist(candidates->from_marking_groups(), "M"); - log_cset_candidate_grouplist(candidates->retained_groups(), "R"); + log_card_set_group_list(candidates->from_marking_groups(), "M"); + log_card_set_group_list(candidates->retained_groups(), "R"); } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index ca36b48de5b4..18183044f655 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -45,8 +45,8 @@ class ConcurrentGCTimer; class G1CollectedHeap; -class G1CSetCandidateGroup; -class G1CSetCandidateGroupList; +class G1CardSetGroup; +class G1CardSetGroupList; class G1ConcurrentMark; class G1ConcurrentMarkThread; class G1CMOopClosure; @@ -715,9 +715,11 @@ class G1ConcurrentMark : public CHeapObj { // safepoint. void clear_bitmap_for_region(G1HeapRegion* hr); - // Verify that there are no collection set oops on the stacks (taskqueues / - // global mark stack) and fingers (global / per-task). - // If marking is not in progress, it's a no-op. + // Verify that no entry on the global mark stack or the task queues refers to + // an object in the (optional) collection set, that the global finger is at a + // region bottom, and that no task finger points into a region in the + // (optional) collection set. + // A no-op unless marking or remembered set rebuilding is in progress. void verify_no_collection_set_oops() PRODUCT_RETURN; inline bool do_yield_check(); @@ -1026,9 +1028,9 @@ class G1PrintRegionLivenessInfoClosure : public G1HeapRegionClosure { return (double) val / (double) M; } - void log_cset_candidate_group_add_total(G1CSetCandidateGroup* gr, const char* type); - void log_cset_candidate_grouplist(G1CSetCandidateGroupList& gl, const char* type); - void log_cset_candidate_groups(); + void log_card_set_group_add_total(G1CardSetGroup* gr, const char* type); + void log_card_set_group_list(G1CardSetGroupList& gl, const char* type); + void log_card_set_groups(); public: // The header and footer are printed in the constructor and diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkRemarkTasks.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkRemarkTasks.cpp index 61ec542c71f0..017c07bd32bf 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkRemarkTasks.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkRemarkTasks.cpp @@ -190,17 +190,17 @@ void G1UpdateRegionLivenessAndSelectForRebuildTask::prune(GrowableArrayCHeaplength(); - uint min_old_cset_length = p->calc_min_old_cset_length(num_candidates); + uint min_num_old_cset_regions = p->calc_min_num_old_cset_regions(num_candidates); uint num_pruned = 0; size_t wasted_bytes = 0; - if (min_old_cset_length >= num_candidates) { + if (min_num_old_cset_regions >= num_candidates) { // We take all of the candidate regions to provide some forward progress. return; } size_t allowed_waste = p->allowed_waste_in_collection_set(); - uint max_to_prune = num_candidates - min_old_cset_length; + uint max_to_prune = num_candidates - min_num_old_cset_regions; while (true) { G1HeapRegion* r = old_regions->at(num_candidates - num_pruned - 1); @@ -209,7 +209,7 @@ void G1UpdateRegionLivenessAndSelectForRebuildTask::prune(GrowableArrayCHeap allowed_waste) { break; } - assert(!r->rem_set()->has_cset_group(), "must not have a cset group"); + assert(!r->rem_set()->has_card_set_group(), "must not have a card set group"); r->rem_set()->set_state_untracked(); wasted_bytes += reclaimable; diff --git a/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp b/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp index 03c20346eb35..42c4f47bc93e 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp +++ b/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp @@ -32,26 +32,26 @@ #include "utilities/bitMap.inline.hpp" G1EvacFailureRegions::G1EvacFailureRegions() : - _regions_evac_failed(mtGC), + _evac_failed_regions_map(mtGC), _regions_pinned(mtGC), _regions_alloc_failed(mtGC), _evac_failed_regions(nullptr), - _num_regions_evac_failed(0) { } + _num_evac_failed_regions(0) { } G1EvacFailureRegions::~G1EvacFailureRegions() { assert(_evac_failed_regions == nullptr, "not cleaned up"); } -void G1EvacFailureRegions::pre_collection(uint max_regions) { - _num_regions_evac_failed.store_relaxed(0u); - _regions_evac_failed.resize(max_regions); - _regions_pinned.resize(max_regions); - _regions_alloc_failed.resize(max_regions); - _evac_failed_regions = NEW_C_HEAP_ARRAY(uint, max_regions, mtGC); +void G1EvacFailureRegions::pre_collection(uint max_num_regions) { + _num_evac_failed_regions.store_relaxed(0u); + _evac_failed_regions_map.resize(max_num_regions); + _regions_pinned.resize(max_num_regions); + _regions_alloc_failed.resize(max_num_regions); + _evac_failed_regions = NEW_C_HEAP_ARRAY(uint, max_num_regions, mtGC); } void G1EvacFailureRegions::post_collection() { - _regions_evac_failed.resize(0); + _evac_failed_regions_map.resize(0); _regions_pinned.resize(0); _regions_alloc_failed.resize(0); @@ -60,7 +60,7 @@ void G1EvacFailureRegions::post_collection() { } bool G1EvacFailureRegions::contains(uint region_idx) const { - return _regions_evac_failed.par_at(region_idx, memory_order_relaxed); + return _evac_failed_regions_map.par_at(region_idx, memory_order_relaxed); } void G1EvacFailureRegions::par_iterate(G1HeapRegionClosure* closure, @@ -69,6 +69,6 @@ void G1EvacFailureRegions::par_iterate(G1HeapRegionClosure* closure, G1CollectedHeap::heap()->par_iterate_regions_array(closure, hrclaimer, _evac_failed_regions, - num_regions_evac_failed(), + num_evac_failed_regions(), worker_id); } diff --git a/src/hotspot/share/gc/g1/g1EvacFailureRegions.hpp b/src/hotspot/share/gc/g1/g1EvacFailureRegions.hpp index f752a3f8ab78..2852ef372a33 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailureRegions.hpp +++ b/src/hotspot/share/gc/g1/g1EvacFailureRegions.hpp @@ -37,17 +37,18 @@ class G1HeapRegionClosure; // evacuation failure. // An evacuation failure may occur due to pinning or due to allocation failure // (not enough to-space). For every such occurrence the class records region -// information to speed up iteration of these regions in various gc phases. +// information to speed up iteration of these regions in various GC phases. // // Pinned regions may experience an allocation failure at the same time as G1 -// tries to evacuate anything but objects that are possible to be pinned. So +// tries to evacuate anything but objects that are possible to be pinned. // -// _num_regions_pinned + _num_regions_alloc_failed >= _num_regions_evac_failed +// So it is possible that the number of pinned regions plus the number of allocation +// failed regions is larger than the number of evacuation failed regions. // class G1EvacFailureRegions { // Records for every region on the heap whether the region has experienced an // evacuation failure. - CHeapBitMap _regions_evac_failed; + CHeapBitMap _evac_failed_regions_map; // Records for every region on the heap whether the evacuation failure cause // has been allocation failure or region pinning. CHeapBitMap _regions_pinned; @@ -55,19 +56,19 @@ class G1EvacFailureRegions { // Evacuation failed regions (indexes) in the current collection. uint* _evac_failed_regions; // Number of regions evacuation failed in the current collection. - Atomic _num_regions_evac_failed; + Atomic _num_evac_failed_regions; public: G1EvacFailureRegions(); ~G1EvacFailureRegions(); uint get_region_idx(uint idx) const { - assert(idx < _num_regions_evac_failed.load_relaxed(), "precondition"); + assert(idx < _num_evac_failed_regions.load_relaxed(), "precondition"); return _evac_failed_regions[idx]; } // Sets up the bitmap and failed regions array for addition. - void pre_collection(uint max_regions); + void pre_collection(uint max_num_regions); // Drops memory for internal data structures, but keep counts. void post_collection(); @@ -79,11 +80,11 @@ class G1EvacFailureRegions { // Return a G1AbstractSubTask which does necessary preparation for evacuation failed regions G1AbstractSubTask* create_prepare_regions_task(); - inline uint num_regions_evac_failed() const; + inline uint num_evac_failed_regions() const; - inline bool has_regions_evac_failed() const; - inline bool has_regions_evac_pinned() const; - inline bool has_regions_alloc_failed() const; + inline bool has_evac_failed_regions() const; + inline bool has_evac_pinned_regions() const; + inline bool has_alloc_failed_regions() const; // Record that the garbage collection encountered an evacuation failure in the // given region. Returns whether this has been the first occurrence of an evacuation diff --git a/src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp b/src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp index fb456475b56b..78e5d049bbcf 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp +++ b/src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp @@ -31,22 +31,22 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" -uint G1EvacFailureRegions::num_regions_evac_failed() const { - return _num_regions_evac_failed.load_relaxed(); +uint G1EvacFailureRegions::num_evac_failed_regions() const { + return _num_evac_failed_regions.load_relaxed(); } -bool G1EvacFailureRegions::has_regions_evac_failed() const { - return num_regions_evac_failed() > 0; +bool G1EvacFailureRegions::has_evac_failed_regions() const { + return num_evac_failed_regions() > 0; } -bool G1EvacFailureRegions::has_regions_evac_pinned() const { +bool G1EvacFailureRegions::has_evac_pinned_regions() const { G1GCPhaseTimes* p = G1CollectedHeap::heap()->phase_times(); size_t count = p->sum_thread_work_items(G1GCPhaseTimes::RestoreEvacuationFailedRegions, G1GCPhaseTimes::RestoreEvacFailureRegionsPinnedNum); return count != 0; } -bool G1EvacFailureRegions::has_regions_alloc_failed() const { +bool G1EvacFailureRegions::has_alloc_failed_regions() const { G1GCPhaseTimes* p = G1CollectedHeap::heap()->phase_times(); size_t count = p->sum_thread_work_items(G1GCPhaseTimes::RestoreEvacuationFailedRegions, G1GCPhaseTimes::RestoreEvacFailureRegionsAllocFailedNum); @@ -54,10 +54,10 @@ bool G1EvacFailureRegions::has_regions_alloc_failed() const { } bool G1EvacFailureRegions::record(uint worker_id, uint region_idx, bool cause_pinned) { - bool success = _regions_evac_failed.par_set_bit(region_idx, + bool success = _evac_failed_regions_map.par_set_bit(region_idx, memory_order_relaxed); if (success) { - size_t offset = _num_regions_evac_failed.fetch_then_add(1u); + size_t offset = _num_evac_failed_regions.fetch_then_add(1u); _evac_failed_regions[offset] = region_idx; G1CollectedHeap* g1h = G1CollectedHeap::heap(); diff --git a/src/hotspot/share/gc/g1/g1EvacInfo.hpp b/src/hotspot/share/gc/g1/g1EvacInfo.hpp index dc86f90d5f25..8a386bd58374 100644 --- a/src/hotspot/share/gc/g1/g1EvacInfo.hpp +++ b/src/hotspot/share/gc/g1/g1EvacInfo.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,26 +28,26 @@ #include "memory/allocation.hpp" class G1EvacInfo : public StackObj { - uint _collection_set_regions; - uint _allocation_regions; + uint _num_collection_set_regions; + uint _num_allocation_regions; size_t _collection_set_used_before; size_t _collection_set_used_after; size_t _alloc_regions_used_before; size_t _bytes_used; - uint _regions_freed; + uint _num_freed_regions; public: G1EvacInfo() : - _collection_set_regions(0), _allocation_regions(0), _collection_set_used_before(0), + _num_collection_set_regions(0), _num_allocation_regions(0), _collection_set_used_before(0), _collection_set_used_after(0), _alloc_regions_used_before(0), - _bytes_used(0), _regions_freed(0) { } + _bytes_used(0), _num_freed_regions(0) { } - void set_collection_set_regions(uint collection_set_regions) { - _collection_set_regions = collection_set_regions; + void set_num_collection_set_regions(uint num_collection_set_regions) { + _num_collection_set_regions = num_collection_set_regions; } - void set_allocation_regions(uint allocation_regions) { - _allocation_regions = allocation_regions; + void set_num_allocation_regions(uint num_allocation_regions) { + _num_allocation_regions = num_allocation_regions; } void set_collection_set_used_before(size_t used) { @@ -66,17 +66,17 @@ class G1EvacInfo : public StackObj { _bytes_used = used; } - void set_regions_freed(uint freed) { - _regions_freed += freed; + void add_to_num_freed_regions(uint num_freed_regions) { + _num_freed_regions += num_freed_regions; } - uint collection_set_regions() { return _collection_set_regions; } - uint allocation_regions() { return _allocation_regions; } + uint num_collection_set_regions() { return _num_collection_set_regions; } + uint num_allocation_regions() { return _num_allocation_regions; } size_t collection_set_used_before() { return _collection_set_used_before; } size_t collection_set_used_after() { return _collection_set_used_after; } size_t alloc_regions_used_before() { return _alloc_regions_used_before; } size_t bytes_used() { return _bytes_used; } - uint regions_freed() { return _regions_freed; } + uint num_freed_regions() { return _num_freed_regions; } }; #endif // SHARE_GC_G1_G1EVACINFO_HPP diff --git a/src/hotspot/share/gc/g1/g1EvacStats.cpp b/src/hotspot/share/gc/g1/g1EvacStats.cpp index d93f63383c45..58d7b3fec783 100644 --- a/src/hotspot/share/gc/g1/g1EvacStats.cpp +++ b/src/hotspot/share/gc/g1/g1EvacStats.cpp @@ -32,7 +32,7 @@ void G1EvacStats::reset() { PLABStats::reset(); _region_end_waste.store_relaxed(0); - _regions_filled.store_relaxed(0); + _num_filled_regions.store_relaxed(0); _num_plab_filled.store_relaxed(0); _direct_allocated.store_relaxed(0); _num_direct_allocated.store_relaxed(0); @@ -63,7 +63,7 @@ void G1EvacStats::log_plab_allocation() { "failure wasted: %zuB", _description, region_end_waste() * HeapWordSize, - regions_filled(), + num_filled_regions(), num_plab_filled(), direct_allocated() * HeapWordSize, num_direct_allocated(), @@ -132,7 +132,7 @@ G1EvacStats::G1EvacStats(const char* description, size_t default_per_thread_plab _desired_net_plab_size(default_per_thread_plab_size * ParallelGCThreads), _net_plab_size_filter(wt), _region_end_waste(0), - _regions_filled(0), + _num_filled_regions(0), _num_plab_filled(0), _direct_allocated(0), _num_direct_allocated(0), diff --git a/src/hotspot/share/gc/g1/g1EvacStats.hpp b/src/hotspot/share/gc/g1/g1EvacStats.hpp index b250d4580b55..e133d9feaf39 100644 --- a/src/hotspot/share/gc/g1/g1EvacStats.hpp +++ b/src/hotspot/share/gc/g1/g1EvacStats.hpp @@ -38,7 +38,7 @@ class G1EvacStats : public PLABStats { _net_plab_size_filter; // Integrator with decay Atomic _region_end_waste; // Number of words wasted due to skipping to the next region. - Atomic _regions_filled; // Number of regions filled completely. + Atomic _num_filled_regions; // Number of regions filled completely. Atomic _num_plab_filled; // Number of PLABs filled and retired. Atomic _direct_allocated; // Number of words allocated directly into the regions. Atomic _num_direct_allocated; // Number of direct allocation attempts. @@ -69,7 +69,7 @@ class G1EvacStats : public PLABStats { // Should be called at the end of a GC pause. void adjust_desired_plab_size(); - uint regions_filled() const; + uint num_filled_regions() const; size_t num_plab_filled() const; size_t region_end_waste() const; size_t direct_allocated() const; diff --git a/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp b/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp index 2bd3b37719ab..95bb47b4ce41 100644 --- a/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp +++ b/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp @@ -27,8 +27,8 @@ #include "gc/g1/g1EvacStats.hpp" -inline uint G1EvacStats::regions_filled() const { - return _regions_filled.load_relaxed(); +inline uint G1EvacStats::num_filled_regions() const { + return _num_filled_regions.load_relaxed(); } inline size_t G1EvacStats::num_plab_filled() const { @@ -69,7 +69,7 @@ inline void G1EvacStats::add_num_direct_allocated(size_t value) { inline void G1EvacStats::add_region_end_waste(size_t value) { _region_end_waste.add_then_fetch(value, memory_order_relaxed); - _regions_filled.add_then_fetch(1u, memory_order_relaxed); + _num_filled_regions.add_then_fetch(1u, memory_order_relaxed); } inline void G1EvacStats::add_failure_used_and_waste(size_t used, size_t waste) { diff --git a/src/hotspot/share/gc/g1/g1FromCardCache.hpp b/src/hotspot/share/gc/g1/g1FromCardCache.hpp index 5f759be0c4fb..6c71d5074fb1 100644 --- a/src/hotspot/share/gc/g1/g1FromCardCache.hpp +++ b/src/hotspot/share/gc/g1/g1FromCardCache.hpp @@ -29,40 +29,40 @@ #include "oops/oopsHierarchy.hpp" #include "utilities/globalDefinitions.hpp" -// G1FromCardCache remembers which destination cset groups have been +// G1FromCardCache remembers which destination card set groups have been // encountered while a worker scans the current from_card. // // Refinement and remembered set rebuild scan the heap linearly, visiting // references from a card consecutively. Therefore, the cache only tracks -// the destination cset groups found while scanning the current card. The +// the destination card set groups found while scanning the current card. The // cache state is discarded when advancing to the next card. // // A scan can be suspended at a yield point. A GC may run while it is -// suspended and change the cset group assignments. Therefore, the cache +// suspended and change the card set group assignments. Therefore, the cache // must be reset before the scan resumes after every yield. class G1FromCardCache { - // Worst case: each reference in a card targets a different cset group. + // Worst case: each reference in a card targets a different card set group. static constexpr uint MaxGroupsPerCard = MaxGCCardSizeInBytes / sizeof(narrowOop); uintptr_t _from_card; - uint _num_cset_groups; - uint _cset_group_ids[MaxGroupsPerCard]; + uint _num_card_set_groups; + uint _card_set_group_ids[MaxGroupsPerCard]; NONCOPYABLE(G1FromCardCache); public: G1FromCardCache() : _from_card(0), - _num_cset_groups(0) {} + _num_card_set_groups(0) {} // Discard the state associated with the _from_card. void reset() { - _num_cset_groups = 0; + _num_card_set_groups = 0; } - // Returns true if cset_group_id has already been encountered while + // Returns true if card_set_group_id has already been encountered while // scanning from_card. Otherwise, records the id and returns false. - inline bool contains_or_add(uintptr_t from_card, uint cset_group_id); + inline bool contains_or_add(uintptr_t from_card, uint card_set_group_id); }; #endif // SHARE_GC_G1_G1FROMCARDCACHE_HPP diff --git a/src/hotspot/share/gc/g1/g1FromCardCache.inline.hpp b/src/hotspot/share/gc/g1/g1FromCardCache.inline.hpp index 9a4abac3bc81..566d5ffa1735 100644 --- a/src/hotspot/share/gc/g1/g1FromCardCache.inline.hpp +++ b/src/hotspot/share/gc/g1/g1FromCardCache.inline.hpp @@ -27,21 +27,21 @@ #include "gc/g1/g1FromCardCache.hpp" -bool G1FromCardCache::contains_or_add(uintptr_t from_card, uint cset_group_id) { +bool G1FromCardCache::contains_or_add(uintptr_t from_card, uint card_set_group_id) { if (_from_card != from_card) { _from_card = from_card; - _num_cset_groups = 0; + _num_card_set_groups = 0; } - for (uint i = 0; i < _num_cset_groups; i++) { - if (_cset_group_ids[i] == cset_group_id) { + for (uint i = 0; i < _num_card_set_groups; i++) { + if (_card_set_group_ids[i] == card_set_group_id) { return true; } } - assert(_num_cset_groups < MaxGroupsPerCard, "from_card has too many destination cset groups"); + assert(_num_card_set_groups < MaxGroupsPerCard, "from_card has too many destination card set groups"); - _cset_group_ids[_num_cset_groups++] = cset_group_id; + _card_set_group_ids[_num_card_set_groups++] = card_set_group_id; return false; } diff --git a/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.cpp b/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.cpp index d6d39bafb34e..922155747b90 100644 --- a/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.cpp @@ -31,12 +31,12 @@ G1FullGCResetMetadataTask::G1ResetMetadataClosure::G1ResetMetadataClosure(G1Full _collector(collector) { } void G1FullGCResetMetadataTask::G1ResetMetadataClosure::reset_region_metadata(G1HeapRegion* hr) { - if (hr->rem_set()->has_cset_group()) { - assert(hr->is_starts_humongous(), "Only humongous regions can retain a cset group"); - assert(hr->rem_set()->cset_group()->length() == 1, - "Humongous region cset group must contain exactly one region"); + if (hr->rem_set()->has_card_set_group()) { + assert(hr->is_starts_humongous(), "Only humongous start regions can retain a card set group"); + assert(hr->rem_set()->card_set_group()->num_regions() == 1, + "Humongous region card set group must contain exactly one region"); - hr->rem_set()->cset_group()->clear_card_set(); + hr->rem_set()->card_set_group()->clear_card_set(); } hr->rem_set()->clear(); diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.cpp b/src/hotspot/share/gc/g1/g1HeapRegion.cpp index a9a76eee634f..70d326272e58 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.cpp @@ -109,7 +109,7 @@ void G1HeapRegion::handle_evacuation_failure(bool retain) { move_to_old(); _rem_set->clean_code_roots(this); - assert(!_rem_set->has_cset_group(), "must not have a cset group"); + assert(!_rem_set->has_card_set_group(), "must not have a card set group"); if (retain) { assert(_rem_set->is_tracked(), "must be"); } else { @@ -128,7 +128,7 @@ void G1HeapRegion::hr_clear(bool clear_space) { clear_young_index_in_cset(); clear_index_in_opt_cset(); uninstall_surv_rate_group(); - uninstall_cset_group(); + uninstall_card_set_group(); set_free(); reset_pre_dummy_top(); @@ -198,8 +198,8 @@ void G1HeapRegion::set_starts_humongous(HeapWord* obj_top, size_t fill_size) { _type.set_starts_humongous(); _humongous_start_region = this; - G1CSetCandidateGroup* cset_group = new G1CSetCandidateGroup(); - cset_group->add(this); + G1CardSetGroup* card_set_group = new G1CardSetGroup(); + card_set_group->add(this); _bot->update_for_block(bottom(), obj_top); if (fill_size > 0) { @@ -222,18 +222,18 @@ void G1HeapRegion::clear_humongous() { assert(capacity() == G1HeapRegion::GrainBytes, "pre-condition"); if (is_starts_humongous()) { - G1CSetCandidateGroup* cset_group = _rem_set->cset_group(); - assert(cset_group != nullptr, "pre-condition %u missing cardset", hrm_index()); - uninstall_cset_group(); - cset_group->clear(); - delete cset_group; + G1CardSetGroup* card_set_group = _rem_set->card_set_group(); + assert(card_set_group != nullptr, "pre-condition %u missing card set group", hrm_index()); + uninstall_card_set_group(); + card_set_group->clear(); + delete card_set_group; } _humongous_start_region = nullptr; } void G1HeapRegion::prepare_remset_for_scan() { if (is_young()) { - uninstall_cset_group(); + uninstall_card_set_group(); } _rem_set->reset_table_scanner(); } @@ -629,7 +629,7 @@ class G1VerifyLiveAndRemSetClosure : public BasicOopIterateClosure { bool failed() const { if (_from != _to && !_from->is_young() && _to->rem_set()->is_complete() && - _from->rem_set()->cset_group() != _to->rem_set()->cset_group()) { + _from->rem_set()->card_set_group() != _to->rem_set()->card_set_group()) { const CardValue clean = G1CardTable::clean_card_val(); return !(_to->rem_set()->contains_reference(this->_p) || (this->_containing_obj->is_objArray() ? diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.hpp index ec9cab260495..6e0d79231611 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.hpp @@ -41,7 +41,7 @@ class G1CardSet; class G1CardSetConfiguration; class G1CollectedHeap; class G1CMBitMap; -class G1CSetCandidateGroup; +class G1CardSetGroup; class G1Predictions; class G1HeapRegionRemSet; class G1HeapRegionSetBase; @@ -518,8 +518,8 @@ class G1HeapRegion : public CHeapObj { void install_surv_rate_group(G1SurvRateGroup* surv_rate_group); void uninstall_surv_rate_group(); - void install_cset_group(G1CSetCandidateGroup* cset_group); - void uninstall_cset_group(); + void install_card_set_group(G1CardSetGroup* card_set_group); + void uninstall_card_set_group(); void record_surv_words_in_group(size_t words_survived); diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp index 87597d450cb4..ae71190d6052 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp @@ -534,12 +534,12 @@ inline void G1HeapRegion::add_pinned_object_count(size_t value) { _pinned_object_count.add_then_fetch(value, memory_order_relaxed); } -inline void G1HeapRegion::install_cset_group(G1CSetCandidateGroup* cset_group) { - _rem_set->install_cset_group(cset_group); +inline void G1HeapRegion::install_card_set_group(G1CardSetGroup* card_set_group) { + _rem_set->install_card_set_group(card_set_group); } -inline void G1HeapRegion::uninstall_cset_group() { - _rem_set->uninstall_cset_group(); +inline void G1HeapRegion::uninstall_card_set_group() { + _rem_set->uninstall_card_set_group(); } #endif // SHARE_GC_G1_G1HEAPREGION_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp index 68ea6b60a4ea..56633d0b6d65 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp @@ -287,7 +287,7 @@ MemoryUsage G1HeapRegionManager::get_auxiliary_data_memory_usage() const { } bool G1HeapRegionManager::has_inactive_regions() const { - return _committed_map.num_inactive() > 0; + return _committed_map.num_inactive_regions() > 0; } uint G1HeapRegionManager::uncommit_inactive_regions(uint limit) { @@ -300,12 +300,12 @@ uint G1HeapRegionManager::uncommit_inactive_regions(uint limit) { G1HeapRegionRange range = _committed_map.next_inactive_range(offset); // No more regions available for uncommit. Return the number of regions // already uncommitted or 0 if there were no longer any inactive regions. - if (range.length() == 0) { + if (range.num_regions() == 0) { return uncommitted; } uint start = range.start(); - uint num_regions = MIN2(range.length(), limit - uncommitted); + uint num_regions = MIN2(range.num_regions(), limit - uncommitted); uncommitted += num_regions; uncommit_regions(start, num_regions); } while (uncommitted < limit); @@ -320,12 +320,12 @@ uint G1HeapRegionManager::expand_inactive(uint num_regions) { do { G1HeapRegionRange regions = _committed_map.next_inactive_range(offset); - if (regions.length() == 0) { + if (regions.num_regions() == 0) { // No more unavailable regions. break; } - uint to_expand = MIN2(num_regions - expanded, regions.length()); + uint to_expand = MIN2(num_regions - expanded, regions.num_regions()); reactivate_regions(regions.start(), to_expand); expanded += to_expand; offset = regions.end(); @@ -342,12 +342,12 @@ uint G1HeapRegionManager::expand_any(uint num_regions, WorkerThreads* pretouch_w do { G1HeapRegionRange regions = _committed_map.next_committable_range(offset); - if (regions.length() == 0) { + if (regions.num_regions() == 0) { // No more unavailable regions. break; } - uint to_expand = MIN2(num_regions - expanded, regions.length()); + uint to_expand = MIN2(num_regions - expanded, regions.num_regions()); expand(regions.start(), to_expand, pretouch_workers); expanded += to_expand; offset = regions.end(); @@ -379,18 +379,18 @@ void G1HeapRegionManager::expand_exact(uint start, uint num_regions, WorkerThrea for (uint i = start; i < end; i++) { // First check inactive. If the regions is inactive, try to reactivate it // before it get uncommitted by the G1SeriveThread. - if (_committed_map.inactive(i)) { + if (_committed_map.is_inactive(i)) { // Need to grab the lock since this can be called by a java thread // doing humongous allocations. MutexLocker uc(G1Uncommit_lock, Mutex::_no_safepoint_check_flag); // State might change while getting the lock. - if (_committed_map.inactive(i)) { + if (_committed_map.is_inactive(i)) { reactivate_regions(i, 1); } } // Not else-if to catch the case where the inactive region was uncommitted // while waiting to get the lock. - if (!_committed_map.active(i)) { + if (!_committed_map.is_active(i)) { expand(i, 1, pretouch_workers); } @@ -439,8 +439,8 @@ void G1HeapRegionManager::assert_contiguous_range(uint start, uint num_regions) for (uint i = start; i < (start + num_regions); i++) { G1HeapRegion* hr = _regions.get_by_index(i); assert(!is_available(i) || hr->is_free(), - "Found region sequence starting at " UINT32_FORMAT ", length " UINT32_FORMAT - " that is not free at " UINT32_FORMAT ". Hr is " PTR_FORMAT ", type is %s", + "Found region sequence starting at %u, num regions %u" + " that is not free at %u. Hr is " PTR_FORMAT ", type is %s", start, num_regions, i, p2i(hr), hr->get_type_str()); } } @@ -558,10 +558,10 @@ void G1HeapRegionManager::par_iterate(G1HeapRegionClosure* blk, G1HeapRegionClai // are currently not committed. // This also (potentially) iterates over regions newly allocated during GC. This // is no problem except for some extra work. - const uint n_regions = hrclaimer->n_regions(); - for (uint count = 0; count < n_regions; count++) { - const uint index = (start_index + count) % n_regions; - assert(index < n_regions, "sanity"); + const uint num_regions = hrclaimer->num_regions(); + for (uint cur_region_offset = 0; cur_region_offset < num_regions; cur_region_offset++) { + const uint index = (start_index + cur_region_offset) % num_regions; + assert(index < num_regions, "sanity"); // Skip over unavailable regions if (!is_available(index)) { continue; @@ -708,10 +708,10 @@ void G1HeapRegionManager::verify_optional() { } #endif // PRODUCT -G1HeapRegionClaimer::G1HeapRegionClaimer(uint n_workers) : - _n_workers(n_workers), _n_regions(G1CollectedHeap::heap()->_hrm._next_highest_used_hrm_index), _claims(nullptr) { - Atomic* new_claims = NEW_C_HEAP_ARRAY(Atomic, _n_regions, mtGC); - for (uint i = 0; i < _n_regions; i++) { +G1HeapRegionClaimer::G1HeapRegionClaimer(uint num_workers) : + _num_workers(num_workers), _num_regions(G1CollectedHeap::heap()->_hrm._next_highest_used_hrm_index), _claims(nullptr) { + Atomic* new_claims = NEW_C_HEAP_ARRAY(Atomic, _num_regions, mtGC); + for (uint i = 0; i < _num_regions; i++) { new_claims[i].store_relaxed(Unclaimed); } _claims = new_claims; @@ -722,18 +722,18 @@ G1HeapRegionClaimer::~G1HeapRegionClaimer() { } uint G1HeapRegionClaimer::offset_for_worker(uint worker_id) const { - assert(_n_workers > 0, "must be set"); - assert(worker_id < _n_workers, "Invalid worker_id."); - return _n_regions * worker_id / _n_workers; + assert(_num_workers > 0, "must be set"); + assert(worker_id < _num_workers, "Invalid worker_id."); + return _num_regions * worker_id / _num_workers; } bool G1HeapRegionClaimer::is_region_claimed(uint region_index) const { - assert(region_index < _n_regions, "Invalid index."); + assert(region_index < _num_regions, "Invalid index."); return _claims[region_index].load_relaxed() == Claimed; } bool G1HeapRegionClaimer::claim_region(uint region_index) { - assert(region_index < _n_regions, "Invalid index."); + assert(region_index < _num_regions, "Invalid index."); return _claims[region_index].compare_set(Unclaimed, Claimed); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp index 37cf89661ac6..0bef96ceba4c 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp @@ -61,10 +61,10 @@ class G1HeapRegionTable : public G1BiasedMappedArray { // region we retain the G1HeapRegion to be able to re-use it in the // future (in case we recommit it). // -// We keep track of four lengths: +// We keep track of three region counts: // -// * _num_committed (returned by length()) is the number of currently -// committed regions. These may not be contiguous. +// * num_committed_regions() is the number of currently committed regions using +// the committed map. These may not be contiguous. // * _next_highest_used_hrm_index (not exposed outside this class) is the // highest heap region index +1 for which we have G1HeapRegions. // * max_num_regions() returns the maximum number of regions the heap has reserved. @@ -128,10 +128,10 @@ class G1HeapRegionManager: public CHeapObj { void expand(uint index, uint num_regions, WorkerThreads* pretouch_workers = nullptr); - // G1RegionCommittedMap helpers. These functions do the work that comes with + // G1CommittedRegionMap helpers. These functions do the work that comes with // the state changes tracked by G1CommittedRegionMap. To make sure this is // safe from a multi-threading point of view there are two lock protocols in - // G1RegionCommittedMap::guarantee_mt_safety_* that are enforced. The lock + // G1CommittedRegionMap::guarantee_mt_safety_* that are enforced. The lock // needed should have been acquired before calling these functions. void activate_regions(uint index, uint num_regions); void deactivate_regions(uint start, uint num_regions); @@ -226,7 +226,7 @@ class G1HeapRegionManager: public CHeapObj { uint num_used_regions() const { return num_committed_regions() - num_free_regions(); } uint num_free_regions(uint node_index) const { - return _free_list.length(node_index); + return _free_list.num_regions_on_node(node_index); } size_t total_free_bytes() const { @@ -237,7 +237,7 @@ class G1HeapRegionManager: public CHeapObj { uint num_inactive_regions() const { return max_num_regions() - num_committed_regions(); } // Return the number of regions currently active and available for use. - uint num_committed_regions() const { return _committed_map.num_active(); } + uint num_committed_regions() const { return _committed_map.num_active_regions(); } // The number of regions reserved for the heap. uint max_num_regions() const { return (uint)_regions.length(); } @@ -293,25 +293,25 @@ class G1HeapRegionManager: public CHeapObj { // The G1HeapRegionClaimer is used during parallel iteration over heap regions, // allowing workers to claim heap regions, gaining exclusive rights to these regions. class G1HeapRegionClaimer : public StackObj { - uint _n_workers; - uint _n_regions; + uint _num_workers; + uint _num_regions; Atomic* _claims; static const uint Unclaimed = 0; static const uint Claimed = 1; public: - G1HeapRegionClaimer(uint n_workers); + G1HeapRegionClaimer(uint num_workers); ~G1HeapRegionClaimer(); - inline uint n_regions() const { - return _n_regions; + inline uint num_regions() const { + return _num_regions; } - void set_n_workers(uint n_workers) { - assert(_n_workers == 0, "already set"); - assert(n_workers > 0, "must be"); - _n_workers = n_workers; + void set_num_workers(uint num_workers) { + assert(_num_workers == 0, "already set"); + assert(num_workers > 0, "must be"); + _num_workers = num_workers; } // Return a start offset given a worker id. uint offset_for_worker(uint worker_id) const; diff --git a/src/hotspot/share/gc/g1/g1HeapRegionManager.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.inline.hpp index d65fdef922c6..566088976f14 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionManager.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionManager.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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,7 +32,7 @@ #include "gc/g1/g1HeapRegionSet.inline.hpp" inline bool G1HeapRegionManager::is_available(uint region) const { - return _committed_map.active(region); + return _committed_map.is_active(region); } inline G1HeapRegion* G1HeapRegionManager::addr_to_region(HeapWord* addr) const { diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp index a965859a4146..c556303d74ef 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp @@ -35,17 +35,17 @@ void G1HeapRegionRemSet::initialize(MemRegion reserved) { _heap_base_address = reserved.start(); } -void G1HeapRegionRemSet::uninstall_cset_group() { - _cset_group = nullptr; +void G1HeapRegionRemSet::uninstall_card_set_group() { + _card_set_group = nullptr; } G1HeapRegionRemSet::G1HeapRegionRemSet() : _code_roots(), - _cset_group(nullptr), + _card_set_group(nullptr), _state(Untracked) { } G1HeapRegionRemSet::~G1HeapRegionRemSet() { - assert(!has_cset_group(), "Still assigned to a CSet group"); + assert(!has_card_set_group(), "Still assigned to a card set group"); } void G1HeapRegionRemSet::clear() { @@ -60,14 +60,14 @@ void G1HeapRegionRemSet::reset_code_root_table_scanner() { void G1HeapRegionRemSet::reset_table_scanner() { reset_code_root_table_scanner(); - if (has_cset_group()) { + if (has_card_set_group()) { card_set()->reset_table_scanner(); } } G1MonotonicArenaMemoryStats G1HeapRegionRemSet::card_set_memory_stats() const { - assert(has_cset_group(), "pre-condition"); - return cset_group()->card_set_memory_stats(); + assert(has_card_set_group(), "pre-condition"); + return card_set_group()->card_set_memory_stats(); } void G1HeapRegionRemSet::print_static_mem_size(outputStream* out) { diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp index 2552df58b3a3..2e662dd5e530 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp @@ -38,53 +38,53 @@ class G1HeapRegionRemSet : public CHeapObj { // the region that owns this RSet. G1CodeRootSet _code_roots; - G1CSetCandidateGroup* _cset_group; + G1CardSetGroup* _card_set_group; // Cached value of heap base address. static HeapWord* _heap_base_address; G1CardSet* card_set() { - assert(has_cset_group(), "pre-condition"); - return cset_group()->card_set(); + assert(has_card_set_group(), "pre-condition"); + return card_set_group()->card_set(); } const G1CardSet* card_set() const { - assert(has_cset_group(), "pre-condition"); - return cset_group()->card_set(); + assert(has_card_set_group(), "pre-condition"); + return card_set_group()->card_set(); } bool card_set_is_empty() const { - return !has_cset_group() || card_set()->is_empty(); + return !has_card_set_group() || card_set()->is_empty(); } public: G1HeapRegionRemSet(); ~G1HeapRegionRemSet(); - void install_cset_group(G1CSetCandidateGroup* cset_group) { - assert(cset_group != nullptr, "pre-condition"); - assert(_cset_group == nullptr, "pre-condition"); + void install_card_set_group(G1CardSetGroup* card_set_group) { + assert(card_set_group != nullptr, "pre-condition"); + assert(_card_set_group == nullptr, "pre-condition"); - _cset_group = cset_group; + _card_set_group = card_set_group; } - void uninstall_cset_group(); + void uninstall_card_set_group(); - bool has_cset_group() const { - return _cset_group != nullptr; + bool has_card_set_group() const { + return _card_set_group != nullptr; } - G1CSetCandidateGroup* cset_group() { - return _cset_group; + G1CardSetGroup* card_set_group() { + return _card_set_group; } - const G1CSetCandidateGroup* cset_group() const { - return _cset_group; + const G1CardSetGroup* card_set_group() const { + return _card_set_group; } - uint cset_group_id() const { - assert(has_cset_group(), "pre-condition"); - return cset_group()->group_id(); + uint card_set_group_id() const { + assert(has_card_set_group(), "pre-condition"); + return card_set_group()->group_id(); } bool is_empty() const { @@ -105,7 +105,7 @@ class G1HeapRegionRemSet : public CHeapObj { inline static void iterate_for_merge(G1CardSet* card_set, CardOrRangeVisitor& cl); size_t occupied() { - assert(has_cset_group(), "pre-condition"); + assert(has_card_set_group(), "pre-condition"); return card_set()->occupied(); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp index 25b1fbebfff5..3746b0d58c2b 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp @@ -122,12 +122,12 @@ uintptr_t G1HeapRegionRemSet::to_card(OopOrNarrowOopStar from) const { } void G1HeapRegionRemSet::add_reference(OopOrNarrowOopStar from, G1FromCardCache& from_card_cache) { - precond(has_cset_group()); + precond(has_card_set_group()); precond(_state != Untracked); uintptr_t from_card = uintptr_t(from) >> CardTable::card_shift(); - if (from_card_cache.contains_or_add(from_card, cset_group()->group_id())) { + if (from_card_cache.contains_or_add(from_card, card_set_group()->group_id())) { // We can't check whether the card is in the remembered set - the card container // may be coarsened just now. return; diff --git a/src/hotspot/share/gc/g1/g1HeapRegionSet.cpp b/src/hotspot/share/gc/g1/g1HeapRegionSet.cpp index 24888421c4fe..f710b64d7f29 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionSet.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionSet.cpp @@ -27,7 +27,7 @@ #include "gc/g1/g1HeapRegionSet.inline.hpp" #include "gc/g1/g1NUMA.hpp" -uint G1FreeRegionList::_unrealistically_long_length = 0; +uint G1FreeRegionList::_unrealistically_large_num_regions = 0; #ifndef PRODUCT void G1HeapRegionSetBase::verify_region(G1HeapRegion* hr) { @@ -83,9 +83,9 @@ G1HeapRegionSetBase::G1HeapRegionSetBase(const char* name, G1HeapRegionSetChecke { } -void G1FreeRegionList::set_unrealistically_long_length(uint len) { - guarantee(_unrealistically_long_length == 0, "should only be set once"); - _unrealistically_long_length = len; +void G1FreeRegionList::set_unrealistically_large_num_regions(uint num_regions) { + guarantee(_unrealistically_large_num_regions == 0, "should only be set once"); + _unrealistically_large_num_regions = num_regions; } void G1FreeRegionList::abandon() { @@ -107,7 +107,7 @@ void G1FreeRegionList::remove_all() { curr->set_prev(nullptr); curr->set_containing_set(nullptr); - decrease_length(curr->node_index()); + decrease_num_regions(curr->node_index()); curr = next; } @@ -250,7 +250,7 @@ void G1FreeRegionList::remove_starting_at(G1HeapRegion* first, uint num_regions_ assert_free_region_list(num_regions() >= num_regions_to_remove, "pre-condition"); verify_optional(); - DEBUG_ONLY(uint old_length = num_regions();) + DEBUG_ONLY(uint old_num_regions = num_regions();) // prev points to the node right before first or null when first == _head G1HeapRegion* const prev = first->prev(); @@ -276,7 +276,7 @@ void G1FreeRegionList::remove_starting_at(G1HeapRegion* first, uint num_regions_ num_regions_removed++; - decrease_length(curr->node_index()); + decrease_num_regions(curr->node_index()); curr = next; } @@ -293,12 +293,12 @@ void G1FreeRegionList::remove_starting_at(G1HeapRegion* first, uint num_regions_ } assert(num_regions_removed == num_regions_to_remove, - "[%s] count: %u should be == num_regions: %u", + "[%s] removed: %u should be equal to num_regions_to_remove: %u", name(), num_regions_removed, num_regions_to_remove); - assert(num_regions() + num_regions_to_remove == old_length, - "[%s] new length should be consistent " - "new length: %u old length: %u num_regions: %u", - name(), num_regions(), old_length, num_regions_to_remove); + assert(num_regions() + num_regions_to_remove == old_num_regions, + "[%s] new num_regions should be equal " + "new num_regions: %u old num_regions: %u num_regions_to_remove: %u", + name(), num_regions(), old_num_regions, num_regions_to_remove); verify_optional(); } @@ -331,18 +331,17 @@ void G1FreeRegionList::verify_list() { G1HeapRegion* curr = _head; G1HeapRegion* prev1 = nullptr; G1HeapRegion* prev0 = nullptr; - uint count = 0; - size_t capacity = 0; + uint actual_num_regions = 0; uint last_index = 0; guarantee(_head == nullptr || _head->prev() == nullptr, "_head should not have a prev"); while (curr != nullptr) { verify_region(curr); - count++; - guarantee(count < _unrealistically_long_length, - "[%s] the calculated length: %u seems very long, is there maybe a cycle? curr: " PTR_FORMAT " prev0: " PTR_FORMAT " " "prev1: " PTR_FORMAT " length: %u", - name(), count, p2i(curr), p2i(prev0), p2i(prev1), num_regions()); + actual_num_regions++; + guarantee(actual_num_regions < _unrealistically_large_num_regions, + "[%s] the calculated number of regions: %u seems unrealistically large, cycle? curr: " PTR_FORMAT " prev0: " PTR_FORMAT " " "prev1: " PTR_FORMAT " num_regions: %u", + name(), actual_num_regions, p2i(curr), p2i(prev0), p2i(prev1), num_regions()); if (curr->next() != nullptr) { guarantee(curr->next()->prev() == curr, "Next or prev pointers messed up"); @@ -350,8 +349,6 @@ void G1FreeRegionList::verify_list() { guarantee(curr->hrm_index() == 0 || curr->hrm_index() > last_index, "List should be sorted"); last_index = curr->hrm_index(); - capacity += curr->capacity(); - prev1 = prev0; prev0 = curr; curr = curr->next(); @@ -359,7 +356,7 @@ void G1FreeRegionList::verify_list() { guarantee(_tail == prev0, "Expected %s to end with %u but it ended with %u.", name(), _tail->hrm_index(), prev0->hrm_index()); guarantee(_tail == nullptr || _tail->next() == nullptr, "_tail should not have a next"); - guarantee(num_regions() == count, "%s count mismatch. Expected %u, actual %u.", name(), num_regions(), count); + guarantee(num_regions() == actual_num_regions, "%s num_regions mismatch. Expected %u, actual %u.", name(), num_regions(), actual_num_regions); } @@ -376,25 +373,25 @@ G1FreeRegionList::~G1FreeRegionList() { } } -G1FreeRegionList::NodeInfo::NodeInfo() : _numa(G1NUMA::numa()), _length_of_node(nullptr), +G1FreeRegionList::NodeInfo::NodeInfo() : _numa(G1NUMA::numa()), _num_regions_on_node(nullptr), _num_nodes(_numa->num_active_nodes()) { assert(UseNUMA, "Invariant"); - _length_of_node = NEW_C_HEAP_ARRAY(uint, _num_nodes, mtGC); + _num_regions_on_node = NEW_C_HEAP_ARRAY(uint, _num_nodes, mtGC); } G1FreeRegionList::NodeInfo::~NodeInfo() { - FREE_C_HEAP_ARRAY(_length_of_node); + FREE_C_HEAP_ARRAY(_num_regions_on_node); } void G1FreeRegionList::NodeInfo::clear() { for (uint i = 0; i < _num_nodes; ++i) { - _length_of_node[i] = 0; + _num_regions_on_node[i] = 0; } } void G1FreeRegionList::NodeInfo::add(NodeInfo* info) { for (uint i = 0; i < _num_nodes; ++i) { - _length_of_node[i] += info->_length_of_node[i]; + _num_regions_on_node[i] += info->_num_regions_on_node[i]; } } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionSet.hpp b/src/hotspot/share/gc/g1/g1HeapRegionSet.hpp index a98397ad0118..32646ea84236 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionSet.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionSet.hpp @@ -145,17 +145,17 @@ class G1FreeRegionList : public G1HeapRegionSetBase { // This class is only initialized if there are multiple active nodes. class NodeInfo : public CHeapObj { G1NUMA* _numa; - uint* _length_of_node; + uint* _num_regions_on_node; uint _num_nodes; public: NodeInfo(); ~NodeInfo(); - inline void increase_length(uint node_index); - inline void decrease_length(uint node_index); + inline void increase_num_regions(uint node_index); + inline void decrease_num_regions(uint node_index); - inline uint length(uint index) const; + inline uint num_regions_on_node(uint index) const; void clear(); @@ -169,15 +169,15 @@ class G1FreeRegionList : public G1HeapRegionSetBase { // time. It helps to improve performance when adding several ordered items in a row. G1HeapRegion* _last; - NodeInfo* _node_info; + NodeInfo* _node_info; - static uint _unrealistically_long_length; + static uint _unrealistically_large_num_regions; inline G1HeapRegion* remove_from_head_impl(); inline G1HeapRegion* remove_from_tail_impl(); - inline void increase_length(uint node_index); - inline void decrease_length(uint node_index); + inline void increase_num_regions(uint node_index); + inline void decrease_num_regions(uint node_index); // Common checks for adding a list. void add_list_common_start(G1FreeRegionList* from_list); @@ -200,7 +200,7 @@ class G1FreeRegionList : public G1HeapRegionSetBase { } #endif - static void set_unrealistically_long_length(uint len); + static void set_unrealistically_large_num_regions(uint num_regions); // Add hr to the list. The region should not be a member of another set. // Assumes that the list is ordered and will preserve that order. The order @@ -235,7 +235,7 @@ class G1FreeRegionList : public G1HeapRegionSetBase { virtual void verify(); using G1HeapRegionSetBase::num_regions; - uint length(uint node_index) const; + uint num_regions_on_node(uint node_index) const; }; // Iterator class that provides a convenient way to iterate over the diff --git a/src/hotspot/share/gc/g1/g1HeapRegionSet.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegionSet.inline.hpp index 5bd6ac703bcd..c18ac68e0648 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionSet.inline.hpp @@ -68,7 +68,7 @@ inline void G1FreeRegionList::add_to_tail(G1HeapRegion* region_to_add) { _head = region_to_add; _tail = region_to_add; } - increase_length(region_to_add->node_index()); + increase_num_regions(region_to_add->node_index()); } inline void G1FreeRegionList::add_ordered(G1HeapRegion* hr) { @@ -117,7 +117,7 @@ inline void G1FreeRegionList::add_ordered(G1HeapRegion* hr) { } _last = hr; - increase_length(hr->node_index()); + increase_num_regions(hr->node_index()); } inline G1HeapRegion* G1FreeRegionList::remove_from_head_impl() { @@ -169,7 +169,7 @@ inline G1HeapRegion* G1FreeRegionList::remove_region(bool from_head) { // remove() will verify the region and check mt safety. remove(hr); - decrease_length(hr->node_index()); + decrease_num_regions(hr->node_index()); return hr; } @@ -227,45 +227,45 @@ inline G1HeapRegion* G1FreeRegionList::remove_region_with_node_index(bool from_h } remove(cur); - decrease_length(cur->node_index()); + decrease_num_regions(cur->node_index()); return cur; } -inline void G1FreeRegionList::NodeInfo::increase_length(uint node_index) { +inline void G1FreeRegionList::NodeInfo::increase_num_regions(uint node_index) { if (node_index < _num_nodes) { - _length_of_node[node_index] += 1; + _num_regions_on_node[node_index] += 1; } } -inline void G1FreeRegionList::NodeInfo::decrease_length(uint node_index) { +inline void G1FreeRegionList::NodeInfo::decrease_num_regions(uint node_index) { if (node_index < _num_nodes) { - assert(_length_of_node[node_index] > 0, - "Current length %u should be greater than zero for node %u", - _length_of_node[node_index], node_index); - _length_of_node[node_index] -= 1; + assert(_num_regions_on_node[node_index] > 0, + "Current num_regions %u should be greater than zero for node %u", + _num_regions_on_node[node_index], node_index); + _num_regions_on_node[node_index] -= 1; } } -inline uint G1FreeRegionList::NodeInfo::length(uint node_index) const { - return _length_of_node[node_index]; +inline uint G1FreeRegionList::NodeInfo::num_regions_on_node(uint node_index) const { + return _num_regions_on_node[node_index]; } -inline void G1FreeRegionList::increase_length(uint node_index) { +inline void G1FreeRegionList::increase_num_regions(uint node_index) { if (_node_info != nullptr) { - return _node_info->increase_length(node_index); + return _node_info->increase_num_regions(node_index); } } -inline void G1FreeRegionList::decrease_length(uint node_index) { +inline void G1FreeRegionList::decrease_num_regions(uint node_index) { if (_node_info != nullptr) { - return _node_info->decrease_length(node_index); + return _node_info->decrease_num_regions(node_index); } } -inline uint G1FreeRegionList::length(uint node_index) const { +inline uint G1FreeRegionList::num_regions_on_node(uint node_index) const { if (_node_info != nullptr) { - return _node_info->length(node_index); + return _node_info->num_regions_on_node(node_index); } else { return 0; } diff --git a/src/hotspot/share/gc/g1/g1HeapTransition.cpp b/src/hotspot/share/gc/g1/g1HeapTransition.cpp index 0c00be382c0c..ff3209012078 100644 --- a/src/hotspot/share/gc/g1/g1HeapTransition.cpp +++ b/src/hotspot/share/gc/g1/g1HeapTransition.cpp @@ -133,7 +133,7 @@ void G1HeapTransition::print() { Data after(_g1_heap); size_t num_eden_after_gc = _g1_heap->policy()->target_num_young_regions() - after._num_survivor_regions; - size_t num_survivor_before_gc = _g1_heap->policy()->max_survivor_regions(); + size_t num_survivor_before_gc = _g1_heap->policy()->max_num_survivor_regions(); DetailedUsage usage; if (log_is_enabled(Trace, gc, heap)) { diff --git a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp index aed36f8738fd..c7ea27882ab0 100644 --- a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp +++ b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp @@ -163,7 +163,7 @@ inline void G1ConcurrentRefineOopClosure::do_oop_work(T* p) { if (to_rem_set->is_tracked()) { G1HeapRegion* from = _g1h->heap_region_containing(p); - if (from->rem_set()->cset_group() != to_rem_set->cset_group()) { + if (from->rem_set()->card_set_group() != to_rem_set->card_set_group()) { to_rem_set->add_reference(p, _from_card_cache); _has_ref_to_old = true; } @@ -290,7 +290,7 @@ template void G1RebuildRemSetClosure::do_oop_work(T* p) { if (!to->is_young()) { G1HeapRegion* from = _g1h->heap_region_containing(p); - if (from->rem_set()->cset_group() != rem_set->cset_group()) { + if (from->rem_set()->card_set_group() != rem_set->card_set_group()) { rem_set->add_reference(p, _from_card_cache); } } diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 66dd3967e387..0b1b383a026f 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -65,7 +65,7 @@ G1Policy::G1Policy(STWGCTimer* gc_timer) : _eden_surv_rate_group(new G1SurvRateGroup()), _survivor_surv_rate_group(new G1SurvRateGroup()), _reserve_factor((double) G1ReservePercent / 100.0), - _reserve_regions(0), + _num_reserve_regions(0), _young_gen_sizer(), _free_regions_at_end_of_collection(0), _pending_cards_from_gc(0), @@ -75,7 +75,7 @@ G1Policy::G1Policy(STWGCTimer* gc_timer) : _phase_times_timer(gc_timer), _phase_times(nullptr), _tenuring_threshold(MaxTenuringThreshold), - _max_survivor_regions(0), + _max_num_survivor_regions(0), _survivors_age_table(true) { } @@ -156,16 +156,15 @@ class G1NumYoungRegionsPredictor { } }; -void G1Policy::record_new_heap_size(uint new_number_of_regions) { - // re-calculate the necessary reserve - double reserve_regions_d = (double) new_number_of_regions * _reserve_factor; - // We use ceiling so that if reserve_regions_d is > 0.0 (but - // smaller than 1.0) we'll get 1. - _reserve_regions.store_relaxed((uint) ceil(reserve_regions_d)); +void G1Policy::record_new_heap_size(uint new_num_regions) { + // Re-calculate the necessary reserve. + double num_reserve_regions_d = (double)new_num_regions * _reserve_factor; + // Round up above result to always get a non-zero result. + _num_reserve_regions.store_relaxed((uint)ceil(num_reserve_regions_d)); - _young_gen_sizer.heap_size_changed(new_number_of_regions); + _young_gen_sizer.heap_size_changed(new_num_regions); - _ihop_control->update_target_occupancy(new_number_of_regions * G1HeapRegion::GrainBytes); + _ihop_control->update_target_occupancy(new_num_regions * G1HeapRegion::GrainBytes); } uint G1Policy::calculate_desired_num_eden_regions_by_mmu() const { @@ -340,10 +339,10 @@ uint G1Policy::calculate_target_num_young_regions(uint desired_num_young_regions // It can be concurrently modified by the mutator as it expands the heap. It can // only increase at that time, so this is a conservative snapshot. So at worst this // method will return a too small number of young regions in that case. - uint reserve_regions = _reserve_regions.load_relaxed(); + uint num_reserve_regions = _num_reserve_regions.load_relaxed(); uint max_to_eat_into_reserve = MIN2(min_num_young_regions_by_sizer, - (reserve_regions + 1) / 2); + (num_reserve_regions + 1) / 2); log_trace(gc, ergo, heap)("Target young regions: Common " "free regions at end of collection %u " @@ -352,14 +351,14 @@ uint G1Policy::calculate_target_num_young_regions(uint desired_num_young_regions "max to eat into reserve %u", _free_regions_at_end_of_collection, desired_num_young_regions, - reserve_regions, + num_reserve_regions, max_to_eat_into_reserve); uint num_survivor_regions = _g1h->num_survivor_regions(); uint desired_num_eden_regions = desired_num_young_regions - num_survivor_regions; uint num_eden_regions = num_young_regions - num_survivor_regions; - if (_free_regions_at_end_of_collection <= reserve_regions) { + if (_free_regions_at_end_of_collection <= num_reserve_regions) { // Fully eat (or already eating) into the reserve. uint receiving_eden = MIN3(_free_regions_at_end_of_collection, desired_num_eden_regions, @@ -374,9 +373,9 @@ uint G1Policy::calculate_target_num_young_regions(uint desired_num_young_regions log_trace(gc, ergo, heap)("Target young regions: Fully eat into reserve " "receiving eden %u receiving additional eden %u", receiving_eden, receiving_additional_eden); - } else if (_free_regions_at_end_of_collection < (desired_num_eden_regions + reserve_regions)) { + } else if (_free_regions_at_end_of_collection < (desired_num_eden_regions + num_reserve_regions)) { // Partially eat into the reserve, at most max_to_eat_into_reserve regions. - uint free_outside_reserve = _free_regions_at_end_of_collection - reserve_regions; + uint free_outside_reserve = _free_regions_at_end_of_collection - num_reserve_regions; assert(free_outside_reserve < desired_num_eden_regions, "must be %u %u", free_outside_reserve, desired_num_eden_regions); @@ -508,16 +507,16 @@ uint G1Policy::calculate_desired_num_eden_regions_before_young_only(double base_ uint G1Policy::calculate_desired_num_eden_regions_before_mixed(double base_time_ms, uint min_num_eden_regions, uint max_num_eden_regions) const { - uint min_marking_candidates = MIN2(calc_min_old_cset_length(candidates()->last_marking_candidates_length()), - candidates()->from_marking_groups().num_regions()); + uint min_num_marking_candidate_regions = MIN2(calc_min_num_old_cset_regions(candidates()->num_last_marking_candidate_regions()), + candidates()->from_marking_groups().num_regions()); double predicted_region_evac_time_ms = base_time_ms; - uint selected_candidates = 0; - for (G1CSetCandidateGroup* gr : candidates()->from_marking_groups()) { - if (selected_candidates >= min_marking_candidates) { + uint num_selected_candidate_regions = 0; + for (G1CardSetGroup* gr : candidates()->from_marking_groups()) { + if (num_selected_candidate_regions >= min_num_marking_candidate_regions) { break; } predicted_region_evac_time_ms += gr->predict_group_total_time_ms(); - selected_candidates += gr->length(); + num_selected_candidate_regions += gr->num_regions(); } return calculate_desired_num_eden_regions_before_young_only(predicted_region_evac_time_ms, @@ -540,15 +539,15 @@ double G1Policy::predict_retained_regions_evac_time() const { double result = 0.0; - G1CSetCandidateGroupList* retained_groups = &candidates()->retained_groups(); - uint min_regions_left = MIN2(min_retained_old_cset_length(), + G1CardSetGroupList* retained_groups = &candidates()->retained_groups(); + uint min_regions_left = MIN2(min_num_retained_old_cset_regions(), retained_groups->num_regions()); - for (G1CSetCandidateGroup* group : *retained_groups) { - assert(group->length() == 1, "We should only have one region in a retained group"); + for (G1CardSetGroup* group : *retained_groups) { + assert(group->num_regions() == 1, "We should only have one region in a retained group"); G1HeapRegion* r = group->region_at(0); // We only have one region per group. - // We optimistically assume that any of these marking candidate regions will - // be reclaimable the next gc, so just consider them as normal. + // We optimistically assume that any regions of these card set groups that contain pinned + // regions can be evacuated the next gc, so just consider them like normal. if (r->has_pinned_objects()) { num_pinned_regions++; } @@ -699,9 +698,9 @@ void G1Policy::record_young_collection_start() { // every time we calculate / recalculate the target number of young regions. update_survivors_policy(); - assert(max_survivor_regions() + _g1h->num_used_regions() <= _g1h->max_num_regions(), + assert(max_num_survivor_regions() + _g1h->num_used_regions() <= _g1h->max_num_regions(), "Maximum survivor regions %u plus used regions %u exceeds max regions %u", - max_survivor_regions(), _g1h->num_used_regions(), _g1h->max_num_regions()); + max_num_survivor_regions(), _g1h->num_used_regions(), _g1h->max_num_regions()); assert_used_and_recalculate_used_equal(_g1h); // do that for any other surv rate groups @@ -858,8 +857,8 @@ G1CollectorState G1Policy::record_young_collection_end(bool concurrent_operation // given that humongous object allocations do not really affect // either the pause's duration nor when the next pause will take // place we can safely ignore them here. - uint regions_allocated = _collection_set->num_eden_regions(); - double alloc_rate_ms = (double) regions_allocated / app_time_ms; + uint num_eden_regions = _collection_set->num_eden_regions(); + double alloc_rate_ms = (double) num_eden_regions / app_time_ms; _analytics->report_alloc_rate_ms(alloc_rate_ms); double merge_refinement_table_time = p->cur_merge_refinement_table_time(); @@ -1222,8 +1221,8 @@ size_t G1Policy::estimate_used_young_bytes_locked() const { return bytes_used + allocator->used_in_alloc_regions(); } -size_t G1Policy::desired_survivor_size(uint max_regions) const { - size_t const survivor_capacity = G1HeapRegion::GrainWords * max_regions; +size_t G1Policy::desired_survivor_size(uint max_num_regions) const { + size_t const survivor_capacity = G1HeapRegion::GrainWords * max_num_regions; return (size_t)((((double)survivor_capacity) * TargetSurvivorRatio) / 100); } @@ -1233,14 +1232,14 @@ void G1Policy::print_age_table() { // Calculates survivor space parameters. void G1Policy::update_survivors_policy() { - double max_survivor_regions_d = + double max_num_survivor_regions_d = (double)target_num_young_regions() / (double) SurvivorRatio; // Calculate desired survivor size based on desired max survivor regions (unconstrained // by remaining heap). Otherwise we may cause undesired promotions as we are // already getting close to end of the heap, impacting performance even more. - uint const desired_max_survivor_regions = ceil(max_survivor_regions_d); - size_t const survivor_size = desired_survivor_size(desired_max_survivor_regions); + uint const desired_max_num_survivor_regions = ceil(max_num_survivor_regions_d); + size_t const survivor_size = desired_survivor_size(desired_max_num_survivor_regions); _tenuring_threshold = _survivors_age_table.compute_tenuring_threshold(survivor_size); if (UsePerfData) { @@ -1249,8 +1248,8 @@ void G1Policy::update_survivors_policy() { } // The real maximum survivor size is bounded by the number of regions that can // be allocated into. - _max_survivor_regions = MIN2(desired_max_survivor_regions, - _g1h->num_available_regions()); + _max_num_survivor_regions = MIN2(desired_max_num_survivor_regions, + _g1h->num_available_regions()); } bool G1Policy::force_concurrent_start_if_outside_cycle(GCCause::Cause gc_cause) { @@ -1492,13 +1491,13 @@ size_t G1Policy::current_to_collection_set_cards() { return _to_collection_set_cards; } -uint G1Policy::min_retained_old_cset_length() const { +uint G1Policy::min_num_retained_old_cset_regions() const { // Guarantee some progress with retained regions regardless of available time by // taking at least one region. return 1; } -uint G1Policy::calc_min_old_cset_length(uint num_candidate_regions) const { +uint G1Policy::calc_min_num_old_cset_regions(uint num_candidate_regions) const { // The min old CSet region bound is based on the maximum desired // number of mixed GCs after a cycle. I.e., even if some old regions // look expensive, we should add them to the CSet anyway to make @@ -1513,7 +1512,7 @@ uint G1Policy::calc_min_old_cset_length(uint num_candidate_regions) const { return (uint)ceil((double)num_candidate_regions / gc_num); } -uint G1Policy::calc_max_old_cset_length() const { +uint G1Policy::calc_max_num_old_cset_regions() const { // The max old CSet region bound is based on the threshold expressed // as a percentage of the heap size. I.e., it should bound the // number of old regions added to the CSet irrespective of how many diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp index 8438935675ae..13b5ae1e719f 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -95,7 +95,7 @@ class G1Policy: public CHeapObj { // G1 allocation of new regions for eden is restrained when allocating into that reserve. // This intentionally slows down the allocation when the heap is close to full to allow // concurrent marking to finish and hopefully avoid a Full GC. - Atomic _reserve_regions; + Atomic _num_reserve_regions; G1YoungGenSizer _young_gen_sizer; @@ -251,15 +251,15 @@ class G1Policy: public CHeapObj { double predict_gc_efficiency(G1HeapRegion* hr); // The minimum number of retained regions we will add to the CSet during a young GC. - uint min_retained_old_cset_length() const; + uint min_num_retained_old_cset_regions() const; // Calculate the minimum number of old regions we'll add to the CSet // during a single mixed GC given the initial number of regions selected during // marking. - uint calc_min_old_cset_length(uint num_candidate_regions) const; + uint calc_min_num_old_cset_regions(uint num_candidate_regions) const; // Calculate the maximum number of old regions we'll add to the CSet // during a mixed GC. - uint calc_max_old_cset_length() const; + uint calc_max_num_old_cset_regions() const; private: void abandon_collection_set_candidates(); @@ -290,7 +290,7 @@ class G1Policy: public CHeapObj { void revise_target_num_young_regions(size_t pending_cards, size_t card_rs_length, size_t code_root_rs_length); // This should be called after the heap is resized. - void record_new_heap_size(uint new_number_of_regions); + void record_new_heap_size(uint new_num_regions); void init(G1CollectedHeap* g1h, G1CollectionSet* collection_set); @@ -401,11 +401,11 @@ class G1Policy: public CHeapObj { uint _tenuring_threshold; // The limit on the number of regions allocated for survivors. - uint _max_survivor_regions; + uint _max_num_survivor_regions; AgeTable _survivors_age_table; - size_t desired_survivor_size(uint max_regions) const; + size_t desired_survivor_size(uint max_num_regions) const; public: // Fraction used when predicting how many optional regions to include in @@ -422,8 +422,8 @@ class G1Policy: public CHeapObj { uint tenuring_threshold() const { return _tenuring_threshold; } - uint max_survivor_regions() { - return _max_survivor_regions; + uint max_num_survivor_regions() { + return _max_num_survivor_regions; } void start_adding_survivor_regions() { diff --git a/src/hotspot/share/gc/g1/g1RegionsOnNodes.cpp b/src/hotspot/share/gc/g1/g1RegionsOnNodes.cpp index fbe6ff588b80..16dd258450db 100644 --- a/src/hotspot/share/gc/g1/g1RegionsOnNodes.cpp +++ b/src/hotspot/share/gc/g1/g1RegionsOnNodes.cpp @@ -26,13 +26,13 @@ #include "gc/g1/g1NUMA.hpp" #include "gc/g1/g1RegionsOnNodes.hpp" -G1RegionsOnNodes::G1RegionsOnNodes() : _num_regions_per_node(nullptr), _numa(G1NUMA::numa()) { - _num_regions_per_node = NEW_C_HEAP_ARRAY(Atomic, _numa->num_active_nodes(), mtGC); +G1RegionsOnNodes::G1RegionsOnNodes() : _num_regions_on_node(nullptr), _numa(G1NUMA::numa()) { + _num_regions_on_node = NEW_C_HEAP_ARRAY(Atomic, _numa->num_active_nodes(), mtGC); clear(); } G1RegionsOnNodes::~G1RegionsOnNodes() { - FREE_C_HEAP_ARRAY(_num_regions_per_node); + FREE_C_HEAP_ARRAY(_num_regions_on_node); } void G1RegionsOnNodes::add(G1HeapRegion* hr) { @@ -40,14 +40,14 @@ void G1RegionsOnNodes::add(G1HeapRegion* hr) { // Update only if the node index is valid. if (node_index < _numa->num_active_nodes()) { - _num_regions_per_node[node_index].add_then_fetch(1u, memory_order_relaxed); + _num_regions_on_node[node_index].add_then_fetch(1u, memory_order_relaxed); } } void G1RegionsOnNodes::clear() { - ::new (_num_regions_per_node) Atomic[_numa->num_active_nodes()]{}; + ::new (_num_regions_on_node) Atomic[_numa->num_active_nodes()]{}; } -uint G1RegionsOnNodes::num_regions_per_node(uint node_index) const { - return _num_regions_per_node[node_index].load_relaxed(); +uint G1RegionsOnNodes::num_regions_on_node(uint node_index) const { + return _num_regions_on_node[node_index].load_relaxed(); } diff --git a/src/hotspot/share/gc/g1/g1RegionsOnNodes.hpp b/src/hotspot/share/gc/g1/g1RegionsOnNodes.hpp index a28c8b7e7161..24ae30a1c703 100644 --- a/src/hotspot/share/gc/g1/g1RegionsOnNodes.hpp +++ b/src/hotspot/share/gc/g1/g1RegionsOnNodes.hpp @@ -33,7 +33,7 @@ class G1HeapRegion; // Contains per node index region count class G1RegionsOnNodes : public StackObj { - Atomic* _num_regions_per_node; + Atomic* _num_regions_on_node; G1NUMA* _numa; public: @@ -46,7 +46,7 @@ class G1RegionsOnNodes : public StackObj { void clear(); - uint num_regions_per_node(uint node_index) const; + uint num_regions_on_node(uint node_index) const; }; #endif // SHARE_VM_GC_G1_G1REGIONS_HPP diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 5261d39e715e..294cd56f3733 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -1077,9 +1077,9 @@ class G1MergeHeapRootsTask : public WorkerTask { // remembered sets for this region. // We want to continue collecting remembered set entries for humongous regions // that were not reclaimed. - G1CSetCandidateGroup* group = r->rem_set()->cset_group(); - assert(group != nullptr, "must have a cset group"); - assert(group->length() == 1, "humongous regions cset group must have a single entry"); + G1CardSetGroup* group = r->rem_set()->card_set_group(); + assert(group != nullptr, "must have a card set group"); + assert(group->num_regions() == 1, "Card set groups containing humongous regions must have a single region"); group->clear_card_set(); } @@ -1148,7 +1148,7 @@ class G1MergeHeapRootsTask : public WorkerTask { // 2. collection set G1MergeCardSetClosure merge(_scan_state); - g1h->collection_set()->merge_cardsets_for_collection_groups(merge, worker_id, _num_workers); + g1h->collection_set()->merge_collection_set_card_set_groups(merge, worker_id, _num_workers); G1MergeCardSetStats stats = merge.stats(); @@ -1211,14 +1211,14 @@ void G1RemSet::merge_heap_roots(bool initial_evacuation) { { WorkerThreads* workers = g1h->workers(); - uint const num_groups_in_increment = g1h->collection_set()->num_groups_in_increment(); + uint const num_selected_groups_in_increment = g1h->collection_set()->num_selected_groups_in_increment(); uint const num_workers = initial_evacuation ? workers->active_workers() : - MIN2(workers->active_workers(), num_groups_in_increment); + MIN2(workers->active_workers(), num_selected_groups_in_increment); G1MergeHeapRootsTask cl(_scan_state, num_workers, initial_evacuation); - log_debug(gc, ergo)("Running %s using %u workers for %u groups", - cl.name(), num_workers, num_groups_in_increment); + log_debug(gc, ergo)("Running %s using %u workers for %u card set groups", + cl.name(), num_workers, num_selected_groups_in_increment); workers->run_task(&cl, num_workers); } diff --git a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp index 00682df647d2..46ae960bfdb4 100644 --- a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp +++ b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, 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 @@ -216,8 +216,8 @@ class G1HeapRegionStatsClosure: public G1HeapRegionClosure { size_t _max_code_root_mem_sz; G1HeapRegion* _max_code_root_mem_sz_region; - size_t _max_group_cardset_mem_sz; - G1CSetCandidateGroup* _max_cardset_mem_sz_group; + size_t _max_group_card_set_mem_sz; + G1CardSetGroup* _max_card_set_mem_sz_group; size_t total_rs_unused_mem_sz() const { return _all.rs_unused_mem_size(); } size_t total_rs_mem_sz() const { return _all.rs_mem_size(); } @@ -226,8 +226,8 @@ class G1HeapRegionStatsClosure: public G1HeapRegionClosure { size_t max_rs_mem_sz() const { return _max_rs_mem_sz; } G1HeapRegion* max_rs_mem_sz_region() const { return _max_rs_mem_sz_region; } - size_t max_group_cardset_mem_sz() const { return _max_group_cardset_mem_sz; } - G1CSetCandidateGroup* max_cardset_mem_sz_group() const { return _max_cardset_mem_sz_group; } + size_t max_group_card_set_mem_sz() const { return _max_group_card_set_mem_sz; } + G1CardSetGroup* max_card_set_mem_sz_group() const { return _max_card_set_mem_sz_group; } size_t total_code_root_mem_sz() const { return _all.code_root_mem_size(); } size_t total_code_root_elems() const { return _all.code_root_elems(); } @@ -240,7 +240,7 @@ class G1HeapRegionStatsClosure: public G1HeapRegionClosure { _free("Free"), _old("Old"), _all("All"), _max_rs_mem_sz(0), _max_rs_mem_sz_region(nullptr), _max_code_root_mem_sz(0), _max_code_root_mem_sz_region(nullptr), - _max_group_cardset_mem_sz(0), _max_cardset_mem_sz_group(nullptr) + _max_group_card_set_mem_sz(0), _max_card_set_mem_sz_group(nullptr) {} bool do_heap_region(G1HeapRegion* r) { @@ -249,10 +249,10 @@ class G1HeapRegionStatsClosure: public G1HeapRegionClosure { size_t rs_unused_mem_sz = 0; size_t occupied_cards = 0; - // Accumulate card set details for regions that are assigned to single region - // groups. G1HeapRegionRemSet::mem_size() includes the size of the code roots - if (hrrs->has_cset_group() && hrrs->cset_group()->length() == 1) { - G1CardSet* card_set = hrrs->cset_group()->card_set(); + // Accumulate card set details for regions that are assigned to single-region + // card set groups. G1HeapRegionRemSet::mem_size() includes the size of the code roots + if (hrrs->has_card_set_group() && hrrs->card_set_group()->num_regions() == 1) { + G1CardSet* card_set = hrrs->card_set_group()->card_set(); rs_mem_sz = hrrs->mem_size() + card_set->mem_size(); rs_unused_mem_sz = card_set->unused_mem_size(); @@ -291,19 +291,19 @@ class G1HeapRegionStatsClosure: public G1HeapRegionClosure { return false; } - void accumulate_stats_for_group(G1CSetCandidateGroup* group, G1PerRegionTypeRemSetCounters* gen_counter) { + void accumulate_stats_for_group(G1CardSetGroup* group, G1PerRegionTypeRemSetCounters* gen_counter) { // If the group has only a single region, then stats were accumulated // during region iteration. Skip these. - if (group->length() > 1) { + if (group->num_regions() > 1) { G1CardSet* card_set = group->card_set(); size_t rs_mem_sz = card_set->mem_size(); size_t rs_unused_mem_sz = card_set->unused_mem_size(); size_t occupied_cards = card_set->occupied(); - if (rs_mem_sz > _max_group_cardset_mem_sz) { - _max_group_cardset_mem_sz = rs_mem_sz; - _max_cardset_mem_sz_group = group; + if (rs_mem_sz > _max_group_card_set_mem_sz) { + _max_group_card_set_mem_sz = rs_mem_sz; + _max_card_set_mem_sz_group = group; } gen_counter->add(rs_unused_mem_sz, rs_mem_sz, occupied_cards, 0, 0, false); @@ -311,19 +311,19 @@ class G1HeapRegionStatsClosure: public G1HeapRegionClosure { } } - void do_cset_groups() { + void do_card_set_groups() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - accumulate_stats_for_group(g1h->young_regions_cset_group(), &_young); + accumulate_stats_for_group(g1h->young_regions_card_set_group(), &_young); G1CollectionSetCandidates* candidates = g1h->policy()->candidates(); - for (G1CSetCandidateGroup* group : candidates->from_marking_groups()) { + for (G1CardSetGroup* group : candidates->from_marking_groups()) { accumulate_stats_for_group(group, &_old); } // Skip gathering statistics for retained regions. Just verify that they have - // the expected amount of regions. - for (G1CSetCandidateGroup* group : candidates->retained_groups()) { - assert(group->length() == 1, "must be"); + // the expected number of regions. + for (G1CardSetGroup* group : candidates->retained_groups()) { + assert(group->num_regions() == 1, "must be"); } } @@ -356,13 +356,13 @@ class G1HeapRegionStatsClosure: public G1HeapRegionClosure { rem_set->occupied()); } - if (max_cardset_mem_sz_group() != nullptr) { - G1CSetCandidateGroup* cset_group = max_cardset_mem_sz_group(); - out->print_cr(" Collectionset Candidate Group with largest cardset = %u:(%u regions), " + if (max_card_set_mem_sz_group() != nullptr) { + G1CardSetGroup* card_set_group = max_card_set_mem_sz_group(); + out->print_cr(" Card Set Group with largest card set = %u:(%u regions), " "size = %zu occupied = %zu", - cset_group->group_id(), cset_group->length(), - cset_group->card_set()->mem_size(), - cset_group->card_set()->occupied()); + card_set_group->group_id(), card_set_group->num_regions(), + card_set_group->card_set()->mem_size(), + card_set_group->card_set()->occupied()); } G1HeapRegionRemSet::print_static_mem_size(out); @@ -408,6 +408,6 @@ void G1RemSetSummary::print_on(outputStream* out, bool show_thread_times) { } G1HeapRegionStatsClosure blk; G1CollectedHeap::heap()->heap_region_iterate(&blk); - blk.do_cset_groups(); + blk.do_card_set_groups(); blk.print_summary_on(out); } diff --git a/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp b/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp index 587ef2b6a12a..5bd508183f9c 100644 --- a/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp +++ b/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp @@ -102,10 +102,10 @@ void G1RemSetTrackingPolicy::update_after_rebuild(G1HeapRegion* r) { // cycle as e.g. remembered set entries will always be added. if (r->is_starts_humongous() && !g1h->is_potential_eager_reclaim_candidate(r)) { // Handle HC regions with the HS region. - G1CSetCandidateGroup* group = r->rem_set()->cset_group(); + G1CardSetGroup* group = r->rem_set()->card_set_group(); - assert(group != nullptr, "humongous start must have a cset group"); - assert(group->length() == 1, "humongous group must have only one region"); + assert(group != nullptr, "humongous start must have a card set group"); + assert(group->num_regions() == 1, "humongous group must have only one region"); group->clear_card_set(); g1h->humongous_obj_regions_iterate(r, @@ -118,10 +118,10 @@ void G1RemSetTrackingPolicy::update_after_rebuild(G1HeapRegion* r) { size_t remset_bytes = r->rem_set()->mem_size(); size_t occupied = 0; - // per region cardset details only valid if group contains a single region. - if (r->rem_set()->has_cset_group() && - r->rem_set()->cset_group()->length() == 1 ) { - G1CardSet *card_set = r->rem_set()->cset_group()->card_set(); + // Per-region card set group statistics are only valid if group contains a single region. + if (r->rem_set()->has_card_set_group() && + r->rem_set()->card_set_group()->num_regions() == 1 ) { + G1CardSet *card_set = r->rem_set()->card_set_group()->card_set(); remset_bytes += card_set->mem_size(); occupied = card_set->occupied(); } diff --git a/src/hotspot/share/gc/g1/g1Trace.cpp b/src/hotspot/share/gc/g1/g1Trace.cpp index bcc0941dc629..26faf40dee72 100644 --- a/src/hotspot/share/gc/g1/g1Trace.cpp +++ b/src/hotspot/share/gc/g1/g1Trace.cpp @@ -144,14 +144,14 @@ void G1NewTracer::send_evacuation_info_event(G1EvacInfo* info) { EventEvacuationInformation e; if (e.should_commit()) { e.set_gcId(GCId::current()); - e.set_cSetRegions(info->collection_set_regions()); + e.set_cSetRegions(info->num_collection_set_regions()); e.set_cSetUsedBefore(info->collection_set_used_before()); e.set_cSetUsedAfter(info->collection_set_used_after()); - e.set_allocationRegions(info->allocation_regions()); + e.set_allocationRegions(info->num_allocation_regions()); e.set_allocationRegionsUsedBefore(info->alloc_regions_used_before()); e.set_allocationRegionsUsedAfter(info->alloc_regions_used_before() + info->bytes_used()); e.set_bytesCopied(info->bytes_used()); - e.set_regionsFreed(info->regions_freed()); + e.set_regionsFreed(info->num_freed_regions()); e.commit(); } } @@ -181,7 +181,7 @@ create_g1_evacstats(unsigned gcid, const G1EvacSummary& summary) { s.set_used(summary.used() * HeapWordSize); s.set_undoWaste(summary.undo_wasted() * HeapWordSize); s.set_regionEndWaste(summary.region_end_waste() * HeapWordSize); - s.set_regionsRefilled(summary.regions_filled()); + s.set_regionsRefilled(summary.num_regions_filled()); s.set_directAllocated(summary.direct_allocated() * HeapWordSize); s.set_failureUsed(summary.failure_used() * HeapWordSize); s.set_failureWaste(summary.failure_waste() * HeapWordSize); diff --git a/src/hotspot/share/gc/g1/g1UncommitRegionTask.cpp b/src/hotspot/share/gc/g1/g1UncommitRegionTask.cpp index f88736c5642f..a93c3ef275cc 100644 --- a/src/hotspot/share/gc/g1/g1UncommitRegionTask.cpp +++ b/src/hotspot/share/gc/g1/g1UncommitRegionTask.cpp @@ -34,7 +34,7 @@ G1UncommitRegionTask::G1UncommitRegionTask() : G1ServiceTask("G1 Uncommit Region Task"), _active(false), _summary_duration(), - _summary_region_count(0) { } + _summary_num_regions(0) { } void G1UncommitRegionTask::initialize() { assert(_instance == nullptr, "Already initialized"); @@ -77,28 +77,28 @@ void G1UncommitRegionTask::set_active(bool state) { _active = state; } -void G1UncommitRegionTask::report_execution(Tickspan time, uint regions) { - _summary_region_count += regions; - _summary_duration += time; +void G1UncommitRegionTask::report_execution(Tickspan uncommit_time, uint num_uncommitted_regions) { + _summary_num_regions += num_uncommitted_regions; + _summary_duration += uncommit_time; log_trace(gc, heap)("Concurrent Uncommit: %zu%s, %u regions, %1.3fms", - byte_size_in_proper_unit(regions * G1HeapRegion::GrainBytes), - proper_unit_for_byte_size(regions * G1HeapRegion::GrainBytes), - regions, - time.seconds() * 1000); + byte_size_in_proper_unit(num_uncommitted_regions * G1HeapRegion::GrainBytes), + proper_unit_for_byte_size(num_uncommitted_regions * G1HeapRegion::GrainBytes), + num_uncommitted_regions, + uncommit_time.seconds() * 1000); } void G1UncommitRegionTask::report_summary() { log_debug(gc, heap)("Concurrent Uncommit Summary: %zu%s, %u regions, %1.3fms", - byte_size_in_proper_unit(_summary_region_count * G1HeapRegion::GrainBytes), - proper_unit_for_byte_size(_summary_region_count * G1HeapRegion::GrainBytes), - _summary_region_count, + byte_size_in_proper_unit(_summary_num_regions * G1HeapRegion::GrainBytes), + proper_unit_for_byte_size(_summary_num_regions * G1HeapRegion::GrainBytes), + _summary_num_regions, _summary_duration.seconds() * 1000); } void G1UncommitRegionTask::clear_summary() { _summary_duration = Tickspan(); - _summary_region_count = 0; + _summary_num_regions = 0; } void G1UncommitRegionTask::execute() { @@ -106,18 +106,18 @@ void G1UncommitRegionTask::execute() { // Translate the size limit into a number of regions. This cannot be a // compile time constant because G1HeapRegionSize is set ergonomically. - static const uint region_limit = (uint) (UncommitSizeLimit / G1HeapRegionSize); + static const uint max_num_regions_to_uncommit = (uint)(UncommitSizeLimit / G1HeapRegionSize); // Prevent from running during a GC pause. SuspendibleThreadSetJoiner sts; G1CollectedHeap* g1h = G1CollectedHeap::heap(); Ticks start = Ticks::now(); - uint uncommit_count = g1h->uncommit_regions(region_limit); + uint num_uncommitted_regions = g1h->uncommit_regions(max_num_regions_to_uncommit); Tickspan uncommit_time = (Ticks::now() - start); - if (uncommit_count > 0) { - report_execution(uncommit_time, uncommit_count); + if (num_uncommitted_regions > 0) { + report_execution(uncommit_time, num_uncommitted_regions); } // Reschedule if there are more regions to uncommit, otherwise diff --git a/src/hotspot/share/gc/g1/g1UncommitRegionTask.hpp b/src/hotspot/share/gc/g1/g1UncommitRegionTask.hpp index 835217d2a595..2de91a3c5149 100644 --- a/src/hotspot/share/gc/g1/g1UncommitRegionTask.hpp +++ b/src/hotspot/share/gc/g1/g1UncommitRegionTask.hpp @@ -49,13 +49,13 @@ class G1UncommitRegionTask : public G1ServiceTask { // Members to keep a summary of the current concurrent uncommit // work. Used for printing when no more work is available. Tickspan _summary_duration; - uint _summary_region_count; + uint _summary_num_regions; G1UncommitRegionTask(); bool is_active(); void set_active(bool state); - void report_execution(Tickspan time, uint regions); + void report_execution(Tickspan uncommit_time, uint num_uncommitted_regions); void report_summary(); void clear_summary(); diff --git a/src/hotspot/share/gc/g1/g1VMOperations.cpp b/src/hotspot/share/gc/g1/g1VMOperations.cpp index 577f3b5491d9..bb51be1aee89 100644 --- a/src/hotspot/share/gc/g1/g1VMOperations.cpp +++ b/src/hotspot/share/gc/g1/g1VMOperations.cpp @@ -114,10 +114,12 @@ void VM_G1TryInitiateConcMark::doit() { } } -VM_G1CollectForAllocation::VM_G1CollectForAllocation(size_t word_size, +VM_G1CollectForAllocation::VM_G1CollectForAllocation(uint node_index, + size_t word_size, uint gc_count_before, GCCause::Cause gc_cause) : - VM_CollectForAllocation(word_size, gc_count_before, gc_cause) {} + VM_CollectForAllocation(word_size, gc_count_before, gc_cause), + _node_index(node_index) {} void VM_G1CollectForAllocation::doit() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); @@ -128,7 +130,7 @@ void VM_G1CollectForAllocation::doit() { if (_word_size > 0) { // An allocation had been requested. Do it, eventually trying a stronger // kind of GC. - _result = g1h->satisfy_failed_allocation(_word_size); + _result = g1h->satisfy_failed_allocation(_node_index, _word_size); } else if (g1h->should_upgrade_to_full_gc()) { // There has been a request to perform a GC to free some space. We have no // information on how much memory has been asked for. In case there are diff --git a/src/hotspot/share/gc/g1/g1VMOperations.hpp b/src/hotspot/share/gc/g1/g1VMOperations.hpp index 0c12e75eef08..beaacaaea1d1 100644 --- a/src/hotspot/share/gc/g1/g1VMOperations.hpp +++ b/src/hotspot/share/gc/g1/g1VMOperations.hpp @@ -68,9 +68,11 @@ class VM_G1TryInitiateConcMark : public VM_GC_Collect_Operation { }; class VM_G1CollectForAllocation : public VM_CollectForAllocation { + const uint _node_index; public: - VM_G1CollectForAllocation(size_t word_size, + VM_G1CollectForAllocation(uint node_index, + size_t word_size, uint gc_count_before, GCCause::Cause gc_cause); virtual VMOp_Type type() const { return VMOp_G1CollectForAllocation; } diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index f8137a162016..ac10c2e94681 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -260,7 +260,7 @@ void G1YoungCollector::calculate_collection_set(G1EvacInfo* evacuation_info, dou allocator()->release_mutator_alloc_regions(); collection_set()->finalize_initial_collection_set(target_pause_time_ms, survivor_regions()); - evacuation_info->set_collection_set_regions(collection_set()->num_initial_regions() + + evacuation_info->set_num_collection_set_regions(collection_set()->num_initial_regions() + collection_set()->num_optional_regions()); concurrent_mark()->verify_no_collection_set_oops(); @@ -556,7 +556,7 @@ void G1YoungCollector::pre_evacuate_collection_set(G1EvacInfo* evacuation_info) Tickspan task_time = run_task_timed(&g1_prep_task); G1MonotonicArenaMemoryStats sampled_card_set_stats = g1_prep_task.all_card_set_stats(); - sampled_card_set_stats.add(_g1h->young_regions_cset_group()->card_set_memory_stats()); + sampled_card_set_stats.add(_g1h->young_regions_card_set_group()->card_set_memory_stats()); _g1h->set_young_gen_card_set_stats(sampled_card_set_stats); _g1h->set_humongous_stats(g1_prep_task.humongous_total(), g1_prep_task.humongous_candidates()); @@ -1084,15 +1084,15 @@ void G1YoungCollector::post_evacuate_collection_set(G1EvacInfo* evacuation_info, } bool G1YoungCollector::evacuation_failed() const { - return _evac_failure_regions.has_regions_evac_failed(); + return _evac_failure_regions.has_evac_failed_regions(); } bool G1YoungCollector::evacuation_pinned() const { - return _evac_failure_regions.has_regions_evac_pinned(); + return _evac_failure_regions.has_evac_pinned_regions(); } bool G1YoungCollector::evacuation_alloc_failed() const { - return _evac_failure_regions.has_regions_alloc_failed(); + return _evac_failure_regions.has_alloc_failed_regions(); } G1YoungCollector::G1YoungCollector(GCCause::Cause gc_cause, diff --git a/src/hotspot/share/gc/g1/g1YoungGCAllocationFailureInjector.cpp b/src/hotspot/share/gc/g1/g1YoungGCAllocationFailureInjector.cpp index 0d922c0a3eda..01e472f77ea0 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCAllocationFailureInjector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCAllocationFailureInjector.cpp @@ -31,20 +31,20 @@ class SelectAllocationFailureRegionClosure : public G1HeapRegionClosure { CHeapBitMap& _allocation_failure_regions; - size_t _allocation_failure_regions_num; + size_t _num_allocation_failure_regions; public: - SelectAllocationFailureRegionClosure(CHeapBitMap& allocation_failure_regions, size_t cset_length) : + SelectAllocationFailureRegionClosure(CHeapBitMap& allocation_failure_regions, size_t num_cset_regions) : _allocation_failure_regions(allocation_failure_regions), - _allocation_failure_regions_num(cset_length * G1GCAllocationFailureALotCSetPercent / 100) { } + _num_allocation_failure_regions(num_cset_regions * G1GCAllocationFailureALotCSetPercent / 100) { } bool do_heap_region(G1HeapRegion* r) override { assert(r->in_collection_set(), "must be"); - if (_allocation_failure_regions_num > 0) { + if (_num_allocation_failure_regions > 0) { _allocation_failure_regions.set_bit(r->hrm_index()); - --_allocation_failure_regions_num; + --_num_allocation_failure_regions; } - return _allocation_failure_regions_num == 0; + return _num_allocation_failure_regions == 0; } }; diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index 6207480a50e1..5fbc56ceb315 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -108,11 +108,11 @@ class G1PostEvacuateCollectionSetCleanupTask1::SampleCollectionSetCandidatesTask G1MonotonicArenaMemoryStats _total; G1CollectionSetCandidates* candidates = g1h->collection_set()->candidates(); - for (G1CSetCandidateGroup* gr : candidates->from_marking_groups()) { + for (G1CardSetGroup* gr : candidates->from_marking_groups()) { _total.add(gr->card_set_memory_stats()); } - for (G1CSetCandidateGroup* gr : candidates->retained_groups()) { + for (G1CardSetGroup* gr : candidates->retained_groups()) { _total.add(gr->card_set_memory_stats()); } g1h->set_collection_set_candidates_stats(_total); @@ -133,10 +133,10 @@ class G1PostEvacuateCollectionSetCleanupTask1::UpdateCodeRootsTask // Add code roots serially to avoid lock and resize contention. void do_work(uint worker_id) override { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - uint max_regions = g1h->max_num_regions(); + uint max_num_regions = g1h->max_num_regions(); - uint* counts = NEW_C_HEAP_ARRAY(uint, max_regions, mtGC); - memset(counts, 0, max_regions * sizeof(uint)); + uint* counts = NEW_C_HEAP_ARRAY(uint, max_num_regions, mtGC); + memset(counts, 0, max_num_regions * sizeof(uint)); // Pass 1: count the number of nmethods to add per region across all workers. for (uint i = 0; i < _psss->num_workers(); i++) { @@ -176,7 +176,7 @@ class G1PostEvacuateCollectionSetCleanupTask1::RestoreEvacFailureRegionsTask : p CHeapBitMap _chunk_bitmap; uint _num_chunks_per_region; - uint _num_evac_fail_regions; + uint _num_evac_failed_regions; size_t _chunk_size; class PhaseTimesStat { @@ -337,7 +337,7 @@ class G1PostEvacuateCollectionSetCleanupTask1::RestoreEvacFailureRegionsTask : p _evac_failure_regions(evac_failure_regions), _chunk_bitmap(mtGC) { - _num_evac_fail_regions = _evac_failure_regions->num_regions_evac_failed(); + _num_evac_failed_regions = _evac_failure_regions->num_evac_failed_regions(); _num_chunks_per_region = G1CollectedHeap::get_chunks_per_region_for_scan(); _chunk_size = static_cast(G1HeapRegion::GrainWords / _num_chunks_per_region); @@ -345,19 +345,19 @@ class G1PostEvacuateCollectionSetCleanupTask1::RestoreEvacFailureRegionsTask : p log_debug(gc, ergo)("Initializing removing self forwards with %u chunks per region", _num_chunks_per_region); - _chunk_bitmap.resize(_num_chunks_per_region * _num_evac_fail_regions); + _chunk_bitmap.resize(_num_chunks_per_region * _num_evac_failed_regions); } double worker_cost() const override { - assert(_evac_failure_regions->has_regions_evac_failed(), "Should not call this if there were no evacuation failures"); + assert(_evac_failure_regions->has_evac_failed_regions(), "Should not call this if there were no evacuation failures"); double workers_per_region = (double)G1CollectedHeap::get_chunks_per_region_for_scan() / G1RestoreRetainedRegionChunksPerWorker; - return workers_per_region * _evac_failure_regions->num_regions_evac_failed(); + return workers_per_region * _evac_failure_regions->num_evac_failed_regions(); } void do_work(uint worker_id) override { const uint total_workers = G1CollectedHeap::heap()->workers()->active_workers(); - const uint total_chunks = _num_chunks_per_region * _num_evac_fail_regions; + const uint total_chunks = _num_chunks_per_region * _num_evac_failed_regions; const uint start_chunk_idx = worker_id * total_chunks / total_workers; for (uint i = 0; i < total_chunks; i++) { @@ -373,8 +373,8 @@ G1PostEvacuateCollectionSetCleanupTask1::G1PostEvacuateCollectionSetCleanupTask1 G1EvacFailureRegions* evac_failure_regions) : G1BatchedTask("Post Evacuate Cleanup 1", G1CollectedHeap::heap()->phase_times()) { - bool evac_failed = evac_failure_regions->has_regions_evac_failed(); - bool alloc_failed = evac_failure_regions->has_regions_alloc_failed(); + bool evac_failed = evac_failure_regions->has_evac_failed_regions(); + bool alloc_failed = evac_failure_regions->has_alloc_failed_regions(); add_serial_task(new FlushPssTask(per_thread_states)); add_serial_task(new RecalculateUsedTask(evac_failed, alloc_failed)); @@ -390,8 +390,8 @@ G1PostEvacuateCollectionSetCleanupTask1::G1PostEvacuateCollectionSetCleanupTask1 } class G1FreeHumongousRegionClosure : public G1HeapRegionIndexClosure { - uint _humongous_objects_reclaimed; - uint _humongous_regions_reclaimed; + uint _num_humongous_objects_reclaimed; + uint _num_humongous_regions_reclaimed; size_t _freed_bytes; G1CollectedHeap* _g1h; @@ -429,8 +429,8 @@ class G1FreeHumongousRegionClosure : public G1HeapRegionIndexClosure { public: G1FreeHumongousRegionClosure() : - _humongous_objects_reclaimed(0), - _humongous_regions_reclaimed(0), + _num_humongous_objects_reclaimed(0), + _num_humongous_regions_reclaimed(0), _freed_bytes(0), _g1h(G1CollectedHeap::heap()) {} @@ -469,12 +469,12 @@ class G1FreeHumongousRegionClosure : public G1HeapRegionIndexClosure { "Eagerly reclaimed humongous region %u should not be marked at all but is in bitmap %s", region_index, BOOL_TO_STR(cm->is_marked_in_bitmap(obj))); - _humongous_objects_reclaimed++; + _num_humongous_objects_reclaimed++; auto free_humongous_region = [&] (G1HeapRegion* r) { _freed_bytes += r->used(); r->set_containing_set(nullptr); - _humongous_regions_reclaimed++; + _num_humongous_regions_reclaimed++; G1HeapRegionPrinter::eager_reclaim(r); // Humongous non-typeArrays may have dirty card tables. Need to be cleared. Do it // for all types just in case. @@ -487,12 +487,12 @@ class G1FreeHumongousRegionClosure : public G1HeapRegionIndexClosure { return false; } - uint humongous_objects_reclaimed() { - return _humongous_objects_reclaimed; + uint num_humongous_objects_reclaimed() { + return _num_humongous_objects_reclaimed; } - uint humongous_regions_reclaimed() { - return _humongous_regions_reclaimed; + uint num_humongous_regions_reclaimed() { + return _num_humongous_regions_reclaimed; } size_t bytes_freed() const { @@ -536,9 +536,9 @@ class G1PostEvacuateCollectionSetCleanupTask2::EagerlyReclaimHumongousObjectsTas record_work_item(worker_id, G1GCPhaseTimes::EagerlyReclaimNumTotal, g1h->num_humongous_objects()); record_work_item(worker_id, G1GCPhaseTimes::EagerlyReclaimNumCandidates, g1h->num_humongous_reclaim_candidates()); - record_work_item(worker_id, G1GCPhaseTimes::EagerlyReclaimNumReclaimed, cl.humongous_objects_reclaimed()); + record_work_item(worker_id, G1GCPhaseTimes::EagerlyReclaimNumReclaimed, cl.num_humongous_objects_reclaimed()); - _humongous_regions_reclaimed = cl.humongous_regions_reclaimed(); + _humongous_regions_reclaimed = cl.num_humongous_regions_reclaimed(); _bytes_freed = cl.bytes_freed(); } }; @@ -583,11 +583,11 @@ class G1PostEvacuateCollectionSetCleanupTask2::ProcessEvacuationFailedRegionsTas } void set_max_workers(uint max_workers) override { - _claimer.set_n_workers(max_workers); + _claimer.set_num_workers(max_workers); } double worker_cost() const override { - return _evac_failure_regions->num_regions_evac_failed(); + return _evac_failure_regions->num_evac_failed_regions(); } void do_work(uint worker_id) override { @@ -603,7 +603,7 @@ class FreeCSetStats { size_t _bytes_allocated_in_old_since_last_pause; // Size of young regions turned into old size_t _failure_used_words; // Live size in failed regions size_t _failure_waste_words; // Wasted size in failed regions - uint _regions_freed; // Number of regions freed + uint _num_regions_freed; // Number of regions freed public: FreeCSetStats() : @@ -612,7 +612,7 @@ class FreeCSetStats { _bytes_allocated_in_old_since_last_pause(0), _failure_used_words(0), _failure_waste_words(0), - _regions_freed(0) { } + _num_regions_freed(0) { } void merge_stats(FreeCSetStats* other) { assert(other != nullptr, "invariant"); @@ -621,11 +621,11 @@ class FreeCSetStats { _bytes_allocated_in_old_since_last_pause += other->_bytes_allocated_in_old_since_last_pause; _failure_used_words += other->_failure_used_words; _failure_waste_words += other->_failure_waste_words; - _regions_freed += other->_regions_freed; + _num_regions_freed += other->_num_regions_freed; } void report(G1CollectedHeap* g1h, G1EvacInfo* evacuation_info) { - evacuation_info->set_regions_freed(_regions_freed); + evacuation_info->add_to_num_freed_regions(_num_regions_freed); evacuation_info->set_collection_set_used_before(_before_used_bytes + _after_used_bytes); evacuation_info->increment_collection_set_used_after(_after_used_bytes); @@ -658,7 +658,7 @@ class FreeCSetStats { size_t used = r->used(); assert(used > 0, "region %u %s zero used", r->hrm_index(), r->get_short_type_str()); _before_used_bytes += used; - _regions_freed += 1; + _num_regions_freed += 1; } }; @@ -804,7 +804,7 @@ class FreeCSetClosure : public G1HeapRegionClosure { } } - bool num_retained_regions() const { return _num_retained_regions; } + uint num_retained_regions() const { return _num_retained_regions; } }; class G1PostEvacuateCollectionSetCleanupTask2::FreeCollectionSetTask : public G1AbstractSubTask { @@ -874,7 +874,7 @@ class G1PostEvacuateCollectionSetCleanupTask2::FreeCollectionSetTask : public G1 _active_workers = max_workers; _worker_stats = NEW_C_HEAP_ARRAY(FreeCSetStats, max_workers, mtGC); ::new (_worker_stats) FreeCSetStats[_active_workers]{}; - _claimer.set_n_workers(_active_workers); + _claimer.set_num_workers(_active_workers); } void do_work(uint worker_id) override { @@ -952,7 +952,7 @@ G1PostEvacuateCollectionSetCleanupTask2::G1PostEvacuateCollectionSetCleanupTask2 } add_serial_task(new DestroyPssTask(per_thread_states)); - if (evac_failure_regions->has_regions_evac_failed()) { + if (evac_failure_regions->has_evac_failed_regions()) { add_parallel_task(new ProcessEvacuationFailedRegionsTask(evac_failure_regions)); } diff --git a/src/hotspot/share/gc/g1/g1YoungGenSizer.cpp b/src/hotspot/share/gc/g1/g1YoungGenSizer.cpp index e817ebcab56f..df8838bcd974 100644 --- a/src/hotspot/share/gc/g1/g1YoungGenSizer.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGenSizer.cpp @@ -118,37 +118,37 @@ G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), } } -uint G1YoungGenSizer::calculate_default_min_num_regions(uint new_number_of_heap_regions) { - uint default_value = (new_number_of_heap_regions * G1NewSizePercent) / 100; +uint G1YoungGenSizer::calculate_default_min_num_regions(uint new_num_regions) { + uint default_value = (new_num_regions * G1NewSizePercent) / 100; return MAX2(1U, default_value); } -uint G1YoungGenSizer::calculate_default_max_num_regions(uint new_number_of_heap_regions) { - uint default_value = (new_number_of_heap_regions * G1MaxNewSizePercent) / 100; +uint G1YoungGenSizer::calculate_default_max_num_regions(uint new_num_regions) { + uint default_value = (new_num_regions * G1MaxNewSizePercent) / 100; return MAX2(1U, default_value); } -void G1YoungGenSizer::recalculate_min_max_num_regions(uint number_of_heap_regions, uint* min_num_young_regions, uint* max_num_young_regions) { - assert(number_of_heap_regions > 0, "Heap must be initialized"); +void G1YoungGenSizer::recalculate_min_max_num_regions(uint num_regions, uint* min_num_young_regions, uint* max_num_young_regions) { + assert(num_regions > 0, "Heap must be initialized"); switch (_sizer_kind) { case SizerDefaults: - *min_num_young_regions = calculate_default_min_num_regions(number_of_heap_regions); - *max_num_young_regions = calculate_default_max_num_regions(number_of_heap_regions); + *min_num_young_regions = calculate_default_min_num_regions(num_regions); + *max_num_young_regions = calculate_default_max_num_regions(num_regions); break; case SizerNewSizeOnly: - *max_num_young_regions = calculate_default_max_num_regions(number_of_heap_regions); + *max_num_young_regions = calculate_default_max_num_regions(num_regions); *max_num_young_regions = MAX2(*min_num_young_regions, *max_num_young_regions); break; case SizerMaxNewSizeOnly: - *min_num_young_regions = calculate_default_min_num_regions(number_of_heap_regions); + *min_num_young_regions = calculate_default_min_num_regions(num_regions); *min_num_young_regions = MIN2(*min_num_young_regions, *max_num_young_regions); break; case SizerMaxAndNewSize: // Do nothing. Values set on the command line, don't update them at runtime. break; case SizerNewRatio: - *min_num_young_regions = MAX2((uint)(number_of_heap_regions / (NewRatio + 1)), 1u); + *min_num_young_regions = MAX2((uint)(num_regions / (NewRatio + 1)), 1u); *max_num_young_regions = *min_num_young_regions; break; default: @@ -158,12 +158,12 @@ void G1YoungGenSizer::recalculate_min_max_num_regions(uint number_of_heap_region assert(*min_num_young_regions <= *max_num_young_regions, "Invalid min/max young gen size values"); } -void G1YoungGenSizer::adjust_max_new_size(uint number_of_heap_regions) { +void G1YoungGenSizer::adjust_max_new_size(uint num_regions) { // We need to pass the desired values because recalculation may not update these // values in some cases. uint unused_new_min = min_desired_num_regions(); uint new_max = max_desired_num_regions(); - recalculate_min_max_num_regions(number_of_heap_regions, &unused_new_min, &new_max); + recalculate_min_max_num_regions(num_regions, &unused_new_min, &new_max); size_t max_young_size = new_max * G1HeapRegion::GrainBytes; if (max_young_size != MaxNewSize) { @@ -171,10 +171,10 @@ void G1YoungGenSizer::adjust_max_new_size(uint number_of_heap_regions) { } } -void G1YoungGenSizer::heap_size_changed(uint new_number_of_heap_regions) { +void G1YoungGenSizer::heap_size_changed(uint new_num_regions) { uint min = min_desired_num_regions(); uint max = max_desired_num_regions(); - recalculate_min_max_num_regions(new_number_of_heap_regions, &min, &max); + recalculate_min_max_num_regions(new_num_regions, &min, &max); _min_desired_num_regions.store_relaxed(min); _max_desired_num_regions.store_relaxed(max); } diff --git a/src/hotspot/share/gc/g1/g1YoungGenSizer.hpp b/src/hotspot/share/gc/g1/g1YoungGenSizer.hpp index ea269f72559f..653460ab0e35 100644 --- a/src/hotspot/share/gc/g1/g1YoungGenSizer.hpp +++ b/src/hotspot/share/gc/g1/g1YoungGenSizer.hpp @@ -82,20 +82,20 @@ class G1YoungGenSizer { Atomic _min_desired_num_regions; Atomic _max_desired_num_regions; - uint calculate_default_min_num_regions(uint new_number_of_heap_regions); - uint calculate_default_max_num_regions(uint new_number_of_heap_regions); + uint calculate_default_min_num_regions(uint new_num_regions); + uint calculate_default_max_num_regions(uint new_num_regions); // Recalculate the minimum and maximum number of young regions for the // given number of heap regions according to the current sizing algorithm. - void recalculate_min_max_num_regions(uint number_of_heap_regions, uint* min_num_young_regions, uint* max_num_young_regions); + void recalculate_min_max_num_regions(uint num_regions, uint* min_num_young_regions, uint* max_num_young_regions); public: G1YoungGenSizer(); // Calculate the maximum size of the young gen given the number of regions // depending on the sizing algorithm. - virtual void adjust_max_new_size(uint number_of_heap_regions); + virtual void adjust_max_new_size(uint num_regions); - virtual void heap_size_changed(uint new_number_of_heap_regions); + virtual void heap_size_changed(uint new_num_regions); uint min_desired_num_regions() const { return _min_desired_num_regions.load_relaxed(); } diff --git a/src/hotspot/share/gc/g1/g1YoungRegions.hpp b/src/hotspot/share/gc/g1/g1YoungRegions.hpp index 7d40e4c0a412..b6cb2866723f 100644 --- a/src/hotspot/share/gc/g1/g1YoungRegions.hpp +++ b/src/hotspot/share/gc/g1/g1YoungRegions.hpp @@ -46,8 +46,8 @@ class G1YoungRegions { NONCOPYABLE(G1YoungRegions); public: - uint regions_on_node(uint node_index) const { - return _regions_on_node.num_regions_per_node(node_index); + uint num_regions_on_node(uint node_index) const { + return _regions_on_node.num_regions_on_node(node_index); } void add_used_bytes(size_t used_bytes) { _used_bytes.add_then_fetch(used_bytes, memory_order_relaxed); } diff --git a/src/hotspot/share/gc/g1/g1_globals.hpp b/src/hotspot/share/gc/g1/g1_globals.hpp index 9860e47adc16..0164a18971a6 100644 --- a/src/hotspot/share/gc/g1/g1_globals.hpp +++ b/src/hotspot/share/gc/g1/g1_globals.hpp @@ -316,16 +316,16 @@ "Chunk size used for rebuilding the remembered set.") \ range(4 * K, 32 * M) \ \ - product(uint, G1OldCSetRegionThresholdPercent, 10, EXPERIMENTAL, \ + product(uint, G1OldCSetRegionThresholdPercent, 10, EXPERIMENTAL, \ "An upper bound for the number of old CSet regions expressed " \ "as a percentage of the heap size.") \ range(0, 100) \ \ - product(uint, G1OldCSetGroupSize, 5, EXPERIMENTAL, \ - "The maximum number of old CSet regions in a collection group. " \ - "All regions in a group will be evacuated in the same GC pause." \ - "The first group calculated after marking from marking " \ - "candidates may exceed this limit as it is calculated based on " \ + product(uint, G1OldCardSetGroupSize, 5, EXPERIMENTAL, \ + "The maximum number of old regions in a card set group. " \ + "All regions in a group will be evacuated in the same GC pause. " \ + "The first group calculated in the concurrent cycle " \ + "may exceed this limit as it is calculated based on " \ "G1MixedGCCountTarget.") \ range(1, 256) \ \ @@ -392,8 +392,8 @@ develop(bool, G1ForceOptionalEvacuation, false, \ "Force optional evacuation for all GCs where there are old gen " \ "collection set candidates." \ - "Also schedule all available optional groups for evacuation " \ - "regardless of timing.") \ + "Also schedule all available optional card set groups for " \ + "evacuation regardless of timing.") \ \ GC_G1_EVACUATION_FAILURE_FLAGS(develop, \ develop_pd, \ diff --git a/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp b/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp index ca4e77bab8ec..5b402029c2d6 100644 --- a/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp +++ b/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp @@ -40,6 +40,7 @@ #include "utilities/globalDefinitions.hpp" MutableNUMASpace::MutableNUMASpace(size_t page_size) : MutableSpace(page_size) { + _all_lgrp_spaces = new (mtGC) GrowableArray(0, mtGC); _lgrp_spaces = new (mtGC) GrowableArray(0, mtGC); _adaptation_cycles = 0; _samples_count = 0; @@ -49,22 +50,45 @@ MutableNUMASpace::MutableNUMASpace(size_t page_size) : MutableSpace(page_size) { size_t lgrp_num = os::numa_get_leaf_groups(lgrp_ids, lgrp_limit); assert(lgrp_num > 0, "There should be at least one locality group"); + all_lgrp_spaces()->reserve(checked_cast(lgrp_num)); lgrp_spaces()->reserve(checked_cast(lgrp_num)); - // Add new spaces for the new nodes for (size_t i = 0; i < lgrp_num; i++) { - lgrp_spaces()->append(new LGRPSpace(lgrp_ids[i], page_size)); + LGRPSpace* lgrp_space = new LGRPSpace(lgrp_ids[i], page_size); + all_lgrp_spaces()->append(lgrp_space); } + update_active_lgrp_spaces(all_lgrp_spaces(), lgrp_spaces(), + lgrp_num * page_size, page_size); FREE_C_HEAP_ARRAY(lgrp_ids); } MutableNUMASpace::~MutableNUMASpace() { - for (int i = 0; i < lgrp_spaces()->length(); i++) { - delete lgrp_spaces()->at(i); + for (LGRPSpace* lgrp_space : *all_lgrp_spaces()) { + delete lgrp_space; } + delete all_lgrp_spaces(); delete lgrp_spaces(); } +int MutableNUMASpace::update_active_lgrp_spaces(GrowableArray* all_lgrp_spaces, + GrowableArray* active_lgrp_spaces, + size_t region_size, + size_t page_size) { + assert(all_lgrp_spaces->length() > 0, "precondition"); + const size_t num_pages = region_size / page_size; + const int num_active_lgrps = checked_cast(region_size == 0 + ? 1 + : MIN2(num_pages, (size_t)all_lgrp_spaces->length())); + + if (active_lgrp_spaces->length() != num_active_lgrps) { + active_lgrp_spaces->clear(); + for (int i = 0; i < num_active_lgrps; i++) { + active_lgrp_spaces->append(all_lgrp_spaces->at(i)); + } + } + return num_active_lgrps; +} + #ifndef PRODUCT void MutableNUMASpace::mangle_unused_area() { // This method should do nothing. @@ -296,14 +320,26 @@ void MutableNUMASpace::initialize(MemRegion mr, // Must always clear the space clear(SpaceDecorator::DontMangle); - size_t num_pages = mr.byte_size() / page_size(); - - if (num_pages < (size_t)lgrp_spaces()->length()) { - log_warning(gc)("Degraded NUMA config: #os-pages (%zu) < #CPU (%d); space-size: %zu, page-size: %zu", - num_pages, lgrp_spaces()->length(), mr.byte_size(), page_size()); + const size_t num_pages = mr.byte_size() / page_size(); + const int previous_num_active_lgrps = lgrp_spaces()->length(); + const int num_active_lgrps = update_active_lgrp_spaces(all_lgrp_spaces(), lgrp_spaces(), + mr.byte_size(), page_size()); + if (previous_num_active_lgrps != num_active_lgrps) { + if (!mr.is_empty() && num_pages < (size_t)all_lgrp_spaces()->length()) { + log_warning(gc)("Degraded NUMA config: #os-pages (%zu) < #lgrp (%d); space-size: %zu, page-size: %zu", + num_pages, all_lgrp_spaces()->length(), mr.byte_size(), page_size()); + } - // Keep only the first few CPUs. - lgrp_spaces()->trunc_to((int)num_pages); + // Inactive spaces must not retain regions that may temporarily belong to old gen. + const MemRegion empty_region(mr.start(), mr.start()); + for (int i = num_active_lgrps; i < all_lgrp_spaces()->length(); i++) { + all_lgrp_spaces()->at(i)->space()->initialize(empty_region, + SpaceDecorator::Clear, + SpaceDecorator::DontMangle, + MutableSpace::DontSetupPages); + } + log_debug(gc, heap)("NUMA eden locality groups: %d -> %d", + previous_num_active_lgrps, num_active_lgrps); } // Handle space resize @@ -322,8 +358,9 @@ void MutableNUMASpace::initialize(MemRegion mr, // Check if the space layout has changed significantly? // This happens when the space has been resized so that either head or tail // chunk became less than a page. - bool layout_valid = UseAdaptiveNUMAChunkSizing && - current_chunk_size(0) > page_size() && + bool layout_valid = UseAdaptiveNUMAChunkSizing && + previous_num_active_lgrps == num_active_lgrps && + current_chunk_size(0) > page_size() && current_chunk_size(lgrp_spaces()->length() - 1) > page_size(); diff --git a/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp b/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp index 36de38c34bb9..9f0088d4da1e 100644 --- a/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp +++ b/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2026, 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 @@ -61,6 +61,8 @@ */ class MutableNUMASpace : public MutableSpace { + friend class MutableNUMASpaceTest_reactivate_vm_Test; + class LGRPSpace : public CHeapObj { uint _lgrp_id; MutableSpace* _space; @@ -117,6 +119,9 @@ class MutableNUMASpace : public MutableSpace { void accumulate_statistics(size_t page_size); }; + // The discovered topology is stable for the lifetime of this space. The + // active view may shrink and grow as eden crosses NUMA page-count limits. + GrowableArray* _all_lgrp_spaces; GrowableArray* _lgrp_spaces; unsigned _adaptation_cycles, _samples_count; @@ -143,6 +148,12 @@ class MutableNUMASpace : public MutableSpace { LGRPSpace *lgrp_space_for_current_thread() const; + GrowableArray* all_lgrp_spaces() const { return _all_lgrp_spaces; } + static int update_active_lgrp_spaces(GrowableArray* all_lgrp_spaces, + GrowableArray* active_lgrp_spaces, + size_t region_size, + size_t page_size); + public: GrowableArray* lgrp_spaces() const { return _lgrp_spaces; } MutableNUMASpace(size_t page_size); diff --git a/src/hotspot/share/gc/parallel/mutableSpace.cpp b/src/hotspot/share/gc/parallel/mutableSpace.cpp index 9b10f9faee20..dd0ce6f635a1 100644 --- a/src/hotspot/share/gc/parallel/mutableSpace.cpp +++ b/src/hotspot/share/gc/parallel/mutableSpace.cpp @@ -64,7 +64,7 @@ void MutableSpace::initialize(MemRegion mr, assert(Universe::on_page_boundary(mr.start()) && Universe::on_page_boundary(mr.end()), "invalid space boundaries"); - if (setup_pages && (UseNUMA || AlwaysPreTouch)) { + if (!mr.is_empty() && setup_pages && (UseNUMA || AlwaysPreTouch)) { // The space may move left and right or expand/shrink. // We'd like to enforce the desired page placement. MemRegion head, tail; @@ -207,7 +207,7 @@ void MutableSpace::object_iterate(ObjectClosure* cl) { void MutableSpace::print_short() const { print_short_on(tty); } void MutableSpace::print_short_on( outputStream* st) const { st->print("space %zuK, %d%% used", capacity_in_bytes() / K, - (int) ((double) used_in_bytes() * 100 / capacity_in_bytes())); + (int)percent_of(used_in_bytes(), capacity_in_bytes())); } void MutableSpace::print() const { print_on(tty, ""); } diff --git a/src/hotspot/share/gc/parallel/parallelArguments.cpp b/src/hotspot/share/gc/parallel/parallelArguments.cpp index a856078edab9..bf7900f6fe6d 100644 --- a/src/hotspot/share/gc/parallel/parallelArguments.cpp +++ b/src/hotspot/share/gc/parallel/parallelArguments.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -37,14 +37,6 @@ #include "utilities/defaultStream.hpp" #include "utilities/powerOfTwo.hpp" -static size_t num_young_spaces() { - // When using NUMA, we create one MutableNUMASpace for each NUMA node - const size_t num_eden_spaces = UseNUMA ? os::numa_get_groups_num() : 1; - - // The young generation must have room for eden + two survivors - return num_eden_spaces + 2; -} - static size_t num_old_spaces() { return 1; } @@ -56,7 +48,7 @@ void ParallelArguments::initialize_alignments() { SpaceAlignment = ParallelScavengeHeap::default_space_alignment(); if (UseLargePages) { - const size_t total_spaces = num_young_spaces() + num_old_spaces(); + const size_t total_spaces = ParallelScavengeHeap::num_young_spaces() + num_old_spaces(); const size_t page_size = os::page_size_for_region_unaligned(MaxHeapSize, total_spaces); ParallelScavengeHeap::set_desired_page_size(page_size); @@ -154,7 +146,7 @@ CollectedHeap* ParallelArguments::create_heap() { } size_t ParallelArguments::young_gen_size_lower_bound() { - return num_young_spaces() * SpaceAlignment; + return ParallelScavengeHeap::young_gen_size_lower_bound(); } size_t ParallelArguments::old_gen_size_lower_bound() { diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index ea3a85861b8d..d06fdb7904e0 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -27,6 +27,7 @@ #include "gc/parallel/parallelInitLogger.hpp" #include "gc/parallel/parallelScavengeHeap.inline.hpp" #include "gc/parallel/psAdaptiveSizePolicy.hpp" +#include "gc/parallel/psHeapVirtualSpace.hpp" #include "gc/parallel/psMemoryPool.hpp" #include "gc/parallel/psParallelCompact.inline.hpp" #include "gc/parallel/psPromotionManager.hpp" @@ -42,6 +43,7 @@ #include "gc/shared/scavengableNMethods.hpp" #include "gc/shared/suspendibleThreadSet.hpp" #include "logging/log.hpp" +#include "memory/allocation.inline.hpp" #include "memory/iterator.hpp" #include "memory/metaspaceCounters.hpp" #include "memory/metaspaceUtils.hpp" @@ -62,6 +64,36 @@ PSAdaptiveSizePolicy* ParallelScavengeHeap::_size_policy = nullptr; GCPolicyCounters* ParallelScavengeHeap::_gc_policy_counters = nullptr; size_t ParallelScavengeHeap::_desired_page_size = 0; +size_t ParallelScavengeHeap::_num_young_spaces = 0; + +size_t ParallelScavengeHeap::num_young_spaces() { + if (_num_young_spaces != 0) { + return _num_young_spaces; + } + + size_t num_eden_spaces = 1; + + if (UseNUMA) { + const size_t lgrp_limit = os::numa_get_groups_num(); + assert(lgrp_limit > 0, "invalid NUMA topology"); + + uint* lgrp_ids = NEW_C_HEAP_ARRAY(uint, lgrp_limit, mtGC); + num_eden_spaces = os::numa_get_leaf_groups(lgrp_ids, lgrp_limit); + FREE_C_HEAP_ARRAY(lgrp_ids); + + assert(num_eden_spaces > 0 && num_eden_spaces <= lgrp_limit, + "invalid number of NUMA locality groups"); + } + + _num_young_spaces = num_eden_spaces + 2; + return _num_young_spaces; +} + +size_t ParallelScavengeHeap::young_gen_size_lower_bound() { + // This is the structural minimum for a dynamic non-empty young generation, + // not MinNewSize, which is derived for the startup generation split. + return num_young_spaces() * SpaceAlignment; +} jint ParallelScavengeHeap::initialize() { const size_t reserved_heap_size = ParallelArguments::heap_reserved_size_bytes(); @@ -77,13 +109,16 @@ jint ParallelScavengeHeap::initialize() { trace_actual_reserved_page_size(reserved_heap_size, heap_rs); initialize_reserved_region(heap_rs); - // Layout the reserved space for the generations. - ReservedSpace old_rs = heap_rs.first_part(MaxOldSize, SpaceAlignment); - ReservedSpace young_rs = heap_rs.last_part(MaxOldSize, SpaceAlignment); - assert(young_rs.size() == MaxNewSize, "Didn't reserve all of the heap"); + + const size_t min_old_reserved = reserved_heap_size - MaxNewSize; + char* gen_boundary = heap_rs.base() + MAX2(MaxOldSize, min_old_reserved); + _heap_vs = new PSHeapVirtualSpace(heap_rs, SpaceAlignment, gen_boundary); PSCardTable* card_table = new PSCardTable(_reserved); - card_table->initialize(old_rs.base(), young_rs.base()); + card_table->initialize(heap_rs.base(), gen_boundary); + + // For the complete heap + _start_array = new ObjectStartArray(_reserved); CardTableBarrierSet* const barrier_set = new CardTableBarrierSet(card_table); BarrierSet::set_barrier_set(barrier_set); @@ -92,28 +127,15 @@ jint ParallelScavengeHeap::initialize() { _workers.initialize_workers(); // Create and initialize the generations. - _young_gen = new PSYoungGen( - young_rs, - NewSize, - MinNewSize, - MaxNewSize); - _old_gen = new PSOldGen( - old_rs, - OldSize, - MinOldSize, - MaxOldSize); - - assert(young_gen()->max_gen_size() == young_rs.size(),"Consistency check"); - assert(old_gen()->max_gen_size() == old_rs.size(), "Consistency check"); + _young_gen = new PSYoungGen(_heap_vs, NewSize, young_gen_size_lower_bound(), MaxNewSize); + + _old_gen = new PSOldGen(_heap_vs, _start_array, OldSize, reserved_heap_size); double max_gc_pause_sec = ((double) MaxGCPauseMillis)/1000.0; _size_policy = new PSAdaptiveSizePolicy(SpaceAlignment, max_gc_pause_sec); - assert((old_gen()->virtual_space()->high_boundary() == - young_gen()->virtual_space()->low_boundary()), - "Boundaries must meet"); // initialize the policy counters - 2 collectors, 2 generations _gc_policy_counters = new GCPolicyCounters("ParScav:MSC", 2, 2); @@ -178,16 +200,28 @@ void ParallelScavengeHeap::post_initialize() { } void ParallelScavengeHeap::gc_epilogue(bool full) { + size_t capacity_bytes = max_capacity(); + size_t free_bytes = capacity_bytes - used(); + double free_percent = percent_of(free_bytes, capacity_bytes); + if (_is_heap_almost_full) { - // Reset emergency state if eden is empty after a young/full gc - if (_young_gen->eden_space()->is_empty()) { + // Reset emergency state once young gen and sufficient allocation headroom return. + if (_young_gen->reserved_size() > 0 && free_percent > HeapAlmostFullThresholdPercent) { log_debug(gc)("Leaving memory constrained state; back to normal"); _is_heap_almost_full = false; } } else { - if (full && !_young_gen->eden_space()->is_empty()) { - log_debug(gc)("Non-empty young-gen after full-gc; in memory constrained state"); - _is_heap_almost_full = true; + if (full) { + if (_young_gen->reserved_size() == 0) { + log_debug(gc)("After full-gc, young-gen has become zero-sized, free space: %zu / %zu (K); entering memory constrained state", + free_bytes / K, capacity_bytes / K); + _is_heap_almost_full = true; + } else if (free_percent < HeapAlmostFullThresholdPercent) { + // Skip a likely futile normal collection on the next allocation failure. + log_debug(gc)("After full-gc, limited (<10%%) free space: %zu / %zu (K); entering memory constrained state", + free_bytes / K, capacity_bytes / K); + _is_heap_almost_full = true; + } } } } @@ -210,13 +244,7 @@ size_t ParallelScavengeHeap::used() const { } size_t ParallelScavengeHeap::max_capacity() const { - size_t estimated = reserved_region().byte_size(); - if (UseAdaptiveSizePolicy) { - estimated -= _size_policy->max_survivor_size(young_gen()->max_gen_size()); - } else { - estimated -= young_gen()->to_space()->capacity_in_bytes(); - } - return MAX2(estimated, capacity()); + return reserved_region().byte_size(); } bool ParallelScavengeHeap::is_in(const void* p) const { @@ -378,8 +406,8 @@ bool ParallelScavengeHeap::should_attempt_young_gc() const { const bool ShouldRunYoungGC = true; const bool ShouldRunFullGC = false; - if (!_young_gen->to_space()->is_empty()) { - log_debug(gc, ergo)("To-space is not empty; run full-gc instead."); + if (_young_gen->reserved_size() == 0) { + // Young-gen is zero-sized. return ShouldRunFullGC; } @@ -389,7 +417,7 @@ bool ParallelScavengeHeap::should_attempt_young_gc() const { size_t avg_promoted = (size_t) policy->padded_average_promoted_in_bytes(); size_t promotion_estimate = MIN2(avg_promoted, _young_gen->used_in_bytes()); // Total free size after possible old gen expansion - size_t free_in_old_gen_with_expansion = _old_gen->max_gen_size() - _old_gen->used_in_bytes(); + size_t free_in_old_gen_with_expansion = _old_gen->reserved_size() - _old_gen->used_in_bytes(); log_trace(gc, ergo)("average_promoted %zu; padded_average_promoted %zu", (size_t) policy->average_promoted_in_bytes(), @@ -405,11 +433,11 @@ bool ParallelScavengeHeap::should_attempt_young_gc() const { // Also checking OS has enough free memory to commit and expand old-gen. // Otherwise, the recorded gc-pause-time might be inflated to include time // of OS preparing free memory, resulting in inaccurate young-gen resizing. - assert(_old_gen->committed().byte_size() >= _old_gen->used_in_bytes(), "inv"); + assert(_old_gen->committed_size() >= _old_gen->used_in_bytes(), "inv"); // Use uint64_t instead of size_t for 32bit compatibility. uint64_t free_mem_in_os; if (os::free_memory(free_mem_in_os)) { - size_t actual_free = (size_t)MIN2(_old_gen->committed().byte_size() - _old_gen->used_in_bytes() + free_mem_in_os, + size_t actual_free = (size_t)MIN2(_old_gen->committed_size() - _old_gen->used_in_bytes() + free_mem_in_os, (uint64_t)SIZE_MAX); if (promotion_estimate > actual_free) { log_debug(gc, ergo)("Run full-gc; predicted promotion size > free space in old-gen and OS: %zu > %zu", @@ -423,10 +451,6 @@ bool ParallelScavengeHeap::should_attempt_young_gc() const { return ShouldRunYoungGC; } -static bool check_gc_heap_free_limit(size_t free_bytes, size_t capacity_bytes) { - return (free_bytes * 100 / capacity_bytes) < GCHeapFreeLimit; -} - bool ParallelScavengeHeap::check_gc_overhead_limit() { assert(SafepointSynchronize::is_at_safepoint(), "precondition"); @@ -434,13 +458,16 @@ bool ParallelScavengeHeap::check_gc_overhead_limit() { // The goal here is to return null prematurely so that apps can exit // gracefully when GC takes the most time. bool little_mutator_time = _size_policy->mutator_time_percent() * 100 < (100 - GCTimeLimit); - bool little_free_space = check_gc_heap_free_limit(_young_gen->free_in_bytes(), _young_gen->capacity_in_bytes()) - && check_gc_heap_free_limit( _old_gen->free_in_bytes(), _old_gen->capacity_in_bytes()); - log_debug(gc)("GC Overhead Limit: GC Time %f Free Space Young %f Old %f Counter %zu", + size_t heap_capacity_bytes = capacity(); + size_t heap_free_bytes = heap_capacity_bytes - used(); + double heap_free_percent = percent_of(heap_free_bytes, heap_capacity_bytes); + bool little_free_space = heap_free_percent < GCHeapFreeLimit; + + log_debug(gc)("Checking GC Overhead: GC Time %.1f%% Free Space %zuK (%.1f%%) Counter %zu", (100 - _size_policy->mutator_time_percent()), - percent_of(_young_gen->free_in_bytes(), _young_gen->capacity_in_bytes()), - percent_of(_old_gen->free_in_bytes(), _old_gen->capacity_in_bytes()), + heap_free_bytes / K, + heap_free_percent, _gc_overhead_counter); if (little_mutator_time && little_free_space) { @@ -482,10 +509,10 @@ HeapWord* ParallelScavengeHeap::satisfy_failed_allocation(size_t size, bool is_t HeapWord* result = nullptr; if (!_is_heap_almost_full) { - // If young-gen can handle this allocation, attempt young-gc firstly, as young-gc is usually cheaper. + // If young-gen can handle this allocation, attempt young-gc first, as young-gc is usually cheaper. bool should_run_young_gc = is_tlab || should_alloc_in_eden(size); - collect_at_safepoint(!should_run_young_gc); + collect_at_safepoint(!should_run_young_gc, {size, is_tlab}); // If gc-overhead is reached, we will skip allocation. if (!check_gc_overhead_limit()) { @@ -500,7 +527,9 @@ HeapWord* ParallelScavengeHeap::satisfy_failed_allocation(size_t size, bool is_t { const bool clear_all_soft_refs = true; const bool should_do_max_compaction = true; - PSParallelCompact::invoke(clear_all_soft_refs, should_do_max_compaction); + PSParallelCompact::invoke(clear_all_soft_refs, + should_do_max_compaction, + {size, is_tlab}); } if (check_gc_overhead_limit()) { @@ -569,20 +598,28 @@ void ParallelScavengeHeap::collect(GCCause::Cause cause) { VMThread::execute(&op); } -void ParallelScavengeHeap::collect_at_safepoint(bool is_full) { +void ParallelScavengeHeap::collect_at_safepoint(bool is_full, + PSPendingAllocation pending_allocation) { assert(!GCLocker::is_active(), "precondition"); bool clear_soft_refs = GCCause::should_clear_all_soft_refs(_gc_cause); + size_t promoted_before_full_gc = 0; if (!is_full && should_attempt_young_gc()) { + const size_t old_used_before = old_gen()->used_in_bytes(); bool young_gc_success = PSScavenge::invoke(clear_soft_refs); if (young_gc_success) { return; } + assert(old_gen()->used_in_bytes() >= old_used_before, "inv"); + promoted_before_full_gc = old_gen()->used_in_bytes() - old_used_before; log_debug(gc, heap)("Upgrade to Full-GC since Young-gc failed."); } const bool should_do_max_compaction = false; - PSParallelCompact::invoke(clear_soft_refs, should_do_max_compaction); + PSParallelCompact::invoke(clear_soft_refs, + should_do_max_compaction, + pending_allocation, + promoted_before_full_gc); } void ParallelScavengeHeap::object_iterate(ObjectClosure* cl) { @@ -682,15 +719,16 @@ void ParallelScavengeHeap::prepare_for_verify() { PSHeapSummary ParallelScavengeHeap::create_ps_heap_summary() { PSOldGen* old = old_gen(); - HeapWord* old_committed_end = (HeapWord*)old->virtual_space()->committed_high_addr(); - HeapWord* old_reserved_start = old->reserved().start(); - HeapWord* old_reserved_end = old->reserved().end(); - VirtualSpaceSummary old_summary(old_reserved_start, old_committed_end, old_reserved_end); - SpaceSummary old_space(old_reserved_start, old_committed_end, old->used_in_bytes()); + HeapWord* old_committed_end = old->committed().end(); + MemRegion old_reserved = old->reserved(); + VirtualSpaceSummary old_summary(old_reserved.start(), old_committed_end, old_reserved.end()); + SpaceSummary old_space(old_reserved.start(), old_committed_end, old->used_in_bytes()); PSYoungGen* young = young_gen(); - VirtualSpaceSummary young_summary(young->reserved().start(), - (HeapWord*)young->virtual_space()->committed_high_addr(), young->reserved().end()); + MemRegion young_reserved = young->reserved(); + VirtualSpaceSummary young_summary(young_reserved.start(), + young->committed().end(), + young_reserved.end()); MutableSpace* eden = young_gen()->eden_space(); SpaceSummary eden_space(eden->bottom(), eden->end(), eden->used_in_bytes()); @@ -839,15 +877,17 @@ static size_t calculate_free_from_free_ratio_flag(size_t live, uintx free_percen } size_t ParallelScavengeHeap::calculate_desired_old_gen_capacity(size_t old_gen_live_size) { - // If min free percent is 100%, the old-gen should always be in its max capacity + // If min free percent is 100%, the old-gen should stay fully committed, + // i.e. using all reserved size. if (MinHeapFreeRatio == 100) { - return _old_gen->max_gen_size(); + return _old_gen->reserved_size(); } // Using recorded data to calculate the new capacity of old-gen to avoid // excessive expansion but also keep footprint low - size_t promoted_estimate = _size_policy->padded_average_promoted_in_bytes(); + size_t promoted_estimate = MIN2(_size_policy->padded_average_promoted_in_bytes(), + _young_gen->reserved_size()); // Should have at least this free room for the next young-gc promotion. size_t free_size = promoted_estimate; @@ -872,6 +912,14 @@ void ParallelScavengeHeap::resize_old_gen_after_full_gc() { size_t current_capacity = _old_gen->capacity_in_bytes(); size_t desired_capacity = calculate_desired_old_gen_capacity(old_gen()->used_in_bytes()); + // MinHeapSize constraint. + size_t young_gen_committed_size = young_gen()->committed_size(); + size_t min_old_gen_size = old_gen()->min_gen_size(); + if (young_gen_committed_size + min_old_gen_size < MinHeapSize) { + min_old_gen_size = MinHeapSize - young_gen_committed_size; + } + desired_capacity = MAX2(desired_capacity, min_old_gen_size); + // If MinHeapFreeRatio is at its default value; shrink cautiously. Otherwise, users expect prompt shrinking. if (FLAG_IS_DEFAULT(MinHeapFreeRatio)) { if (desired_capacity < current_capacity) { @@ -886,50 +934,270 @@ void ParallelScavengeHeap::resize_old_gen_after_full_gc() { _old_gen->resize(desired_capacity); } -void ParallelScavengeHeap::resize_after_young_gc(bool is_survivor_overflowing) { - _young_gen->resize_after_young_gc(is_survivor_overflowing); +void ParallelScavengeHeap::shrink_old_gen_after_young_gc(bool is_survivor_overflowing) { + if (is_survivor_overflowing) { + // Shouldn't shrink if there is an overflow. + return; + } - // Consider if should shrink old-gen - if (!is_survivor_overflowing) { - assert(old_gen()->capacity_in_bytes() >= old_gen()->min_gen_size(), "inv"); + // MinHeapSize constraint. + size_t young_gen_committed_size = young_gen()->committed_size(); + size_t min_old_gen_size = old_gen()->min_gen_size(); + if (young_gen_committed_size + min_old_gen_size < MinHeapSize) { + min_old_gen_size = MinHeapSize - young_gen_committed_size; + } + assert(old_gen()->capacity_in_bytes() >= min_old_gen_size, "inv"); + if (old_gen()->capacity_in_bytes() == min_old_gen_size) { + // Already minimal; can't shrink + return; + } - // Old gen min_gen_size constraint. - const size_t max_shrink_bytes_gen_size_constraint = old_gen()->capacity_in_bytes() - old_gen()->min_gen_size(); + const size_t max_shrink_bytes_gen_size_constraint = + old_gen()->capacity_in_bytes() - min_old_gen_size; - // Per-step delta to avoid too aggressive shrinking. - const size_t max_shrink_bytes_per_step_constraint = SpaceAlignment; + // Per-step delta to avoid too aggressive shrinking. + const size_t max_shrink_bytes_per_step_constraint = SpaceAlignment; - // Combining the above two constraints. - const size_t max_shrink_bytes = MIN2(max_shrink_bytes_gen_size_constraint, - max_shrink_bytes_per_step_constraint); + // Combining the above two constraints. + const size_t max_shrink_bytes = MIN2(max_shrink_bytes_gen_size_constraint, + max_shrink_bytes_per_step_constraint); - size_t shrink_bytes = _size_policy->compute_old_gen_shrink_bytes(old_gen()->free_in_bytes(), max_shrink_bytes); + size_t shrink_bytes = _size_policy->compute_old_gen_shrink_bytes(old_gen()->free_in_bytes(), + max_shrink_bytes); - assert(old_gen()->capacity_in_bytes() >= shrink_bytes, "inv"); - assert(old_gen()->capacity_in_bytes() - shrink_bytes >= old_gen()->min_gen_size(), "inv"); + assert(old_gen()->capacity_in_bytes() >= shrink_bytes, "inv"); + assert(old_gen()->capacity_in_bytes() - shrink_bytes >= old_gen()->min_gen_size(), "inv"); + if (shrink_bytes == 0) { + return; + } - if (shrink_bytes != 0) { - if (MinHeapFreeRatio != 0) { - size_t new_capacity = old_gen()->capacity_in_bytes() - shrink_bytes; - size_t new_free_size = old_gen()->free_in_bytes() - shrink_bytes; - if ((double)new_free_size / new_capacity * 100 < MinHeapFreeRatio) { - // Would violate MinHeapFreeRatio - return; - } + if (MinHeapFreeRatio != 0) { + size_t new_capacity = old_gen()->capacity_in_bytes() - shrink_bytes; + size_t new_free_size = old_gen()->free_in_bytes() - shrink_bytes; + if ((double)new_free_size / new_capacity * 100 < MinHeapFreeRatio) { + // Would violate MinHeapFreeRatio + return; + } + } + + old_gen()->shrink(shrink_bytes); +} + +void ParallelScavengeHeap::resize_young_gen_after_young_gc(bool is_survivor_overflowing) { + size_t eden_size = 0; + size_t survivor_size = 0; + + // Whether old-gen can lend some space to young-gen. + size_t old_gen_lendable_size; + assert(_young_gen->reserved_size() <= MaxNewSize, "inv"); + if (_young_gen->reserved_size() == MaxNewSize) { + // No headroom to expand young-gen at the expense of old-gen. + old_gen_lendable_size = 0; + } else { + // Gen-boundary has right-shifted. Check if we can move it back. + old_gen_lendable_size = _old_gen->uncommitted_size() + _old_gen->free_in_bytes(); + + // Reserve headroom for expected promotion into old gen. + size_t avg_promoted = MIN2(size_policy()->padded_average_promoted_in_bytes(), + MaxNewSize); + old_gen_lendable_size = (old_gen_lendable_size > avg_promoted) + ? old_gen_lendable_size - avg_promoted + : 0; + + old_gen_lendable_size = MIN2(old_gen_lendable_size, + MaxNewSize - _young_gen->reserved_size()); + old_gen_lendable_size = align_down(old_gen_lendable_size, SpaceAlignment); + } + + // First try resizing with the current gen-boundary + if (_young_gen->try_resize(is_survivor_overflowing, + old_gen_lendable_size, + &eden_size, + &survivor_size)) { + return; + } + + // The current gen-boundary can't satisfy requested eden/survivor sizes. + // Expand young-gen on both left and right edges. + + // From-space might contain live objs, so it needs to stay in-place. + // Additionally, the two survivor spaces must have the same capacity, + // so the left-edge moves by to-capacity. + + // 1. Left-edge expansion + // before: |old-gen | from to eden | + // after: |old-gen | to from eden | + // ^ previous gen-boundary + { + const size_t delta_bytes = survivor_size; + assert(align_down(_old_gen->uncommitted_size() + _old_gen->free_in_bytes(), SpaceAlignment) >= delta_bytes, + "enough space for left-shift"); + + const bool is_old_gen_committed_mr_changed = delta_bytes > _old_gen->uncommitted_size(); + + // left-shift by delta + char* desired_gen_boundary = _heap_vs->gen_boundary() - delta_bytes; + _heap_vs->left_shift_gen_boundary(desired_gen_boundary); + assert(_heap_vs->gen_boundary() == desired_gen_boundary, "postcondition"); + + if (is_old_gen_committed_mr_changed) { + _old_gen->reinit_after_committed_mr_change(); + } + } + + // 2. Right-edge expansion + { + size_t young_gen_uncommitted_size = _young_gen->uncommitted_size(); + if (young_gen_uncommitted_size != 0) { + if (!_heap_vs->expand_young_gen(young_gen_uncommitted_size)) { + vm_exit_out_of_memory(young_gen_uncommitted_size, OOM_MMAP_ERROR, "resize_young_gen_after_young_gc"); } - old_gen()->shrink(shrink_bytes); + assert(_young_gen->uncommitted_size() == 0, "postcondition"); } } + + PSScavenge::reset_young_gen_reserved(_young_gen->reserved()); + + card_table()->left_shift_gen_boundary(_old_gen->committed(), + _young_gen->committed()); + + _young_gen->reinit_to_from_layout(eden_size, survivor_size); +} + +void ParallelScavengeHeap::resize_after_young_gc(bool is_survivor_overflowing) { + // Resize young-gen before shrinking old-gen so that free old-gen space + // is not immediately uncommitted and recommitted for young-gen. + resize_young_gen_after_young_gc(is_survivor_overflowing); + + // Old-gen is expanded when it's actually needed; + // we perform only shrinking in this context to reduce footprint. + shrink_old_gen_after_young_gc(is_survivor_overflowing); } void ParallelScavengeHeap::resize_after_full_gc() { resize_old_gen_after_full_gc(); - // We don't resize young-gen after full-gc because: - // 1. eden-size directly affects young-gc frequency (GCTimeRatio), and we - // don't have enough info to determine its desired size. - // 2. eden can contain live objs after a full-gc, which is unsafe for - // resizing. We will perform expansion on allocation if needed, in - // satisfy_failed_allocation(). + // Young-gen was already handled by adjust_gen_boundary_after_full_gc(): + // full-gc compacts all live objects into old-gen and leaves young-gen empty, + // possibly with a zero-sized reservation. We don't apply adaptive young-gen + // sizing here because full-gc produces no young-gc-specific + // measurements for choosing eden/survivor sizes. If needed, eden is expanded + // on allocation in satisfy_failed_allocation(). +} + +bool ParallelScavengeHeap::adjust_gen_boundary_after_full_gc(size_t live_bytes, + PSPendingAllocation pending_allocation) { + assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); + assert(live_bytes <= MaxHeapSize, "inv"); + + const size_t remaining_heap_bytes = MaxHeapSize - live_bytes; + + const bool has_pending_non_tlab_allocation = pending_allocation.is_non_tlab(); + const size_t young_gen_bytes = UseAdaptiveSizePolicy ? _young_gen->reserved_size() : MaxNewSize; + // Promotion headroom is optional. Do not let it consume the current adaptive + // reservation or the non-adaptive maximum reservation. + const size_t max_promotion_headroom_bytes = remaining_heap_bytes > young_gen_bytes + ? remaining_heap_bytes - young_gen_bytes + : 0; + size_t required_old_free_bytes = MIN2(_size_policy->padded_average_promoted_in_bytes(), + max_promotion_headroom_bytes); + // Ignore impossible requests for boundary sizing; the allocation will fail + // normally after GC without unnecessarily removing young-gen. + if (has_pending_non_tlab_allocation && + pending_allocation._word_size <= remaining_heap_bytes / HeapWordSize) { + // TLAB failures retry outside TLAB. Only non-TLAB requests need old-gen room here. + required_old_free_bytes = MAX2(required_old_free_bytes, + pending_allocation._word_size * HeapWordSize); + } + + size_t requested_old_capacity = align_up(live_bytes + required_old_free_bytes, + SpaceAlignment); + size_t desired_old_capacity = clamp(requested_old_capacity, + SpaceAlignment, + MaxHeapSize); + + char* const heap_low = (char*)reserved_region().start(); + char* const heap_high = (char*)reserved_region().end(); + char* const current_gen_boundary = _heap_vs->gen_boundary(); + const size_t min_young_gen_size = young_gen_size_lower_bound(); + + if (MaxHeapSize - desired_old_capacity < min_young_gen_size) { + desired_old_capacity = MaxHeapSize; + } + + char* desired_gen_boundary = heap_low + desired_old_capacity; + assert(desired_gen_boundary <= heap_high, "inv"); + + // Right-shift + if (desired_gen_boundary > current_gen_boundary) { + // Old-gen needs more reserved space for live data, promotion headroom, or a pending allocation. + MemRegion original_old_gen_committed = _old_gen->committed(); + _heap_vs->right_shift_gen_boundary(desired_gen_boundary); + assert(_heap_vs->old_gen_committed_high_addr() == _heap_vs->young_gen_low_addr(), "inv"); + _old_gen->reinit_after_committed_mr_change(); + _young_gen->reinit_after_gen_boundary_change(); + card_table()->right_shift_gen_boundary(_old_gen->committed(), + _young_gen->committed()); + // Check newly joined old-gen have clean cards. + card_table()->verify_clean_cards(MemRegion{original_old_gen_committed.end(), + _old_gen->committed().end()}); + return true; + } + + if (desired_gen_boundary == current_gen_boundary) { + // No adjustment needed. + return false; + } + + assert(desired_gen_boundary < current_gen_boundary, "inv"); + + // Left-shift. Adaptive sizing recovers from old-gen-only mode gradually; + // fixed sizing returns borrowed reservation up to the startup MaxNewSize. + const size_t young_reserved_before = _young_gen->reserved_size(); + size_t free_bytes_in_old_gen = _old_gen->reserved_size() - desired_old_capacity; + assert(is_aligned(free_bytes_in_old_gen, SpaceAlignment), "inv"); + + size_t desired_shrink_bytes; + if (UseAdaptiveSizePolicy) { + // With a non-empty young reservation, adaptive young-GC sizing owns rebalancing. + if (young_reserved_before > 0) { + return false; + } + // Recover one eighth at a time to retain promotion headroom. If the result is + // smaller than the minimum young size, stay in old-only mode until enough + // free space accumulates. + desired_shrink_bytes = align_down(free_bytes_in_old_gen / 8, SpaceAlignment); + } else { + // Recover the startup reservation without allowing young gen to exceed MaxNewSize. + desired_shrink_bytes = free_bytes_in_old_gen; + } + + desired_shrink_bytes = MIN2(desired_shrink_bytes, MaxNewSize - young_reserved_before); + if (desired_shrink_bytes == 0) { + // Young gen already owns its full MaxNewSize reservation or the calculated shrink + // request is too small; there is nothing to shift. left_shift_gen_boundary() + // requires a strict shift. + return false; + } + if (young_reserved_before + desired_shrink_bytes < min_young_gen_size) { + return false; + } + + desired_gen_boundary = current_gen_boundary - desired_shrink_bytes; + + size_t young_reserved_bytes = pointer_delta(heap_high, desired_gen_boundary, sizeof(char)); + assert(young_reserved_bytes >= min_young_gen_size, "postcondition"); + + _heap_vs->left_shift_gen_boundary(desired_gen_boundary); + + _old_gen->reinit_after_committed_mr_change(); + _young_gen->reinit_after_gen_boundary_change(); + card_table()->left_shift_gen_boundary(_old_gen->committed(), + _young_gen->committed()); + + log_debug(gc, heap)("Young generation reservation after full GC: %zuK -> %zuK", + young_reserved_before / K, young_reserved_bytes / K); + + return true; } HeapWord* ParallelScavengeHeap::allocate_loaded_archive_space(size_t size) { diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp index 588ddfa3f0c5..2dab21623ad3 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,20 +44,38 @@ class MemoryPool; class PSAdaptiveSizePolicy; class PSCardTable; class PSHeapSummary; +class PSHeapVirtualSpace; class ReservedSpace; +struct PSPendingAllocation { + size_t _word_size; + bool _is_tlab; + + static PSPendingAllocation none() { + return {0, false}; + } + + bool is_present() const { + return _word_size != 0; + } + + bool is_non_tlab() const { + return is_present() && !_is_tlab; + } +}; + // ParallelScavengeHeap is the implementation of CollectedHeap for Parallel GC. // // The heap is reserved up-front in a single contiguous block, split into two // parts, the old and young generation. The old generation resides at lower // addresses, the young generation at higher addresses. The boundary address -// between the generations is fixed. Within a generation, committed memory -// grows towards higher addresses. +// between the generations is dynamic and can be adjusted during young/full gc. +// Within a generation, committed memory grows towards higher addresses. // // // low high // -// +-- generation boundary (fixed after startup) +// +-- generation boundary (adjusted during young/full gc) // | // |<- old gen (reserved) ->|<- young gen (reserved) ->| // +---------------+--------+--------+--------+------------------+-------+ @@ -72,12 +90,19 @@ class ParallelScavengeHeap : public CollectedHeap { PSYoungGen* _young_gen; PSOldGen* _old_gen; + PSHeapVirtualSpace* _heap_vs; + + // Keeps track of where objects start for a heap memory range corresponding to a card. + // Used by young-gc to quickly find obj-start to parse the heap. + ObjectStartArray* _start_array; + // Sizing policy for entire heap static PSAdaptiveSizePolicy* _size_policy; static GCPolicyCounters* _gc_policy_counters; // At startup, calculate the desired OS page-size based on heap size and large-page flags. static size_t _desired_page_size; + static size_t _num_young_spaces; GCMemoryManager* _young_manager; GCMemoryManager* _old_manager; @@ -92,6 +117,10 @@ class ParallelScavengeHeap : public CollectedHeap { bool _is_heap_almost_full; + // A full GC with less headroom than this is unlikely to make another + // normal allocation/collection attempt useful. + static constexpr double HeapAlmostFullThresholdPercent = 10.0; + void initialize_serviceability() override; void trace_actual_reserved_page_size(const size_t reserved_heap_size, const ReservedSpace rs); @@ -116,6 +145,9 @@ class ParallelScavengeHeap : public CollectedHeap { void resize_old_gen_after_full_gc(); + void shrink_old_gen_after_young_gc(bool is_survivor_overflowing); + void resize_young_gen_after_young_gc(bool is_survivor_overflowing); + void print_tracing_info() const override; void stop() override {}; @@ -141,6 +173,9 @@ class ParallelScavengeHeap : public CollectedHeap { return alignment; } + static size_t num_young_spaces(); + static size_t young_gen_size_lower_bound(); + static void set_desired_page_size(size_t page_size) { assert(is_power_of_2(page_size), "precondition"); _desired_page_size = page_size; @@ -154,6 +189,8 @@ class ParallelScavengeHeap : public CollectedHeap { return "Parallel"; } + ObjectStartArray* start_array() const { return _start_array; } + // Invoked at gc-pause-end void gc_epilogue(bool full); @@ -163,6 +200,8 @@ class ParallelScavengeHeap : public CollectedHeap { PSYoungGen* young_gen() const { return _young_gen; } PSOldGen* old_gen() const { return _old_gen; } + PSHeapVirtualSpace* heap_vs() const { return _heap_vs; } + PSAdaptiveSizePolicy* size_policy() { return _size_policy; } static GCPolicyCounters* gc_policy_counters() { return _gc_policy_counters; } @@ -210,7 +249,8 @@ class ParallelScavengeHeap : public CollectedHeap { void collect(GCCause::Cause cause) override; - void collect_at_safepoint(bool full); + void collect_at_safepoint(bool full, + PSPendingAllocation pending_allocation = PSPendingAllocation::none()); void ensure_parsability(bool retire_tlabs) override; void resize_all_tlabs() override; @@ -245,6 +285,10 @@ class ParallelScavengeHeap : public CollectedHeap { void resize_after_young_gc(bool is_survivor_overflowing); void resize_after_full_gc(); + // Dynamic generation boundary support for Full GC + bool adjust_gen_boundary_after_full_gc(size_t live_bytes, + PSPendingAllocation pending_allocation); + GCMemoryManager* old_gc_manager() const { return _old_manager; } GCMemoryManager* young_gc_manager() const { return _young_manager; } diff --git a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp index f59733d20195..455c5e71d3ea 100644 --- a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp +++ b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp @@ -148,9 +148,7 @@ size_t PSAdaptiveSizePolicy::compute_desired_eden_size(bool is_survivor_overflow return cur_eden; } -size_t PSAdaptiveSizePolicy::compute_desired_survivor_size( - size_t current_survivor_size, - size_t max_gen_size) { +size_t PSAdaptiveSizePolicy::compute_desired_survivor_size(size_t current_survivor_size, size_t max_gen_size) { size_t desired_survivor_size = survived_bytes_estimate(); if (desired_survivor_size >= current_survivor_size) { @@ -295,9 +293,18 @@ void PSAdaptiveSizePolicy::update_averages(bool is_survivor_overflow, _survived_bytes.add(survived + promoted); } - avg_promoted()->sample(promoted); + sample_promoted_bytes(promoted); _promoted_bytes.add(promoted); double promotion_rate = promoted / (_gc_distance_seconds_seq.last() + _trimmed_minor_gc_time_seconds.last()); _promotion_rate_bytes_per_sec.add(promotion_rate); } + +void PSAdaptiveSizePolicy::sample_promoted_bytes(size_t promoted) { + avg_promoted()->sample(promoted); +} + +void PSAdaptiveSizePolicy::sample_promoted_bytes_permit_zero(size_t promoted) { + // avg_promoted() is AdaptivePaddedNoZeroDevAverage* + avg_promoted()->AdaptivePaddedAverage::sample(promoted); +} diff --git a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp index 54d7185b062b..0d23c9e42467 100644 --- a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp +++ b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, 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 @@ -115,6 +115,9 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy { size_t survived, size_t promoted); + void sample_promoted_bytes(size_t promoted); + void sample_promoted_bytes_permit_zero(size_t promoted); + // Decay the supplemental growth additive. void decay_supplemental_growth(uint num_minor_gcs); }; diff --git a/src/hotspot/share/gc/parallel/psCardTable.cpp b/src/hotspot/share/gc/parallel/psCardTable.cpp index 226ccf72a682..307d5cc0384f 100644 --- a/src/hotspot/share/gc/parallel/psCardTable.cpp +++ b/src/hotspot/share/gc/parallel/psCardTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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 @@ #include "gc/parallel/objectStartArray.inline.hpp" #include "gc/parallel/parallelScavengeHeap.inline.hpp" #include "gc/parallel/psCardTable.hpp" +#include "gc/parallel/psHeapVirtualSpace.hpp" #include "gc/parallel/psPromotionManager.inline.hpp" #include "gc/parallel/psYoungGen.hpp" #include "memory/iterator.inline.hpp" @@ -417,6 +418,175 @@ bool PSCardTable::is_dirty_for_addr(void *addr) { return is_dirty(p); } +#ifdef ASSERT +void PSCardTable::verify_clean_cards(MemRegion mr) const { + assert(!mr.is_empty(), "precondition"); + + CardValue* start; + if (mr.start() == _whole_heap.start()) { + start = byte_for(mr.start()); + } else { + assert(mr.start() > _whole_heap.start(), "mr is not covered."); + start = byte_after(mr.start() - 1); + } + CardValue* const end = byte_after(mr.last()); + for (CardValue* cur = start; cur < end; ++cur) { + assert(*cur == clean_card, "card not clean: " PTR_FORMAT, p2i(cur)); + } +} +#endif + +// Helper to commit only the part of 'delta' that is not in already_committed. +void PSCardTable::commit_delta_excluding(MemRegion delta, MemRegion already_committed, bool should_clear_card) { + assert(!delta.is_empty(), "precondition"); + + if (already_committed.contains(delta)) { + return; + } + + auto commit_or_exit = [&](const MemRegion& r) { + os::commit_memory_or_exit((char*)r.start(), + r.byte_size(), + _page_size, + !ExecMem, + "card table expansion"); + if (should_clear_card) { + memset(r.start(), clean_card, r.byte_size()); + } + }; + + MemRegion inter = delta.intersection(already_committed); + + if (inter.is_empty()) { + commit_or_exit(delta); + } else { + if (delta.start() < inter.start()) { + commit_or_exit(MemRegion(delta.start(), inter.start())); + } + if (inter.end() < delta.end()) { + commit_or_exit(MemRegion(inter.end(), delta.end())); + } + } +} + +void PSCardTable::right_shift_gen_boundary(MemRegion new_region0, + MemRegion new_region1) { + // Preconditions - the whole heap must contain both regions and region0 always starts at heap base. + assert(_whole_heap.contains(new_region0), "precondition"); + assert(_whole_heap.contains(new_region1), "precondition"); + assert(new_region0.start() == _whole_heap.start(), "region0 must start at heap start"); + assert(new_region0.end() == new_region1.start(), "region0 must be fully committed"); + assert(new_region0.end() > _covered[0].end(), "strict right shift"); + + MemRegion old_region0 = _covered[0]; + MemRegion old_region1 = _covered[1]; + + // In a right-shift, the old generation (region0) expands and the young generation (region1) + // moves its low address rightwards. + MemRegion old_committed0 = committed_for(old_region0); + MemRegion old_committed1 = committed_for(old_region1); + + // Update the covered regions. + _covered[0] = new_region0; + _covered[1] = new_region1; + + MemRegion new_committed0 = committed_for(new_region0); + MemRegion new_committed1 = committed_for(new_region1); + + // + // There can be multiple scenarios: + // + // case A - old-gen extends into the middle of before-young-gen + // before: |ooo |yyyy | + // after: |oooooooo|yyyy | + // + // case B - old-gen extends beyond before-young-gen end + // before: |ooo |yyyy | + // after: |oooooooooooo|yy| + // + // case C - old-gen extends to heap-end; after-young-gen is zero sized. + // before: |ooo |yyyy | + // after: |ooooooooooooooo| + // + // In all those scenarios, we need to perform the following 3 actions: + // + // ----------------------------------------------------------------- + // 1) Region0 expands (its high side moves right). Commit the newly needed tail. + // ----------------------------------------------------------------- + if (new_committed0.end() > old_committed0.end()) { + MemRegion delta{old_committed0.end(), new_committed0.end()}; + // The newly added part may overlap the old young-gen committed range; avoid double-commit. + commit_delta_excluding(delta, old_committed1); + } + + // ----------------------------------------------------------------- + // 2) Region1 moves its low side rightwards. + // ----------------------------------------------------------------- + assert(new_committed1.start() >= old_committed1.start(), "inv"); + // Nothing specific to do here for commit, as region1 is shrinking from the left. + // The area it "lost" has been taken over by region0 above. + + // ----------------------------------------------------------------- + // 3) Region1 high side potentially moves rightwards. + // ----------------------------------------------------------------- + assert(new_committed1.end() >= MAX2(old_committed1.end(), new_committed1.start()), "inv"); + + if (new_committed1.end() > MAX2(old_committed1.end(), new_committed1.start())) { + // Expansion at the end + MemRegion delta{MAX2(old_committed1.end(), new_committed1.start()), new_committed1.end()}; + os::commit_memory_or_exit((char*)delta.start(), delta.byte_size(), _page_size, !ExecMem, + "card table expansion"); + memset(delta.start(), clean_card, delta.byte_size()); + } + + { + // Clean the heap range newly joined old-gen committed coverage. + MemRegion old_gen_delta(old_region0.end(), new_region0.end()); + clear_MemRegion(old_gen_delta); + } +} + +void PSCardTable::left_shift_gen_boundary(MemRegion new_region0, + MemRegion new_region1) { + // Preconditions - the whole heap must contain both regions and region0 always starts at heap base. + assert(_whole_heap.contains(new_region0), "precondition"); + assert(_whole_heap.contains(new_region1), "precondition"); + assert(new_region0.start() == _whole_heap.start(), "region0 must start at heap start"); + assert(new_region0.end() <= _covered[0].end(), "region0 committed mem must never grow"); + assert(new_region1.start() < _covered[1].start(), "region1 start must left-shift"); + assert(new_region1.start() < new_region1.end(), "region1 must be non-empty"); + assert(new_region1.end() >= _covered[1].end(), "region1 must never shrink"); + + // Heap: + // before: |oooo |yyyy | + // after: |oooo |yyyyy | + MemRegion old_region1 = _covered[1]; + MemRegion old_committed0 = committed_for(_covered[0]); + MemRegion old_committed1 = committed_for(_covered[1]); + + // Update the covered regions. + _covered[0] = new_region0; + _covered[1] = new_region1; + + MemRegion new_committed1 = committed_for(new_region1); + assert(new_committed1.start() <= old_committed1.start(), "inv"); + // Check if cardtable needs to be expanded on left-edge. + if (new_committed1.start() < old_committed1.start()) { + MemRegion delta{new_committed1.start(), old_committed1.start()}; + commit_delta_excluding(delta, old_committed0, true); + } + + assert(new_committed1.end() >= old_committed1.end(), "region1 must not shrink on the right edge"); + if (new_committed1.end() > old_committed1.end()) { + MemRegion delta{old_committed1.end(), new_committed1.end()}; + commit_delta_excluding(delta, old_committed1, true); + } + + // Cards from old-gen (left-edge) must be clean. + verify_clean_cards(MemRegion{new_region1.start(), old_region1.start()}); + // Can't assert for right-edge; those cards can contain arbitrary value. +} + bool PSCardTable::is_in_young(const void* p) const { return ParallelScavengeHeap::heap()->is_in_young(p); } diff --git a/src/hotspot/share/gc/parallel/psCardTable.hpp b/src/hotspot/share/gc/parallel/psCardTable.hpp index 033933bcbf1b..d8fa5893bcde 100644 --- a/src/hotspot/share/gc/parallel/psCardTable.hpp +++ b/src/hotspot/share/gc/parallel/psCardTable.hpp @@ -69,6 +69,8 @@ class PSCardTable: public CardTable { HeapWord* start, HeapWord* end); + void commit_delta_excluding(MemRegion delta, MemRegion already_committed, bool should_clear_card = false); + public: PSCardTable(MemRegion whole_heap) : CardTable(whole_heap), _preprocessing_active_workers(0) {} @@ -85,6 +87,11 @@ class PSCardTable: public CardTable { bool is_dirty_for_addr(void *addr); + void verify_clean_cards(MemRegion mr) const NOT_DEBUG_RETURN; + + void right_shift_gen_boundary(MemRegion new_region0, MemRegion new_region1); + void left_shift_gen_boundary(MemRegion new_region0, MemRegion new_region1); + // Card marking void inline_write_ref_field_gc(void* field) { CardValue* byte = byte_for(field); diff --git a/src/hotspot/share/gc/parallel/psHeapVirtualSpace.cpp b/src/hotspot/share/gc/parallel/psHeapVirtualSpace.cpp new file mode 100644 index 000000000000..741db2692e3e --- /dev/null +++ b/src/hotspot/share/gc/parallel/psHeapVirtualSpace.cpp @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "gc/parallel/psHeapVirtualSpace.hpp" +#include "logging/log.hpp" +#include "memory/reservedSpace.hpp" +#include "runtime/os.hpp" +#include "utilities/align.hpp" + +PSHeapVirtualSpace::PSHeapVirtualSpace(ReservedSpace rs, size_t alignment, char* gen_boundary) : + _alignment(alignment), + _page_size(rs.page_size()), + _reserved_low_addr(rs.base()), + _reserved_high_addr(rs.base() + rs.size()), + _old_gen_committed_high_addr(rs.base()), + _gen_boundary(gen_boundary), + _young_gen_committed_high_addr(gen_boundary), + _special(rs.special()) { + assert(is_aligned(rs.size(), alignment), "precondition"); +} + +PSHeapVirtualSpace::~PSHeapVirtualSpace() { + _reserved_low_addr = _reserved_high_addr = nullptr; + _gen_boundary = nullptr; + _old_gen_committed_high_addr = nullptr; + _young_gen_committed_high_addr = nullptr; + _special = false; +} + +void PSHeapVirtualSpace::right_shift_gen_boundary(char* new_boundary) { + assert(is_aligned(new_boundary, _alignment), "boundary alignment"); + assert(new_boundary > _reserved_low_addr && new_boundary <= _reserved_high_addr, "boundary out of range"); + assert(_old_gen_committed_high_addr <= _gen_boundary, "precondition"); + assert(_gen_boundary < new_boundary, "precondition"); + + char* original_gen_boundary = _gen_boundary; + char* original_young_gen_committed_high_addr = _young_gen_committed_high_addr; + const size_t original_young_gen_committed_size = young_gen_committed_size(); + + // Ensure old-gen is committed up to the current generation boundary. + if (_old_gen_committed_high_addr < original_gen_boundary) { + size_t diff = pointer_delta(original_gen_boundary, _old_gen_committed_high_addr, sizeof(char)); + if (!expand_old_gen(diff)) { + vm_exit_out_of_memory(diff, OOM_MMAP_ERROR, "right_shift_gen_boundary: fully commit old-gen"); + } + } + assert(_old_gen_committed_high_addr == original_gen_boundary, "inv"); + + _gen_boundary = new_boundary; + + if (original_young_gen_committed_high_addr < new_boundary) { + _old_gen_committed_high_addr = original_young_gen_committed_high_addr; + size_t diff = pointer_delta(new_boundary, original_young_gen_committed_high_addr, sizeof(char)); + if (!expand_old_gen(diff)) { + vm_exit_out_of_memory(diff, OOM_MMAP_ERROR, "right_shift_gen_boundary: expand_old_gen"); + } + _young_gen_committed_high_addr = new_boundary; + } else { + _old_gen_committed_high_addr = new_boundary; + } + // maintain old-gen fully committed + assert(_old_gen_committed_high_addr == _gen_boundary, "inv"); + + size_t young_gen_remaining_size = pointer_delta(_reserved_high_addr, _young_gen_committed_high_addr, sizeof(char)); + // Try to maintain the same committed size in young-gen + if (young_gen_remaining_size > 0) { + size_t current_committed = young_gen_committed_size(); + if (original_young_gen_committed_size > current_committed) { + size_t diff = original_young_gen_committed_size - current_committed; + diff = MIN2(diff, young_gen_remaining_size); + if (!expand_young_gen(diff)) { + vm_exit_out_of_memory(diff, OOM_MMAP_ERROR, "right_shift_gen_boundary: expand_young_gen"); + } + } + } +} + +void PSHeapVirtualSpace::left_shift_gen_boundary(char* new_boundary) { + assert(is_aligned(new_boundary, _alignment), "boundary alignment"); + assert(new_boundary > _reserved_low_addr && new_boundary < _reserved_high_addr, "boundary out of range"); + assert(new_boundary < _gen_boundary, "precondition"); + + if (new_boundary <= _old_gen_committed_high_addr) { + // [_old_gen_committed_high_addr, _gen_boundary) needs to become committed + // and re-assigned to young-gen. + size_t to_commit_size = pointer_delta(_gen_boundary, _old_gen_committed_high_addr, sizeof(char)); + if (to_commit_size > 0) { + if (!expand_old_gen(to_commit_size)) { + vm_exit_out_of_memory(to_commit_size, OOM_MMAP_ERROR, "left_shift_gen_boundary: expand_old_gen"); + } + } + _old_gen_committed_high_addr = new_boundary; + } else { + size_t to_commit_bytes = pointer_delta(_gen_boundary, new_boundary, sizeof(char)); + if (!left_expand_young_gen(to_commit_bytes)) { + vm_exit_out_of_memory(to_commit_bytes, OOM_MMAP_ERROR, "left_expand_young_gen"); + } + } + + _gen_boundary = new_boundary; +} + +void PSHeapVirtualSpace::commit_old_gen_to_boundary() { + assert(_old_gen_committed_high_addr <= _gen_boundary, "precondition"); + if (_old_gen_committed_high_addr < _gen_boundary) { + size_t diff = pointer_delta(_gen_boundary, _old_gen_committed_high_addr, sizeof(char)); + if (!expand_old_gen(diff)) { + vm_exit_out_of_memory(diff, OOM_MMAP_ERROR, "commit_old_gen_to_boundary"); + } + } +} + +bool PSHeapVirtualSpace::expand_old_gen(size_t bytes) { + assert(bytes != 0, "precondition"); + assert(is_aligned(bytes, _alignment), "arg not aligned"); + + char* old_high = _old_gen_committed_high_addr; + char* new_high = old_high + bytes; + + assert(new_high <= _gen_boundary, "cannot expand beyond boundary"); + + if (_special || os::commit_memory(old_high, bytes, _alignment, !ExecMem)) { + _old_gen_committed_high_addr = new_high; + return true; + } + + log_warning(gc)("PSHeapVirtualSpace::expand_old_gen failed: " + "os::commit_memory(" PTR_FORMAT ", %zu, %zu, %d) failed.", + p2i(old_high), bytes, _alignment, !ExecMem); + + return false; +} + +void PSHeapVirtualSpace::shrink_old_gen(size_t bytes) { + assert(bytes != 0, "precondition"); + assert(bytes < old_gen_committed_size(), "cannot shrink more than committed"); + assert(is_aligned(bytes, _alignment), "arg not aligned"); + + char* old_high = _old_gen_committed_high_addr; + char* new_high = old_high - bytes; + + if (!_special) { + os::uncommit_memory(new_high, bytes); + } + + _old_gen_committed_high_addr = new_high; +} + +bool PSHeapVirtualSpace::expand_young_gen(size_t bytes) { + assert(bytes != 0, "precondition"); + assert(is_aligned(bytes, _alignment), "arg not aligned"); + + char* old_high = _young_gen_committed_high_addr; + char* new_high = old_high + bytes; + + assert(new_high <= _reserved_high_addr, "cannot expand beyond reserved"); + + if (_special || os::commit_memory(old_high, bytes, _alignment, !ExecMem)) { + _young_gen_committed_high_addr = new_high; + return true; + } + + log_warning(gc)("PSHeapVirtualSpace::expand_young_gen failed: " + "os::commit_memory(" PTR_FORMAT ", %zu, %zu, %d) failed.", + p2i(old_high), bytes, _alignment, !ExecMem); + + return false; +} + +bool PSHeapVirtualSpace::left_expand_young_gen(size_t bytes) { + assert(bytes != 0, "precondition"); + assert(is_aligned(bytes, _alignment), "precondition"); + + size_t old_gen_uncommitted_size = pointer_delta(_gen_boundary, _old_gen_committed_high_addr, sizeof(char)); + assert(old_gen_uncommitted_size >= bytes, "precondition"); + + char* new_gen_boundary = _gen_boundary - bytes; + assert(new_gen_boundary >= _old_gen_committed_high_addr, "inv"); + + if (_special || os::commit_memory(new_gen_boundary, bytes, _alignment, !ExecMem)) { + return true; + } + + log_warning(gc)("PSHeapVirtualSpace::left_expand_young_gen failed: " + "os::commit_memory(" PTR_FORMAT ", %zu, %zu, %d) failed.", + p2i(new_gen_boundary), bytes, _alignment, !ExecMem); + + return false; +} + +void PSHeapVirtualSpace::shrink_young_gen(size_t bytes) { + assert(bytes != 0, "precondition"); + assert(bytes < young_gen_committed_size(), "cannot shrink more than committed"); + assert(is_aligned(bytes, _alignment), "arg not aligned"); + + char* old_high = _young_gen_committed_high_addr; + char* new_high = old_high - bytes; + + if (!_special) { + os::uncommit_memory(new_high, bytes); + } + + _young_gen_committed_high_addr = new_high; +} + +#ifndef PRODUCT +void PSHeapVirtualSpace::verify() const { + assert(is_aligned(_alignment, _page_size), "inv"); + assert(is_aligned(_reserved_low_addr, _alignment), "bad reserved_low_addr"); + assert(is_aligned(_reserved_high_addr, _alignment), "bad reserved_high_addr"); + assert(is_aligned(_gen_boundary, _alignment), "bad gen_boundary"); + assert(is_aligned(_old_gen_committed_high_addr, _alignment), "bad old_gen_committed_high_addr"); + assert(is_aligned(_young_gen_committed_high_addr, _alignment), "bad young_gen_committed_high_addr"); + + assert(_reserved_low_addr <= _old_gen_committed_high_addr, "inv"); + assert(_old_gen_committed_high_addr <= _gen_boundary, "inv"); + assert(_gen_boundary <= _young_gen_committed_high_addr, "inv"); + assert(_young_gen_committed_high_addr <= _reserved_high_addr, "inv"); +} +#endif diff --git a/src/hotspot/share/gc/parallel/psHeapVirtualSpace.hpp b/src/hotspot/share/gc/parallel/psHeapVirtualSpace.hpp new file mode 100644 index 000000000000..f2b8b71a6630 --- /dev/null +++ b/src/hotspot/share/gc/parallel/psHeapVirtualSpace.hpp @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_PARALLEL_PSHEAPVIRTUALSPACE_HPP +#define SHARE_GC_PARALLEL_PSHEAPVIRTUALSPACE_HPP + +#include "memory/allocation.hpp" + +class ReservedSpace; + +// Manages the heap reservation shared by the old and young generations. The +// generations are separated by a movable boundary and committed independently. +class PSHeapVirtualSpace : public CHeapObj { + friend class VMStructs; + + // The space is committed/uncommitted in chunks of size _alignment. The + // ReservedSpace passed to the constructor must be aligned to this value. + const size_t _alignment; + + // OS page size used. If using Transparent Huge Pages, it's the desired large page-size. + const size_t _page_size; + + char* _reserved_low_addr; + char* _reserved_high_addr; + + char* _old_gen_committed_high_addr; + + char* _gen_boundary; + + char* _young_gen_committed_high_addr; + + // The entire space has been committed and pinned in memory, no + // os::commit_memory() or os::uncommit_memory(). + bool _special; + + size_t old_gen_committed_size() const { + return pointer_delta(_old_gen_committed_high_addr, _reserved_low_addr, sizeof(char)); + } + + size_t young_gen_committed_size() const { + return pointer_delta(_young_gen_committed_high_addr, _gen_boundary, sizeof(char)); + } + +public: + PSHeapVirtualSpace(ReservedSpace rs, size_t alignment, char* gen_boundary); + ~PSHeapVirtualSpace(); + + size_t alignment() const { return _alignment; } + size_t page_size() const { return _page_size; } + + size_t reserved_bytes() const { + return pointer_delta(_reserved_high_addr, _reserved_low_addr, sizeof(char)); + } + + char* old_gen_low_addr() const { return _reserved_low_addr; } + char* old_gen_high_addr() const { return _gen_boundary; } + + char* young_gen_low_addr() const { return _gen_boundary; } + char* young_gen_high_addr() const { return _reserved_high_addr; } + + char* old_gen_committed_high_addr() const { return _old_gen_committed_high_addr; } + char* young_gen_committed_high_addr() const { return _young_gen_committed_high_addr; } + + // Generation boundary management + char* gen_boundary() const { return _gen_boundary; } + void right_shift_gen_boundary(char* new_boundary); + void left_shift_gen_boundary(char* new_boundary); + void commit_old_gen_to_boundary(); + + bool expand_old_gen(size_t bytes); + + void shrink_old_gen(size_t bytes); + + bool expand_young_gen(size_t bytes); + // Usually we expand at higher address (right). + // This API performs expansion at lower address (left). + bool left_expand_young_gen(size_t bytes); + + void shrink_young_gen(size_t bytes); +#ifndef PRODUCT + void verify() const; +#endif +}; + +#endif // SHARE_GC_PARALLEL_PSHEAPVIRTUALSPACE_HPP diff --git a/src/hotspot/share/gc/parallel/psMemoryPool.cpp b/src/hotspot/share/gc/parallel/psMemoryPool.cpp index 13304ca18ad2..efa2f2f74059 100644 --- a/src/hotspot/share/gc/parallel/psMemoryPool.cpp +++ b/src/hotspot/share/gc/parallel/psMemoryPool.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,9 +27,11 @@ PSOldGenerationPool::PSOldGenerationPool(PSOldGen* old_gen, const char* name, bool support_usage_threshold) : - CollectedMemoryPool(name, old_gen->capacity_in_bytes(), - old_gen->reserved().byte_size(), support_usage_threshold), _old_gen(old_gen) { -} + CollectedMemoryPool(name, + old_gen->capacity_in_bytes(), + old_gen->max_gen_size(), + support_usage_threshold), + _old_gen(old_gen) {} MemoryUsage PSOldGenerationPool::get_memory_usage() { size_t maxSize = max_size(); @@ -49,14 +51,14 @@ PSEdenSpacePool::PSEdenSpacePool(PSYoungGen* young_gen, MutableSpace* space, const char* name, bool support_usage_threshold) : - CollectedMemoryPool(name, space->capacity_in_bytes(), + CollectedMemoryPool(name, + space->capacity_in_bytes(), (young_gen->max_gen_size() - young_gen->from_space()->capacity_in_bytes() - young_gen->to_space()->capacity_in_bytes()), support_usage_threshold), _young_gen(young_gen), - _space(space) { -} + _space(space) {} MemoryUsage PSEdenSpacePool::get_memory_usage() { size_t maxSize = max_size(); diff --git a/src/hotspot/share/gc/parallel/psMemoryPool.hpp b/src/hotspot/share/gc/parallel/psMemoryPool.hpp index 72687049ecc3..36faeb44b11b 100644 --- a/src/hotspot/share/gc/parallel/psMemoryPool.hpp +++ b/src/hotspot/share/gc/parallel/psMemoryPool.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ class PSOldGenerationPool : public CollectedMemoryPool { MemoryUsage get_memory_usage(); size_t used_in_bytes() { return _old_gen->used_in_bytes(); } - size_t max_size() const { return _old_gen->reserved().byte_size(); } + size_t max_size() const { return _old_gen->max_gen_size(); } }; class PSEdenSpacePool : public CollectedMemoryPool { diff --git a/src/hotspot/share/gc/parallel/psOldGen.cpp b/src/hotspot/share/gc/parallel/psOldGen.cpp index 6a9f8bfeedc6..ac5a41648f4d 100644 --- a/src/hotspot/share/gc/parallel/psOldGen.cpp +++ b/src/hotspot/share/gc/parallel/psOldGen.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,39 +38,32 @@ #include "runtime/java.hpp" #include "utilities/align.hpp" -PSOldGen::PSOldGen(ReservedSpace rs, size_t initial_size, size_t min_size, +PSOldGen::PSOldGen(PSHeapVirtualSpace* vs, + ObjectStartArray* object_start_array, + size_t initial_size, size_t max_size): - _min_gen_size(min_size), + _heap_vs(vs), + _start_array(object_start_array), _max_gen_size(max_size) { - initialize(rs, initial_size, SpaceAlignment); -} + if (!_heap_vs->expand_old_gen(initial_size)) { + vm_exit_during_initialization("Could not reserve enough space for object heap"); + } -void PSOldGen::initialize(ReservedSpace rs, size_t initial_size, size_t alignment) { - initialize_virtual_space(rs, initial_size, alignment); initialize_work(); initialize_performance_counters(); } -void PSOldGen::initialize_virtual_space(ReservedSpace rs, - size_t initial_size, - size_t alignment) { - - _virtual_space = new PSVirtualSpace(rs, alignment); - if (!_virtual_space->expand_by(initial_size)) { - vm_exit_during_initialization("Could not reserve enough space for " - "object heap"); - } +size_t PSOldGen::min_gen_size() const { + // The old generation may borrow from or lend to young gen. MinOldSize is + // derived for the startup split; the dynamic floor is structural while + // ParallelScavengeHeap enforces MinHeapSize for total committed capacity. + return SpaceAlignment; } void PSOldGen::initialize_work() { - MemRegion const reserved_mr = reserved(); - assert(reserved_mr.byte_size() == max_gen_size(), "invariant"); - - // Card table stuff: for all committed memory - MemRegion committed_mr((HeapWord*)virtual_space()->low(), - (HeapWord*)virtual_space()->high()); + const MemRegion committed_mr = committed(); if (ZapUnusedHeapArea) { // Mangle newly committed space immediately rather than @@ -82,13 +75,13 @@ void PSOldGen::initialize_work() { } ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - PSCardTable* ct = heap->card_table(); - ct->resize_covered_region(committed_mr); + heap->card_table()->resize_covered_region(committed_mr); // Verify that the start and end of this generation is the start of a card. // If this wasn't true, a single card could span more than one generation, // which would cause problems when we commit/uncommit memory, and when we // clear and dirty cards. + const MemRegion reserved_mr = reserved(); guarantee(CardTable::is_card_aligned(reserved_mr.start()), "generation must be card aligned"); // Check the heap layout documented at `class ParallelScavengeHeap`. assert(reserved_mr.end() != heap->reserved_region().end(), "invariant"); @@ -98,26 +91,30 @@ void PSOldGen::initialize_work() { // ObjectSpace stuff // - _object_space = new MutableSpace(virtual_space()->page_size()); + _object_space = new MutableSpace(_heap_vs->page_size()); object_space()->initialize(committed_mr, SpaceDecorator::Clear, SpaceDecorator::Mangle, MutableSpace::SetupPages, - &ParallelScavengeHeap::heap()->workers()); + &heap->workers()); // Update the start_array - _start_array = new ObjectStartArray(reserved_mr); start_array()->set_covered_region(committed_mr); } void PSOldGen::initialize_performance_counters() { const char* perf_data_name = "old"; - _gen_counters = new GenerationCounters(perf_data_name, 1, 1, min_gen_size(), - max_gen_size(), virtual_space()->committed_size()); + const size_t max_size = max_gen_size(); + _gen_counters = new GenerationCounters(perf_data_name, + 1, + 1, + min_gen_size(), + max_size, + committed_size()); _space_counters = new HSpaceCounters(_gen_counters->name_space(), perf_data_name, 0, - virtual_space()->reserved_size(), + max_size, _object_space->capacity_in_bytes()); } @@ -188,19 +185,18 @@ bool PSOldGen::expand_for_allocate(size_t word_size) { return result; } -void PSOldGen::try_expand_till_size(size_t target_capacity_bytes) { - if (target_capacity_bytes <= capacity_in_bytes()) { - // Current capacity is enough - return; +bool PSOldGen::try_accommodate(size_t target_capacity_bytes) { + if (target_capacity_bytes > reserved_size()) { + // Exceeds reserved size + return false; } - if (capacity_in_bytes() == max_gen_size()) { - // Already at max size - return; + if (target_capacity_bytes > capacity_in_bytes()) { + size_t to_expand_bytes = target_capacity_bytes - capacity_in_bytes(); + expand(to_expand_bytes); } - - size_t to_expand_bytes = target_capacity_bytes - capacity_in_bytes(); - expand(to_expand_bytes); + assert(capacity_in_bytes() >= target_capacity_bytes, "postcondition"); + return true; } bool PSOldGen::expand(size_t bytes) { @@ -222,76 +218,59 @@ bool PSOldGen::expand(size_t bytes) { } assert(bytes > 0, "precondition"); #endif - const size_t remaining_bytes = virtual_space()->uncommitted_size(); + + const size_t remaining_bytes = uncommitted_size(); if (remaining_bytes == 0) { return false; } - const size_t alignment = virtual_space()->alignment(); - size_t aligned_bytes = align_up(MIN2(bytes, remaining_bytes), alignment); - size_t aligned_expand_bytes = align_up(MinHeapDeltaBytes, alignment); - - if (UseNUMA) { - // With NUMA we use round-robin page allocation for the old gen. Expand by at least - // providing a page per lgroup. Alignment is larger or equal to the page size. - aligned_expand_bytes = MAX2(aligned_expand_bytes, alignment * os::numa_get_groups_num()); - } - bool success = false; - if (aligned_expand_bytes > aligned_bytes) { - success = expand_by(aligned_expand_bytes); - } - if (!success) { - success = expand_by(aligned_bytes); - } - if (!success) { - success = expand_to_reserved(); - } + bytes = MAX2(bytes, MinHeapDeltaBytes); - return success; + size_t aligned_bytes = align_up(bytes, _heap_vs->alignment()); + aligned_bytes = MIN2(aligned_bytes, remaining_bytes); + + // The request is already clamped to the remaining reservation. A failure + // below is therefore an OS commit failure, not a size-selection failure. + expand_by(aligned_bytes); + + return true; } bool PSOldGen::expand_by(size_t bytes) { assert(bytes > 0, "precondition"); - bool result = virtual_space()->expand_by(bytes); - if (result) { - if (ZapUnusedHeapArea) { - // We need to mangle the newly expanded area. The memregion spans - // end -> new_end, we assume that top -> end is already mangled. - // Do the mangling before post_resize() is called because - // the space is available for allocation after post_resize(); - HeapWord* const virtual_space_high = (HeapWord*) virtual_space()->high(); - assert(object_space()->end() < virtual_space_high, - "Should be true before post_resize()"); - MemRegion mangle_region(object_space()->end(), virtual_space_high); - // Note that the object space has not yet been updated to - // coincide with the new underlying virtual space. - SpaceMangler::mangle_region(mangle_region); - } - post_resize(); - if (UsePerfData) { - _space_counters->update_capacity(_object_space->capacity_in_bytes()); - _gen_counters->update_capacity(_virtual_space->committed_size()); - } + + if (!_heap_vs->expand_old_gen(bytes)) { + vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "PSOldGen::expand"); } - if (result) { - size_t new_mem_size = virtual_space()->committed_size(); - size_t old_mem_size = new_mem_size - bytes; - log_debug(gc)("Expanding %s from %zuK by %zuK to %zuK", - name(), old_mem_size/K, bytes/K, new_mem_size/K); + if (ZapUnusedHeapArea) { + // We need to mangle the newly expanded area. The memregion spans + // end -> new_end, we assume that top -> end is already mangled. + // Do the mangling before post_resize() is called because + // the space is available for allocation after post_resize(); + HeapWord* const virtual_space_high = (HeapWord*)_heap_vs->old_gen_committed_high_addr(); + assert(object_space()->end() < virtual_space_high, + "Should be true before post_resize()"); + MemRegion mangle_region(object_space()->end(), virtual_space_high); + // Note that the object space has not yet been updated to + // coincide with the new underlying virtual space. + SpaceMangler::mangle_region(mangle_region); } - return result; -} + post_resize(); -bool PSOldGen::expand_to_reserved() { - bool result = false; - const size_t remaining_bytes = virtual_space()->uncommitted_size(); - if (remaining_bytes > 0) { - result = expand_by(remaining_bytes); - DEBUG_ONLY(if (!result) log_warning(gc)("grow to reserve failed")); + if (UsePerfData) { + _space_counters->update_capacity(_object_space->capacity_in_bytes()); + _gen_counters->update_capacity(committed_size()); } - return result; + + size_t new_mem_size = committed_size(); + size_t old_mem_size = new_mem_size - bytes; + + log_debug(gc)("Expanding %s from %zuK by %zuK to %zuK", + name(), old_mem_size / K, bytes / K, new_mem_size / K); + + return true; } void PSOldGen::shrink(size_t bytes) { @@ -299,12 +278,12 @@ void PSOldGen::shrink(size_t bytes) { assert(SafepointSynchronize::is_at_safepoint(), "precondition"); assert(bytes > 0, "precondition"); - size_t size = align_down(bytes, virtual_space()->alignment()); - if (size > 0) { - virtual_space()->shrink_by(bytes); + bytes = align_down(bytes, _heap_vs->alignment()); + if (bytes > 0) { + _heap_vs->shrink_old_gen(bytes); post_resize(); - size_t new_mem_size = virtual_space()->committed_size(); + size_t new_mem_size = committed_size(); size_t old_mem_size = new_mem_size + bytes; log_debug(gc)("Shrinking %s from %zuK by %zuK to %zuK", name(), old_mem_size/K, bytes/K, new_mem_size/K); @@ -320,24 +299,30 @@ void PSOldGen::complete_loaded_archive_space(MemRegion archive_space) { } } +void PSOldGen::reinit_after_committed_mr_change() { + const MemRegion committed_mr = committed(); + start_array()->set_covered_region(committed_mr); + + object_space()->initialize(committed_mr, + SpaceDecorator::DontClear, + SpaceDecorator::DontMangle, + MutableSpace::SetupPages, + &ParallelScavengeHeap::heap()->workers()); + + assert((char*) object_space()->end() == _heap_vs->old_gen_committed_high_addr(), "postcondition"); +} + void PSOldGen::resize(size_t desired_capacity) { - const size_t alignment = virtual_space()->alignment(); - const size_t size_before = virtual_space()->committed_size(); + const size_t alignment = _heap_vs->alignment(); + const size_t size_before = committed_size(); size_t new_size = desired_capacity; // Adjust according to our min and max - new_size = clamp(new_size, min_gen_size(), max_gen_size()); + new_size = clamp(new_size, min_gen_size(), reserved_size()); new_size = align_up(new_size, alignment); const size_t current_size = capacity_in_bytes(); - log_trace(gc, ergo)("AdaptiveSizePolicy::old generation size: " - "used: %zu" - " capacity %zu -> %zu" - " gen limits: %zu / %zu", - used_in_bytes(), current_size, new_size, - max_gen_size(), min_gen_size()); - if (new_size == current_size) { // No change requested return; @@ -353,7 +338,7 @@ void PSOldGen::resize(size_t desired_capacity) { log_trace(gc, ergo)("AdaptiveSizePolicy::old generation size: collection: %d (%zu) -> (%zu) ", ParallelScavengeHeap::heap()->total_collections(), size_before, - virtual_space()->committed_size()); + committed_size()); } // NOTE! We need to be careful about resizing. During a GC, multiple @@ -361,27 +346,36 @@ void PSOldGen::resize(size_t desired_capacity) { // heap resizing to become visible before we have correctly resized // all heap related data structures, we may cause program failures. void PSOldGen::post_resize() { - // First construct a memregion representing the new size - MemRegion new_memregion((HeapWord*)virtual_space()->low(), - (HeapWord*)virtual_space()->high()); - size_t new_word_size = new_memregion.word_size(); + auto heap = ParallelScavengeHeap::heap(); + const MemRegion committed_mr = committed(); + HeapWord* const old_end = object_space()->end(); + if (committed_mr.end() < old_end) { + // Shrinking + heap->card_table()->verify_clean_cards(MemRegion{committed_mr.end(), old_end}); + } + size_t new_word_size = committed_mr.word_size(); - start_array()->set_covered_region(new_memregion); - ParallelScavengeHeap::heap()->card_table()->resize_covered_region(new_memregion); + start_array()->set_covered_region(committed_mr); - WorkerThreads* workers = Thread::current()->is_VM_thread() ? - &ParallelScavengeHeap::heap()->workers() : nullptr; + heap->card_table()->resize_covered_region(committed_mr); + if (old_end < committed_mr.end()) { + heap->card_table()->verify_clean_cards(MemRegion(old_end, committed_mr.end())); + } + + WorkerThreads* workers = Thread::current()->is_VM_thread() + ? &heap->workers() + : nullptr; // The update of the space's end is done by this call. As that // makes the new space available for concurrent allocation, this // must be the last step when expanding. - object_space()->initialize(new_memregion, + object_space()->initialize(committed_mr, SpaceDecorator::DontClear, SpaceDecorator::DontMangle, MutableSpace::SetupPages, workers); - assert(new_word_size == heap_word_size(object_space()->capacity_in_bytes()), + assert(new_word_size == object_space()->capacity_in_bytes()/HeapWordSize, "Sanity"); } @@ -389,7 +383,10 @@ void PSOldGen::print() const { print_on(tty);} void PSOldGen::print_on(outputStream* st) const { st->print("%-15s", name()); st->print(" total %zuK, used %zuK ", capacity_in_bytes() / K, used_in_bytes() / K); - virtual_space()->print_space_boundaries_on(st); + st->print_cr("Old Gen: [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ")", + p2i(_heap_vs->old_gen_low_addr()), + p2i(_heap_vs->old_gen_committed_high_addr()), + p2i(_heap_vs->old_gen_high_addr())); StreamIndentor si(st, 1); object_space()->print_on(st, "object "); @@ -398,7 +395,7 @@ void PSOldGen::print_on(outputStream* st) const { void PSOldGen::update_counters() { if (UsePerfData) { _space_counters->update_all(_object_space->capacity_in_bytes(), _object_space->used_in_bytes()); - _gen_counters->update_capacity(_virtual_space->committed_size()); + _gen_counters->update_capacity(committed_size()); } } diff --git a/src/hotspot/share/gc/parallel/psOldGen.hpp b/src/hotspot/share/gc/parallel/psOldGen.hpp index c8e6ada3ebd0..496aa755c461 100644 --- a/src/hotspot/share/gc/parallel/psOldGen.hpp +++ b/src/hotspot/share/gc/parallel/psOldGen.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,75 +27,79 @@ #include "gc/parallel/mutableSpace.hpp" #include "gc/parallel/objectStartArray.hpp" -#include "gc/parallel/psVirtualspace.hpp" +#include "gc/parallel/psHeapVirtualSpace.hpp" #include "gc/shared/generationCounters.hpp" #include "gc/shared/hSpaceCounters.hpp" -#include "runtime/mutexLocker.hpp" -#include "runtime/safepoint.hpp" class ReservedSpace; class PSOldGen : public CHeapObj { friend class VMStructs; private: - PSVirtualSpace* _virtual_space; // Controls mapping and unmapping of virtual mem + PSHeapVirtualSpace* _heap_vs; // Controls mapping and unmapping of virtual mem ObjectStartArray* _start_array; // Keeps track of where objects start in a 512b block MutableSpace* _object_space; // Where all the objects live + // Sizing information, in bytes, set in constructor + const size_t _max_gen_size; + // Performance Counters GenerationCounters* _gen_counters; HSpaceCounters* _space_counters; - // Sizing information, in bytes, set in constructor - const size_t _min_gen_size; - const size_t _max_gen_size; - // Block size for parallel iteration static const size_t IterateBlockSize = 1024 * 1024; bool expand_for_allocate(size_t word_size); bool expand(size_t bytes); bool expand_by(size_t bytes); - bool expand_to_reserved(); void post_resize(); - void initialize(ReservedSpace rs, size_t initial_size, size_t alignment); - void initialize_virtual_space(ReservedSpace rs, size_t initial_size, size_t alignment); void initialize_work(); void initialize_performance_counters(); public: // Initialize the generation. - PSOldGen(ReservedSpace rs, size_t initial_size, size_t min_size, + PSOldGen(PSHeapVirtualSpace* vs, + ObjectStartArray* object_start_array, + size_t initial_size, size_t max_size); MemRegion reserved() const { - return MemRegion((HeapWord*)(_virtual_space->low_boundary()), - (HeapWord*)(_virtual_space->high_boundary())); + return MemRegion((HeapWord*) _heap_vs->old_gen_low_addr(), + (HeapWord*) _heap_vs->old_gen_high_addr()); } MemRegion committed() const { - return MemRegion((HeapWord*)(_virtual_space->low()), - (HeapWord*)(_virtual_space->high())); + return MemRegion((HeapWord*) _heap_vs->old_gen_low_addr(), + (HeapWord*) _heap_vs->old_gen_committed_high_addr()); } + size_t reserved_size() const { return reserved().byte_size(); } + size_t committed_size() const { return committed().byte_size(); } + + size_t uncommitted_size() const { + return pointer_delta(_heap_vs->old_gen_high_addr(), + _heap_vs->old_gen_committed_high_addr(), + sizeof(char)); + } + + size_t min_gen_size() const; size_t max_gen_size() const { return _max_gen_size; } - size_t min_gen_size() const { return _min_gen_size; } - void try_expand_till_size(size_t live_bytes); + bool try_accommodate(size_t live_bytes); - bool is_in(const void* p) const { - return _virtual_space->is_in_committed((void *)p); + bool is_in(const void* p) const { + return committed().contains(p); } bool is_in_reserved(const void* p) const { - return _virtual_space->is_in_reserved(p); + return reserved().contains(p); } MutableSpace* object_space() const { return _object_space; } ObjectStartArray* start_array() { return _start_array; } - PSVirtualSpace* virtual_space() const { return _virtual_space;} // Size info size_t capacity_in_bytes() const { return object_space()->capacity_in_bytes(); } @@ -104,6 +108,8 @@ class PSOldGen : public CHeapObj { void complete_loaded_archive_space(MemRegion archive_space); + void reinit_after_committed_mr_change(); + // Calculating new sizes void resize(size_t desired_capacity); diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index df64f1797446..1aef37b1ecc9 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -150,67 +150,11 @@ void ParallelCompactData::RegionData::verify_clear() { #endif SpaceInfo PSParallelCompact::_space_info[PSParallelCompact::last_space_id]; - +HeapWord* PSParallelCompact::_old_space_dense_prefix = nullptr; +HeapWord* PSParallelCompact::_old_space_new_top = nullptr; SpanSubjectToDiscoveryClosure PSParallelCompact::_span_based_discoverer; ReferenceProcessor* PSParallelCompact::_ref_processor = nullptr; -void SplitInfo::record(size_t split_region_idx, HeapWord* split_point, size_t preceding_live_words) { - assert(split_region_idx != 0, "precondition"); - - // Obj denoted by split_point will be deferred to the next space. - assert(split_point != nullptr, "precondition"); - - const ParallelCompactData& sd = PSParallelCompact::summary_data(); - - PSParallelCompact::RegionData* split_region_ptr = sd.region(split_region_idx); - assert(preceding_live_words < split_region_ptr->data_size(), "inv"); - - HeapWord* preceding_destination = split_region_ptr->destination(); - assert(preceding_destination != nullptr, "inv"); - - // How many regions does the preceding part occupy - uint preceding_destination_count; - if (preceding_live_words == 0) { - preceding_destination_count = 0; - } else { - // -1 so that the ending address doesn't fall on the region-boundary - if (sd.region_align_down(preceding_destination) == - sd.region_align_down(preceding_destination + preceding_live_words - 1)) { - preceding_destination_count = 1; - } else { - preceding_destination_count = 2; - } - } - - _split_region_idx = split_region_idx; - _split_point = split_point; - _preceding_live_words = preceding_live_words; - _preceding_destination = preceding_destination; - _preceding_destination_count = preceding_destination_count; -} - -void SplitInfo::clear() -{ - _split_region_idx = 0; - _split_point = nullptr; - _preceding_live_words = 0; - _preceding_destination = nullptr; - _preceding_destination_count = 0; - assert(!is_valid(), "sanity"); -} - -#ifdef ASSERT -void SplitInfo::verify_clear() -{ - assert(_split_region_idx == 0, "not clear"); - assert(_split_point == nullptr, "not clear"); - assert(_preceding_live_words == 0, "not clear"); - assert(_preceding_destination == nullptr, "not clear"); - assert(_preceding_destination_count == 0, "not clear"); -} -#endif // #ifdef ASSERT - - void PSParallelCompact::print_on(outputStream* st) { _mark_bitmap.print_on(st); } @@ -284,108 +228,6 @@ void ParallelCompactData::clear_range(size_t beg_region, size_t end_region) { } } -// The total live words on src_region would overflow the target space, so find -// the overflowing object and record the split point. The invariant is that an -// obj should not cross space boundary. -HeapWord* ParallelCompactData::summarize_split_space(size_t src_region, - SplitInfo& split_info, - HeapWord* const destination, - HeapWord* const target_end, - HeapWord** target_next) { - assert(destination <= target_end, "sanity"); - assert(destination + _region_data[src_region].data_size() > target_end, - "region should not fit into target space"); - assert(is_region_aligned(target_end), "sanity"); - - size_t partial_obj_size = _region_data[src_region].partial_obj_size(); - - if (destination + partial_obj_size > target_end) { - assert(partial_obj_size > 0, "inv"); - // The overflowing obj is from a previous region. - // - // source-regions: - // - // *************** - // | A|AA | - // *************** - // ^ - // | split-point - // - // dest-region: - // - // ******** - // |~~~~A | - // ******** - // ^^ - // || target-space-end - // | - // | destination - // - // AAA would overflow target-space. - // - HeapWord* overflowing_obj = _region_data[src_region].partial_obj_addr(); - size_t split_region = addr_to_region_idx(overflowing_obj); - - // The number of live words before the overflowing object on this split region - size_t preceding_live_words; - if (is_region_aligned(overflowing_obj)) { - preceding_live_words = 0; - } else { - // Words accounted by the overflowing object on the split region - size_t overflowing_size = pointer_delta(region_align_up(overflowing_obj), overflowing_obj); - preceding_live_words = region(split_region)->data_size() - overflowing_size; - } - - split_info.record(split_region, overflowing_obj, preceding_live_words); - - // The [overflowing_obj, src_region_start) part has been accounted for, so - // must move back the new_top, now that this overflowing obj is deferred. - HeapWord* new_top = destination - pointer_delta(region_to_addr(src_region), overflowing_obj); - - // If the overflowing obj was relocated to its original destination, - // those destination regions would have their source_region set. Now that - // this overflowing obj is relocated somewhere else, reset the - // source_region. - { - size_t range_start = addr_to_region_idx(region_align_up(new_top)); - size_t range_end = addr_to_region_idx(region_align_up(destination)); - for (size_t i = range_start; i < range_end; ++i) { - region(i)->set_source_region(0); - } - } - - // Update new top of target space - *target_next = new_top; - - return overflowing_obj; - } - - // Obj-iteration to locate the overflowing obj - HeapWord* region_start = region_to_addr(src_region); - HeapWord* region_end = region_start + RegionSize; - HeapWord* cur_addr = region_start + partial_obj_size; - size_t live_words = partial_obj_size; - - while (true) { - assert(cur_addr < region_end, "inv"); - cur_addr = PSParallelCompact::mark_bitmap()->find_obj_beg(cur_addr, region_end); - // There must be an overflowing obj in this region - assert(cur_addr < region_end, "inv"); - - oop obj = cast_to_oop(cur_addr); - size_t obj_size = obj->size(); - if (destination + live_words + obj_size > target_end) { - // Found the overflowing obj - split_info.record(src_region, cur_addr, live_words); - *target_next = destination + live_words; - return cur_addr; - } - - live_words += obj_size; - cur_addr += obj_size; - } -} - size_t ParallelCompactData::live_words_in_space(const MutableSpace* space, HeapWord** full_region_prefix_end) { size_t cur_region = addr_to_region_idx(space->bottom()); @@ -417,24 +259,18 @@ size_t ParallelCompactData::live_words_in_space(const MutableSpace* space, } return live_words; } - -bool ParallelCompactData::summarize(SplitInfo& split_info, - HeapWord* source_beg, HeapWord* source_end, - HeapWord** source_next, - HeapWord* target_beg, HeapWord* target_end, - HeapWord** target_next) -{ - HeapWord* const source_next_val = source_next == nullptr ? nullptr : *source_next; - log_develop_trace(gc, compaction)( - "sb=" PTR_FORMAT " se=" PTR_FORMAT " sn=" PTR_FORMAT - "tb=" PTR_FORMAT " te=" PTR_FORMAT " tn=" PTR_FORMAT, - p2i(source_beg), p2i(source_end), p2i(source_next_val), - p2i(target_beg), p2i(target_end), p2i(*target_next)); +// Summarize live objs in [source_beg, source_end). +// Every region in this range will be assigned at most two destination regions. +// The first non-empty region will get target_beg as destination addr. +void ParallelCompactData::summarize(HeapWord* source_beg, + HeapWord* source_end, + HeapWord** new_top_addr) { + assert(is_region_aligned(source_beg), "precondition"); size_t cur_region = addr_to_region_idx(source_beg); const size_t end_region = addr_to_region_idx(region_align_up(source_end)); - HeapWord *dest_addr = target_beg; + HeapWord *dest_addr = *new_top_addr; for (/* empty */; cur_region < end_region; cur_region++) { size_t words = _region_data[cur_region].data_size(); @@ -443,26 +279,9 @@ bool ParallelCompactData::summarize(SplitInfo& split_info, continue; } - if (split_info.is_split(cur_region)) { - assert(words > split_info.preceding_live_words(), "inv"); - words -= split_info.preceding_live_words(); - } - _region_data[cur_region].set_destination(dest_addr); - // If cur_region does not fit entirely into the target space, find a point - // at which the source space can be 'split' so that part is copied to the - // target space and the rest is copied elsewhere. - if (dest_addr + words > target_end) { - assert(source_next != nullptr, "source_next is null when splitting"); - *source_next = summarize_split_space(cur_region, split_info, dest_addr, - target_end, target_next); - return false; - } - - uint destination_count = split_info.is_split(cur_region) - ? split_info.preceding_destination_count() - : 0; + uint destination_count = 0; HeapWord* const last_addr = dest_addr + words - 1; const size_t dest_region_1 = addr_to_region_idx(dest_addr); @@ -488,8 +307,7 @@ bool ParallelCompactData::summarize(SplitInfo& split_info, dest_addr += words; } - *target_next = dest_addr; - return true; + *new_top_addr = dest_addr; } #ifdef ASSERT @@ -578,16 +396,13 @@ void PSParallelCompact::initialize_space_info() PSYoungGen* young_gen = heap->young_gen(); _space_info[old_space_id].set_space(heap->old_gen()->object_space()); - _space_info[eden_space_id].set_space(young_gen->eden_space()); _space_info[from_space_id].set_space(young_gen->from_space()); _space_info[to_space_id].set_space(young_gen->to_space()); - - _space_info[old_space_id].set_start_array(heap->old_gen()->start_array()); + _space_info[eden_space_id].set_space(young_gen->eden_space()); } void -PSParallelCompact::clear_data_covering_space(SpaceId id) -{ +PSParallelCompact::clear_data_covering_space(SpaceId id) { // At this point, top is the value before GC, new_top() is the value that will // be set at the end of GC. The marking bitmap is cleared to top; nothing // should be marked above top. The summary data is cleared to the larger of @@ -595,7 +410,7 @@ PSParallelCompact::clear_data_covering_space(SpaceId id) MutableSpace* const space = _space_info[id].space(); HeapWord* const bot = space->bottom(); HeapWord* const top = space->top(); - HeapWord* const max_top = MAX2(top, _space_info[id].new_top()); + HeapWord* const max_top = MAX2(top, _old_space_new_top); _mark_bitmap.clear_range(bot, top); @@ -603,13 +418,6 @@ PSParallelCompact::clear_data_covering_space(SpaceId id) const size_t end_region = _summary_data.addr_to_region_idx(_summary_data.region_align_up(max_top)); _summary_data.clear_range(beg_region, end_region); - - // Clear the data used to 'split' regions. - SplitInfo& split_info = _space_info[id].split_info(); - if (split_info.is_valid()) { - split_info.clear(); - } - DEBUG_ONLY(split_info.verify_clear();) } void PSParallelCompact::pre_compact() @@ -620,8 +428,6 @@ void PSParallelCompact::pre_compact() // collections will have swapped the spaces an unknown number of times. GCTraceTime(Debug, gc, phases) tm("Pre Compact", &_gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - _space_info[from_space_id].set_space(heap->young_gen()->from_space()); - _space_info[to_space_id].set_space(heap->young_gen()->to_space()); heap->increment_total_collections(true); @@ -641,8 +447,7 @@ void PSParallelCompact::pre_compact() DEBUG_ONLY(summary_data().verify_clear();) } -void PSParallelCompact::post_compact() -{ +void PSParallelCompact::post_compact(PSPendingAllocation pending_allocation) { GCTraceTime(Info, gc, phases) tm("Post Compact", &_gc_timer); ParCompactionManager::remove_all_shadow_regions(); @@ -652,18 +457,8 @@ void PSParallelCompact::post_compact() ClassLoaderDataGraph::clear_claimed_marks(); for (unsigned int id = old_space_id; id < last_space_id; ++id) { - // Clear the marking bitmap, summary data and split info. + // Clear the marking bitmap and summary data. clear_data_covering_space(SpaceId(id)); - { - MutableSpace* space = _space_info[id].space(); - HeapWord* top = space->top(); - HeapWord* new_top = _space_info[id].new_top(); - if (ZapUnusedHeapArea && new_top < top) { - space->mangle_region(MemRegion(new_top, top)); - } - // Update top(). Must be done after clearing the bitmap and summary data. - space->set_top(new_top); - } } #ifdef ASSERT @@ -672,30 +467,49 @@ void PSParallelCompact::post_compact() summary_data().verify_clear(); } #endif + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - ParCompactionManager::flush_all_string_dedup_requests(); - - MutableSpace* const eden_space = _space_info[eden_space_id].space(); - MutableSpace* const from_space = _space_info[from_space_id].space(); - MutableSpace* const to_space = _space_info[to_space_id].space(); + { + GCTraceTime(Debug, gc, phases) tm_debug("Post Compact: Adjust Generation Boundary", &_gc_timer); + { + // Clean up old-gen cards before adjusting gen boundary, because some dirty cards can be migrated to young-gen otherwise. + MutableSpace* space = heap->old_gen()->object_space(); + MemRegion old_space_used_mr = MemRegion{space->bottom(), space->top()}; + if (!old_space_used_mr.is_empty()) { + heap->card_table()->clear_MemRegion(old_space_used_mr); + } + } - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - bool eden_empty = eden_space->is_empty(); + size_t assumed_live_bytes = pointer_delta(_old_space_new_top, heap->reserved_region().start(), sizeof(char)); + bool adjusted_gen_boundary = heap->adjust_gen_boundary_after_full_gc(assumed_live_bytes, + pending_allocation); - // Update heap occupancy information which is used as input to the soft ref - // clearing policy at the next gc. - Universe::heap()->update_capacity_and_used_at_gc(); + if (!adjusted_gen_boundary) { + _space_info[eden_space_id].space()->clear(SpaceDecorator::Mangle); + _space_info[from_space_id].space()->clear(SpaceDecorator::Mangle); + _space_info[to_space_id].space()->clear(SpaceDecorator::Mangle); + } + { + // Unconditionally for old-gen (old-space). + MutableSpace* space = heap->old_gen()->object_space(); + HeapWord* top = space->top(); - bool young_gen_empty = eden_empty && from_space->is_empty() && - to_space->is_empty(); + // Full GC leaves young-gen empty, so all cards for old-gen must be clean. + heap->card_table()->verify_clean_cards(heap->old_gen()->committed()); - PSCardTable* ct = heap->card_table(); - MemRegion old_mr = heap->old_gen()->committed(); - if (young_gen_empty) { - ct->clear_MemRegion(old_mr); - } else { - ct->dirty_MemRegion(old_mr); + HeapWord* new_top = _old_space_new_top; + assert(new_top <= space->end(), "inv"); + if (ZapUnusedHeapArea && new_top < top) { + space->mangle_region(MemRegion(new_top, top)); + } + space->set_top(new_top); + } } + ParCompactionManager::flush_all_string_dedup_requests(); + + // Update heap occupancy information which is used as input to the soft ref + // clearing policy at the next gc. + heap->update_capacity_and_used_at_gc(); heap->prune_scavengable_nmethods(); @@ -704,22 +518,70 @@ void PSParallelCompact::post_compact() #endif // COMPILER2 // Signal that we have completed a visit to all live objects. - Universe::heap()->record_whole_heap_examined_timestamp(); + heap->record_whole_heap_examined_timestamp(); +} + +bool PSParallelCompact::check_maximum_compaction(bool should_do_max_compaction, + size_t total_live_words, + MutableSpace* const old_space, + HeapWord* full_region_prefix_end) { + + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); + + // Check System.GC + bool is_max_on_system_gc = UseMaximumCompactionOnSystemGC + && GCCause::is_user_requested_gc(heap->gc_cause()); + + // Check if all live objs are too much for old-gen. + const bool is_old_gen_too_full = (total_live_words >= old_space->capacity_in_words()); + + // If all regions in old-gen are full + const bool is_region_full = + full_region_prefix_end >= _summary_data.region_align_down(old_space->top()); + + return should_do_max_compaction + || is_max_on_system_gc + || is_old_gen_too_full + || is_region_full; +} + +static size_t compute_max_waste_bytes(size_t live_bytes, size_t max_old_gen_bytes) { + // A two-word filler crossing the dense-prefix boundary replaces one dead + // prefix word, so reserve one word for its net increase in live data when + // such a filler is possible. + const bool can_place_filler = !UseCompactObjectHeaders && + MinObjAlignment < checked_cast(CollectedHeap::min_fill_size()); + const size_t filler_overhead_bytes = can_place_filler ? HeapWordSize : 0; + const size_t old_gen_slack_bytes = max_old_gen_bytes > live_bytes + ? max_old_gen_bytes - live_bytes + : 0; + const size_t max_retained_dead_bytes = old_gen_slack_bytes > filler_overhead_bytes + ? old_gen_slack_bytes - filler_overhead_bytes + : 0; + const size_t dead_ratio_waste_bytes = max_old_gen_bytes * (MarkSweepDeadRatio / 100.0); + return MIN2(dead_ratio_waste_bytes, max_retained_dead_bytes); } HeapWord* PSParallelCompact::compute_dense_prefix_for_old_space(MutableSpace* old_space, - HeapWord* full_region_prefix_end) { + HeapWord* full_region_prefix_end, + size_t max_waste_bytes, + bool should_do_max_compaction) { + + if (should_do_max_compaction) { + return full_region_prefix_end; + } + const size_t region_size = ParallelCompactData::RegionSize; const ParallelCompactData& sd = summary_data(); // Iteration starts with the region *after* the full-region-prefix-end. const RegionData* const start_region = sd.addr_to_region_ptr(full_region_prefix_end); // If final region is not full, iteration stops before that region, - // because fill_dense_prefix_end assumes that prefix_end <= top. + // because we assume prefix_end <= top. const RegionData* const end_region = sd.addr_to_region_ptr(old_space->top()); assert(start_region <= end_region, "inv"); - size_t max_waste = old_space->capacity_in_words() * (MarkSweepDeadRatio / 100.0); + size_t max_waste = max_waste_bytes / HeapWordSize; const RegionData* cur_region = start_region; for (/* empty */; cur_region < end_region; ++cur_region) { assert(region_size >= cur_region->data_size(), "inv"); @@ -730,191 +592,190 @@ HeapWord* PSParallelCompact::compute_dense_prefix_for_old_space(MutableSpace* ol max_waste -= dead_size; } - HeapWord* const prefix_end = sd.region_to_addr(cur_region); - assert(sd.is_region_aligned(prefix_end), "postcondition"); - assert(prefix_end >= full_region_prefix_end, "in-range"); - assert(prefix_end <= old_space->top(), "in-range"); - return prefix_end; + HeapWord* const dense_prefix_end = sd.region_to_addr(cur_region); + assert(sd.is_region_aligned(dense_prefix_end), "postcondition"); + assert(dense_prefix_end >= full_region_prefix_end, "in-range"); + assert(dense_prefix_end <= old_space->top(), "in-range"); + return dense_prefix_end; } -void PSParallelCompact::fill_dense_prefix_end(SpaceId id) { - // Comparing two sizes to decide if filling is required: - // - // The size of the filler (min-obj-size) is 2 heap words with the default - // MinObjAlignment, since both markword and klass take 1 heap word. - // With +UseCompactObjectHeaders, the minimum filler size is only one word, - // because the Klass* gets encoded in the mark-word. - // - // The size of the gap (if any) right before dense-prefix-end is - // MinObjAlignment. - // - // Need to fill in the gap only if it's smaller than min-obj-size, and the - // filler obj will extend to next region. +bool PSParallelCompact::try_fill_gap_at_dense_prefix_end() { + HeapWord* const dense_prefix_end = _old_space_dense_prefix; + MutableSpace* old_space = _space_info[old_space_id].space(); + if (dense_prefix_end == old_space->bottom()) { + return false; + } if (MinObjAlignment >= checked_cast(CollectedHeap::min_fill_size())) { - return; + return false; } assert(!UseCompactObjectHeaders, "Compact headers can allocate small objects"); assert(CollectedHeap::min_fill_size() == 2, "inv"); - HeapWord* const dense_prefix_end = dense_prefix(id); assert(_summary_data.is_region_aligned(dense_prefix_end), "precondition"); - assert(dense_prefix_end <= space(id)->top(), "precondition"); - if (dense_prefix_end == space(id)->top()) { - // Must not have single-word gap right before prefix-end/top. - return; + assert(dense_prefix_end <= old_space->top(), "precondition"); + if (dense_prefix_end == old_space->top()) { + return false; } - RegionData* const region_after_dense_prefix = _summary_data.addr_to_region_ptr(dense_prefix_end); + RegionData* const region_after_dense_prefix = _summary_data.addr_to_region_ptr(dense_prefix_end); if (region_after_dense_prefix->partial_obj_size() != 0 || _mark_bitmap.is_marked(dense_prefix_end)) { - // The region after the dense prefix starts with live bytes. - return; + return false; } - 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 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); - _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); - assert(start_array(id) != nullptr, "sanity"); - start_array(id)->update_for_block(obj_beg, obj_beg + obj_len); + ObjectStartArray* start_array = ParallelScavengeHeap::heap()->start_array(); + assert(start_array != nullptr, "inv"); + HeapWord* block_start = start_array->block_start_reaching_into_card(dense_prefix_end); + if (block_start != dense_prefix_end - 1) { + return false; } -} -bool PSParallelCompact::check_maximum_compaction(bool should_do_max_compaction, - size_t total_live_words, - MutableSpace* const old_space, - HeapWord* full_region_prefix_end) { + assert(!_mark_bitmap.is_marked(block_start), "inv"); + 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); + _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); + start_array->update_for_block(obj_beg, obj_beg + obj_len); + return true; +} +size_t PSParallelCompact::compute_dense_prefix_and_assumed_live_bytes(bool should_do_max_compaction, + size_t total_live_words, + PSOldGen* old_gen, + HeapWord* full_region_prefix_end) { + MutableSpace* old_space = old_gen->object_space(); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); + const size_t max_young_gen_bytes = UseAdaptiveSizePolicy ? heap->young_gen()->reserved_size() : MaxNewSize; + const size_t max_old_gen_bytes = MaxHeapSize - max_young_gen_bytes; + const size_t live_bytes = total_live_words * HeapWordSize; + // Retaining dead space is optional. Do not let it consume the selected + // young-gen target when the live data itself fits alongside that target. + const size_t max_waste_bytes = compute_max_waste_bytes(live_bytes, max_old_gen_bytes); + + should_do_max_compaction = check_maximum_compaction(should_do_max_compaction, + total_live_words, + old_space, + full_region_prefix_end); + + HeapWord* dense_prefix_end = compute_dense_prefix_for_old_space(old_space, + full_region_prefix_end, + max_waste_bytes, + should_do_max_compaction); + _old_space_dense_prefix = dense_prefix_end; + + bool filler_placed = try_fill_gap_at_dense_prefix_end(); + + // Compute assumed_live_bytes + // Regions before full_region_prefix_end are 100% full, so skip them. + const ParallelCompactData& sd = summary_data(); + const RegionData* prefix_start = sd.addr_to_region_ptr(full_region_prefix_end); + const RegionData* prefix_end = sd.addr_to_region_ptr(dense_prefix_end); + size_t dead_in_prefix = 0; + for (const RegionData* r = prefix_start; r < prefix_end; ++r) { + dead_in_prefix += ParallelCompactData::RegionSize - r->data_size(); + } + // The filler (if placed) adds a 2-word filler crossing the dense prefix + // boundary. total_live_words was computed before the filler was placed, so + // add 2 words to account for both words of the filler. + size_t filler_live_words = filler_placed ? 2 : 0; + size_t assumed_live_bytes = (total_live_words + filler_live_words) * HeapWordSize + dead_in_prefix * HeapWordSize; +#ifdef ASSERT + if (!should_do_max_compaction && live_bytes <= max_old_gen_bytes) { + assert(assumed_live_bytes <= max_old_gen_bytes, + "retained dead space consumed the young-gen target"); + } +#endif + return assumed_live_bytes; +} - // Check System.GC - bool is_max_on_system_gc = UseMaximumCompactionOnSystemGC - && GCCause::is_user_requested_gc(heap->gc_cause()); - - // Check if all live objs are too much for old-gen. - const bool is_old_gen_too_full = (total_live_words >= old_space->capacity_in_words()); +void PSParallelCompact::summarize_spaces(size_t assumed_live_bytes) { + // old-space; skip dense-prefix + const MutableSpace* old_space = _space_info[old_space_id].space(); + _old_space_new_top = _old_space_dense_prefix; + _summary_data.summarize(_old_space_dense_prefix, + old_space->top(), + &_old_space_new_top); - // If all regions in old-gen are full - const bool is_region_full = - full_region_prefix_end >= _summary_data.region_align_down(old_space->top()); - return should_do_max_compaction - || is_max_on_system_gc - || is_old_gen_too_full - || is_region_full; + // Young-gen spaces. All live objects from young gen + // should fit into old gen after dynamic boundary adjustment. + for (uint id = first_young_gen_space_id; id < last_space_id; ++id) { + const MutableSpace* space = _space_info[id].space(); + const size_t live_words = _space_info[id].live_words(); + if (live_words > 0) { + // Move all live objects from young gen to old gen. + // Source: current space boundaries (unchanged until after compaction) + // Destination: old gen (where they will be after compaction) + _summary_data.summarize(space->bottom(), + space->top(), + &_old_space_new_top); + } + } +#ifdef ASSERT + { + size_t used_words_after_gc = pointer_delta(_old_space_new_top, + _space_info[old_space_id].space()->bottom()); + size_t used_bytes_after_gc = used_words_after_gc * HeapWordSize; + assert(assumed_live_bytes == used_bytes_after_gc, "inv"); + } +#endif } void PSParallelCompact::summary_phase(bool should_do_max_compaction) { GCTraceTime(Info, gc, phases) tm("Summary Phase", &_gc_timer); - MutableSpace* const old_space = _space_info[old_space_id].space(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); + PSOldGen* old_gen = heap->old_gen(); + MutableSpace* const old_space = old_gen->object_space(); + + size_t total_live_words = 0; + + HeapWord* full_region_prefix_end = nullptr; { - size_t total_live_words = 0; - HeapWord* full_region_prefix_end = nullptr; - { - // old-gen - size_t live_words = _summary_data.live_words_in_space(old_space, - &full_region_prefix_end); - total_live_words += live_words; - } - // young-gen - for (uint i = eden_space_id; i < last_space_id; ++i) { - const MutableSpace* space = _space_info[i].space(); - size_t live_words = _summary_data.live_words_in_space(space); - total_live_words += live_words; - _space_info[i].set_new_top(space->bottom() + live_words); - _space_info[i].set_dense_prefix(space->bottom()); - } - - should_do_max_compaction = check_maximum_compaction(should_do_max_compaction, - total_live_words, - old_space, - full_region_prefix_end); - { - GCTraceTime(Info, gc, phases) tm("Summary Phase: expand", &_gc_timer); - // Try to expand old-gen in order to fit all live objs and waste. - size_t target_capacity_bytes = total_live_words * HeapWordSize - + old_space->capacity_in_bytes() * (MarkSweepDeadRatio / 100); - ParallelScavengeHeap::heap()->old_gen()->try_expand_till_size(target_capacity_bytes); - } - - HeapWord* dense_prefix_end = should_do_max_compaction - ? full_region_prefix_end - : compute_dense_prefix_for_old_space(old_space, - full_region_prefix_end); - SpaceId id = old_space_id; - _space_info[id].set_dense_prefix(dense_prefix_end); - - if (dense_prefix_end != old_space->bottom()) { - fill_dense_prefix_end(id); - } - - // Compacting objs in [dense_prefix_end, old_space->top()) - _summary_data.summarize(_space_info[id].split_info(), - dense_prefix_end, old_space->top(), nullptr, - dense_prefix_end, old_space->end(), - _space_info[id].new_top_addr()); - } - - // Summarize the remaining spaces in the young gen. The initial target space - // is the old gen. If a space does not fit entirely into the target, then the - // remainder is compacted into the space itself and that space becomes the new - // target. - SpaceId dst_space_id = old_space_id; - HeapWord* dst_space_end = old_space->end(); - HeapWord** new_top_addr = _space_info[dst_space_id].new_top_addr(); - for (unsigned int id = eden_space_id; id < last_space_id; ++id) { - const MutableSpace* space = _space_info[id].space(); - const size_t live = pointer_delta(_space_info[id].new_top(), - space->bottom()); - const size_t available = pointer_delta(dst_space_end, *new_top_addr); - - if (live > 0 && live <= available) { - // All the live data will fit. - bool done = _summary_data.summarize(_space_info[id].split_info(), - space->bottom(), space->top(), - nullptr, - *new_top_addr, dst_space_end, - new_top_addr); - assert(done, "space must fit into old gen"); - - // Reset the new_top value for the space. - _space_info[id].set_new_top(space->bottom()); - } else if (live > 0) { - // Attempt to fit part of the source space into the target space. - HeapWord* next_src_addr = nullptr; - bool done = _summary_data.summarize(_space_info[id].split_info(), - space->bottom(), space->top(), - &next_src_addr, - *new_top_addr, dst_space_end, - new_top_addr); - assert(!done, "space should not fit into old gen"); - assert(next_src_addr != nullptr, "sanity"); - - // The source space becomes the new target, so the remainder is compacted - // within the space itself. - dst_space_id = SpaceId(id); - dst_space_end = space->end(); - new_top_addr = _space_info[id].new_top_addr(); - done = _summary_data.summarize(_space_info[id].split_info(), - next_src_addr, space->top(), - nullptr, - space->bottom(), dst_space_end, - new_top_addr); - assert(done, "space must fit when compacted into itself"); - assert(*new_top_addr <= space->top(), "usage should not grow"); + // old-gen + size_t live_words = _summary_data.live_words_in_space(old_space, + &full_region_prefix_end); + _space_info[old_space_id].set_live_words(live_words); + total_live_words += live_words; + } + + // young-gen + for (uint i = first_young_gen_space_id; i < last_space_id; ++i) { + const MutableSpace* space = _space_info[i].space(); + size_t live_words = _summary_data.live_words_in_space(space); + total_live_words += live_words; + _space_info[i].set_live_words(live_words); + } + + size_t assumed_live_bytes = compute_dense_prefix_and_assumed_live_bytes(should_do_max_compaction, + total_live_words, + old_gen, + full_region_prefix_end); + + { + GCTraceTime(Debug, gc, phases) tm_debug("Summary Phase: expand", &_gc_timer); + + if (!old_gen->try_accommodate(assumed_live_bytes)) { + // Current old-gen capacity is too small; the generation boundary must move right. + // Commit old-gen up to the current boundary for the upcoming compaction, and + // update the object start array for the planned post-GC old-gen range. + // The card table is only needed for young-GC old-to-young scanning. Since young-gen + // will be empty after full GC, the card table can be updated later. + heap->heap_vs()->commit_old_gen_to_boundary(); + { + MemRegion mr{old_gen->reserved().start(), + align_up(assumed_live_bytes, SpaceAlignment) / HeapWordSize}; + old_gen->start_array()->set_covered_region(mr); + } } } + + summarize_spaces(assumed_live_bytes); } void PSParallelCompact::report_object_count_after_gc() { @@ -929,6 +790,13 @@ void PSParallelCompact::report_object_count_after_gc() { } bool PSParallelCompact::invoke(bool clear_all_soft_refs, bool should_do_max_compaction) { + return invoke(clear_all_soft_refs, should_do_max_compaction, PSPendingAllocation::none()); +} + +bool PSParallelCompact::invoke(bool clear_all_soft_refs, + bool should_do_max_compaction, + PSPendingAllocation pending_allocation, + size_t promoted_before_full_gc) { assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread"); @@ -975,6 +843,17 @@ bool PSParallelCompact::invoke(bool clear_all_soft_refs, bool should_do_max_comp // Let the size policy know we're starting size_policy->major_collection_begin(); + { + if (heap->young_gen()->reserved_size() > 0 && heap->young_gen()->is_from_to_layout()) { + static_assert(to_space_id < from_space_id, "inv"); + // Ensure to-from layout so that all objs are slid to lower address, + // according to the order in SpaceId. + heap->young_gen()->swap_spaces(); + } + _space_info[to_space_id].set_space(heap->young_gen()->to_space()); + _space_info[from_space_id].set_space(heap->young_gen()->from_space()); + } + #ifdef COMPILER2 DerivedPointerTable::clear(); #endif // COMPILER2 @@ -1000,9 +879,16 @@ bool PSParallelCompact::invoke(bool clear_all_soft_refs, bool should_do_max_comp ParCompactionManager::verify_all_region_stack_empty(); + // Update promotion stats. + size_t promoted_bytes = promoted_before_full_gc; + for (uint id = first_young_gen_space_id; id < last_space_id; ++id) { + promoted_bytes += _space_info[id].live_words() * HeapWordSize; + } + size_policy->sample_promoted_bytes_permit_zero(promoted_bytes); + // Reset the mark bitmap, summary data, and do other bookkeeping. Must be // done before resizing. - post_compact(); + post_compact(pending_allocation); size_policy->major_collection_end(); @@ -1045,7 +931,7 @@ bool PSParallelCompact::invoke(bool clear_all_soft_refs, bool should_do_max_comp _gc_timer.register_gc_end(); - _gc_tracer.report_dense_prefix(dense_prefix(old_space_id)); + _gc_tracer.report_dense_prefix(_old_space_dense_prefix); _gc_tracer.report_gc_end(_gc_timer.gc_end(), _gc_timer.time_partitions()); return true; @@ -1320,22 +1206,10 @@ void PSParallelCompact::adjust_in_stripe(HeapWord* stripe_start, HeapWord* strip } } -void PSParallelCompact::adjust_in_old_space(Atomic* claim_counter) { - // Regions in old-space shouldn't be split. - precond(!_space_info[old_space_id].split_info().is_valid()); - - adjust_in_space_helper(old_space_id, claim_counter); -} - -void PSParallelCompact::adjust_in_young_space(SpaceId id, Atomic* claim_counter) { - adjust_in_space_helper(id, claim_counter); -} - void PSParallelCompact::adjust_pointers_in_spaces(uint worker_id, Atomic* 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]); + for (uint id = old_space_id; id < last_space_id; ++id) { + adjust_in_space_helper(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); } @@ -1483,6 +1357,7 @@ void PSParallelCompact::forward_to_new_addr() { return; } assert(mark_bitmap()->is_marked(cur_addr), "inv"); + assert(new_addr <= cur_addr, "must forward to lower addr"); oop obj = cast_to_oop(cur_addr); if (new_addr != cur_addr) { @@ -1502,7 +1377,9 @@ void PSParallelCompact::forward_to_new_addr() { 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* dense_prefix_addr = id == old_space_id + ? _old_space_dense_prefix + : sp->bottom(); HeapWord* top = sp->top(); if (dense_prefix_addr == top) { @@ -1510,7 +1387,6 @@ void PSParallelCompact::forward_to_new_addr() { continue; } - const SplitInfo& split_info = _space_info[SpaceId(id)].split_info(); 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; @@ -1530,19 +1406,8 @@ void PSParallelCompact::forward_to_new_addr() { HeapWord* region_start = _summary_data.region_to_addr(cur_region); HeapWord* region_end = region_start + ParallelCompactData::RegionSize; - if (split_info.is_split(cur_region)) { - // Part 1: will be relocated to space-1 - HeapWord* preceding_destination = split_info.preceding_destination(); - HeapWord* split_point = split_info.split_point(); - forward_objs_in_range(cm, region_start + partial_obj_size, split_point, preceding_destination + partial_obj_size); - - // Part 2: will be relocated to space-2 - HeapWord* destination = region_ptr->destination(); - forward_objs_in_range(cm, split_point, region_end, destination); - } else { - HeapWord* destination = region_ptr->destination(); - forward_objs_in_range(cm, region_start + partial_obj_size, region_end, destination + partial_obj_size); - } + HeapWord* destination = region_ptr->destination(); + forward_objs_in_range(cm, region_start + partial_obj_size, region_end, destination + partial_obj_size); } } } @@ -1554,16 +1419,25 @@ void PSParallelCompact::forward_to_new_addr() { #ifdef ASSERT void PSParallelCompact::verify_forward() { - HeapWord* const old_dense_prefix_addr = dense_prefix(SpaceId(old_space_id)); + HeapWord* const old_dense_prefix_addr = _old_space_dense_prefix; + + HeapWord* heap_end = (HeapWord*) ParallelScavengeHeap::heap()->reserved_region().end(); + if (old_dense_prefix_addr == heap_end) { + // Dense prefix extends to end of heap reservation: no space after it to compact into, + // so no forwarding happened. Nothing to verify. + return; + } + // The destination addr for the first live obj after dense-prefix. HeapWord* bump_ptr = old_dense_prefix_addr + _summary_data.addr_to_region_ptr(old_dense_prefix_addr)->partial_obj_size(); - SpaceId bump_ptr_space = old_space_id; for (uint id = old_space_id; id < last_space_id; ++id) { MutableSpace* sp = PSParallelCompact::space(SpaceId(id)); // Only verify objs after dense-prefix, because those before dense-prefix are not moved (forwarded). - HeapWord* cur_addr = dense_prefix(SpaceId(id)); + HeapWord* cur_addr = id == old_space_id + ? old_dense_prefix_addr + : sp->bottom(); HeapWord* top = sp->top(); while (cur_addr < top) { @@ -1572,12 +1446,7 @@ void PSParallelCompact::verify_forward() { break; } assert(mark_bitmap()->is_marked(cur_addr), "inv"); - assert(bump_ptr <= _space_info[bump_ptr_space].new_top(), "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); - } + assert(bump_ptr < _old_space_new_top, "inv"); oop obj = cast_to_oop(cur_addr); if (cur_addr == bump_ptr) { assert(!FullGCForwarding::is_forwarded(obj), "inv"); @@ -1588,6 +1457,8 @@ void PSParallelCompact::verify_forward() { cur_addr += obj->size(); } } + + assert(bump_ptr == _old_space_new_top, "inv"); } #endif @@ -1634,6 +1505,8 @@ void PSParallelCompact::prepare_region_draining_tasks(uint parallel_gc_threads) { GCTraceTime(Trace, gc, phases) tm("Drain Task Setup", &_gc_timer); + ParCompactionManager::verify_all_region_stack_empty(); + // Find the threads that are active uint worker_id = 0; @@ -1643,32 +1516,30 @@ void PSParallelCompact::prepare_region_draining_tasks(uint parallel_gc_threads) const ParallelCompactData& sd = PSParallelCompact::summary_data(); - // id + 1 is used to test termination so unsigned can - // be used with an old_space_id == 0. FillableRegionLogger region_logger; - for (unsigned int id = last_space_id - 1; id + 1 > old_space_id; --id) { - SpaceInfo* const space_info = _space_info + id; - HeapWord* const new_top = space_info->new_top(); + // Populate region stack with regions that will contain live objs after full-gc, + // i.e. those regions serving as destinations. + HeapWord* const new_top = _old_space_new_top; - const size_t beg_region = sd.addr_to_region_idx(space_info->dense_prefix()); - const size_t end_region = - sd.addr_to_region_idx(sd.region_align_up(new_top)); - - for (size_t cur = end_region - 1; cur + 1 > beg_region; --cur) { - if (sd.region(cur)->claim_unsafe()) { - ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(worker_id); - bool result = sd.region(cur)->mark_normal(); - assert(result, "Must succeed at this point."); - cm->region_stack()->push(cur); - region_logger.handle(cur); - // Assign regions to tasks in round-robin fashion. - if (++worker_id == parallel_gc_threads) { - worker_id = 0; - } + const size_t beg_region = sd.addr_to_region_idx(_old_space_dense_prefix); + const size_t end_region = + sd.addr_to_region_idx(sd.region_align_up(new_top)); + + // Populate with [beg_region, end_region) + for (size_t cur = end_region - 1; cur + 1 > beg_region; --cur) { + if (sd.region(cur)->claim_unsafe()) { + ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(worker_id); + bool result = sd.region(cur)->mark_normal(); + assert(result, "Must succeed at this point."); + cm->push_region(cur); + region_logger.handle(cur); + // Assign regions to tasks in round-robin fashion. + if (++worker_id == parallel_gc_threads) { + worker_id = 0; } } - region_logger.print_line(); } + region_logger.print_line(); } static void compaction_with_stealing_work(TaskTerminator* terminator, uint worker_id) { @@ -1737,11 +1608,13 @@ void PSParallelCompact::fill_range_in_dense_prefix(HeapWord* start, HeapWord* en } #endif + ObjectStartArray* start_array = ParallelScavengeHeap::heap()->start_array(); + assert(start_array != nullptr, "inv"); 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); + start_array->update_for_block(addr, addr + size); addr += size; } while (addr < end); } @@ -1750,7 +1623,7 @@ void PSParallelCompact::fill_dead_objs_in_dense_prefix() { ParMarkBitMap* bitmap = mark_bitmap(); HeapWord* const bottom = _space_info[old_space_id].space()->bottom(); - HeapWord* const prefix_end = dense_prefix(old_space_id); + HeapWord* const prefix_end = _old_space_dense_prefix; const size_t region_size = ParallelCompactData::RegionSize; @@ -1811,10 +1684,7 @@ void PSParallelCompact::compact() { #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)); - } + verify_regions_after_compaction(); #endif } } @@ -1822,7 +1692,7 @@ void PSParallelCompact::compact() { #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* dense_prefix_end = _old_space_dense_prefix; const size_t region_size = ParallelCompactData::RegionSize; @@ -1857,29 +1727,49 @@ void PSParallelCompact::verify_filler_in_dense_prefix() { } } -void PSParallelCompact::verify_complete(SpaceId space_id) { - // All Regions served as compaction targets, from dense_prefix() to - // new_top(), should be marked as filled and all Regions between new_top() - // and top() should be available (i.e., should have been emptied). +void PSParallelCompact::verify_regions_after_compaction() { ParallelCompactData& sd = summary_data(); - SpaceInfo si = _space_info[space_id]; - HeapWord* new_top_addr = sd.region_align_up(si.new_top()); - HeapWord* old_top_addr = sd.region_align_up(si.space()->top()); - const size_t beg_region = sd.addr_to_region_idx(si.dense_prefix()); - const size_t new_top_region = sd.addr_to_region_idx(new_top_addr); - const size_t old_top_region = sd.addr_to_region_idx(old_top_addr); - - size_t cur_region; - for (cur_region = beg_region; cur_region < new_top_region; ++cur_region) { - const RegionData* const c = sd.region(cur_region); - assert(c->completed(), "region %zu not filled: destination_count=%u", - cur_region, c->destination_count()); + { + // ## Old-gen + // All Regions served as compaction targets, from dense_prefix() to + // new_top(), should be marked as filled and all Regions between new_top() + // and top() should be available (i.e., should have been emptied). + SpaceInfo old_space_info = _space_info[old_space_id]; + const size_t beg_region = sd.addr_to_region_idx(_old_space_dense_prefix); + const size_t new_top_region = sd.addr_to_region_idx(sd.region_align_up(_old_space_new_top)); + const size_t old_top_region = sd.addr_to_region_idx(sd.region_align_up(old_space_info.space()->top())); + + size_t cur_region; + // [beg_region, new_top_region) must be completed (as compaction targets) + for (cur_region = beg_region; cur_region < new_top_region; ++cur_region) { + const RegionData* const c = sd.region(cur_region); + assert(c->completed(), "region %zu not filled: destination_count=%u", + cur_region, c->destination_count()); + } + + // [new_top_region, old_top_region) must be empty. + for (cur_region = new_top_region; cur_region < old_top_region; ++cur_region) { + const RegionData* const c = sd.region(cur_region); + assert(c->available(), "region %zu not empty: destination_count=%u", + cur_region, c->destination_count()); + } } + { + // Young-gen + SpaceInfo first_space_info = _space_info[first_young_gen_space_id]; + assert(sd.is_region_aligned(first_space_info.space()->bottom()), "inv"); + const size_t old_gen_end_region = sd.addr_to_region_idx(sd.region_align_up(_old_space_new_top)); + const size_t young_gen_start_region = sd.addr_to_region_idx(first_space_info.space()->bottom()); + const size_t end_region = sd.addr_to_region_idx(sd.region_align_up(_space_info[last_space_id - 1].space()->top())); + + // In case gen-boundary will be moved, use the larger one. + const size_t beg_region = MAX2(old_gen_end_region, young_gen_start_region); - for (cur_region = new_top_region; cur_region < old_top_region; ++cur_region) { - const RegionData* const c = sd.region(cur_region); - assert(c->available(), "region %zu not empty: destination_count=%u", - cur_region, c->destination_count()); + for (size_t cur_region = beg_region; cur_region < end_region; ++cur_region) { + const RegionData* const c = sd.region(cur_region); + assert(c->available(), "region %zu not empty: destination_count=%u", + cur_region, c->destination_count()); + } } } #endif // #ifdef ASSERT @@ -1896,7 +1786,6 @@ PSParallelCompact::SpaceId PSParallelCompact::space_id(HeapWord* addr) { } } - assert(false, "no space contains the addr"); return last_space_id; } @@ -1928,39 +1817,7 @@ HeapWord* PSParallelCompact::skip_live_words(HeapWord* beg, HeapWord* end, size_ // Conversely, a source-region has a dest-region which holds the destination of // the first live word on this source-region, based on which the destination // for the rest of live words can be derived. -// -// Note: -// There is some complication due to space-boundary-fragmentation (an obj can't -// cross space-boundary) -- a source-region may be split and behave like two -// distinct regions with their own dest-region, as depicted below. -// -// source-region: region-n -// -// ********************** -// | A|A~~~~B|B | -// ********************** -// n-1 n n+1 -// -// AA, BB denote two live objs. ~~~~ denotes unknown number of live objs. -// -// Assuming the dest-region for region-n is the final region before -// old-space-end and its first-live-word is the middle of AA, the heap content -// will look like the following after compaction: -// -// ************** ************* -// A|A~~~~ | |BB | -// ************** ************* -// ^ ^ -// | old-space-end | eden-space-start -// -// Therefore, in this example, region-n will have two dest-regions: -// 1. the final region in old-space -// 2. the first region in eden-space. -// To handle this special case, we introduce the concept of split-region, whose -// contents are relocated to two spaces. `SplitInfo` captures all necessary -// info about the split, the first part, spliting-point, and the second part. HeapWord* PSParallelCompact::first_src_addr(HeapWord* const dest_addr, - SpaceId src_space_id, size_t src_region_idx) { const size_t RegionSize = ParallelCompactData::RegionSize; @@ -1978,17 +1835,7 @@ HeapWord* PSParallelCompact::first_src_addr(HeapWord* const dest_addr, // Identify the actual destination for the first live words on this region, // taking split-region into account. - HeapWord* region_start_destination; - const SplitInfo& split_info = _space_info[src_space_id].split_info(); - if (split_info.is_split(src_region_idx)) { - // The second part of this split region; use the recorded split point. - if (dest_addr == src_region_destination) { - return split_info.split_point(); - } - region_start_destination = split_info.preceding_destination(); - } else { - region_start_destination = src_region_destination; - } + HeapWord* region_start_destination = src_region_destination; // Calculate the offset to be skipped size_t words_to_skip = pointer_delta(dest_addr, region_start_destination); @@ -2001,11 +1848,7 @@ HeapWord* PSParallelCompact::first_src_addr(HeapWord* const dest_addr, result = skip_live_words(region_start + partial_obj_size, region_end, words_to_skip); } - if (split_info.is_split(src_region_idx)) { - assert(result < split_info.split_point(), "postcondition"); - } else { - assert(result < region_end, "postcondition"); - } + assert(result < region_end, "postcondition"); return result; } @@ -2029,8 +1872,8 @@ void PSParallelCompact::decrement_destination_counts(ParCompactionManager* cm, RegionData* const beg = sd.region(beg_region); RegionData* const end = sd.addr_to_region_ptr(sd.region_align_up(end_addr)); - // Regions up to new_top() are enqueued if they become available. - HeapWord* const new_top = _space_info[src_space_id].new_top(); + // Regions up to old-gen new_top() are enqueued if they become available. + HeapWord* const new_top = _old_space_new_top; RegionData* const enqueue_end = sd.addr_to_region_ptr(sd.region_align_up(new_top)); @@ -2158,7 +2001,7 @@ void PSParallelCompact::fill_region(ParCompactionManager* cm, MoveAndUpdateClosu HeapWord* src_space_top = _space_info[src_space_id].space()->top(); HeapWord* dest_addr = sd.region_to_addr(region_idx); - closure.set_source(first_src_addr(dest_addr, src_space_id, src_region_idx)); + closure.set_source(first_src_addr(dest_addr, src_region_idx)); // Adjust src_region_idx to prepare for decrementing destination counts (the // destination count is not decremented when a region is copied to itself). @@ -2316,7 +2159,7 @@ bool PSParallelCompact::steal_unavailable_region(ParCompactionManager* cm, size_ { size_t next = cm->next_shadow_region(); ParallelCompactData& sd = summary_data(); - size_t old_new_top = sd.addr_to_region_idx(_space_info[old_space_id].new_top()); + size_t old_new_top = sd.addr_to_region_idx(_old_space_new_top); uint active_gc_threads = ParallelScavengeHeap::heap()->workers().active_workers(); while (next < old_new_top) { @@ -2345,12 +2188,13 @@ void PSParallelCompact::initialize_shadow_regions(uint parallel_gc_threads) { const ParallelCompactData& sd = PSParallelCompact::summary_data(); + HeapWord* old_gen_new_top = _old_space_new_top; for (unsigned int id = old_space_id; id < last_space_id; ++id) { SpaceInfo* const space_info = _space_info + id; MutableSpace* const space = space_info->space(); const size_t beg_region = - sd.addr_to_region_idx(sd.region_align_up(MAX2(space_info->new_top(), space->top()))); + sd.addr_to_region_idx(sd.region_align_up(MAX2(old_gen_new_top, space->top()))); const size_t end_region = sd.addr_to_region_idx(sd.region_align_down(space->end())); @@ -2359,7 +2203,7 @@ void PSParallelCompact::initialize_shadow_regions(uint parallel_gc_threads) } } - size_t beg_region = sd.addr_to_region_idx(_space_info[old_space_id].dense_prefix()); + size_t beg_region = sd.addr_to_region_idx(_old_space_dense_prefix); for (uint i = 0; i < parallel_gc_threads; i++) { ParCompactionManager *cm = ParCompactionManager::gc_thread_compaction_manager(i); cm->set_next_shadow_region(beg_region + i); diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index 543f0137a944..e9ad68278ba0 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -47,148 +47,19 @@ class MoveAndUpdateClosure; class ParallelOldTracer; class STWGCTimer; -// The SplitInfo class holds the information needed to 'split' a source region -// so that the live data can be copied to two destination *spaces*. Normally, -// all the live data in a region is copied to a single destination space (e.g., -// everything live in a region in eden is copied entirely into the old gen). -// However, when the heap is nearly full, all the live data in eden may not fit -// into the old gen. Copying only some of the regions from eden to old gen -// requires finding a region that does not contain a partial object (i.e., no -// live object crosses the region boundary) somewhere near the last object that -// does fit into the old gen. Since it's not always possible to find such a -// region, splitting is necessary for predictable behavior. -// -// A region is always split at the end of the partial object. This avoids -// additional tests when calculating the new location of a pointer, which is a -// very hot code path. The partial object and everything to its left will be -// copied to another space (call it dest_space_1). The live data to the right -// of the partial object will be copied either within the space itself, or to a -// different destination space (distinct from dest_space_1). -// -// Split points are identified during the summary phase, when region -// destinations are computed: data about the split, including the -// partial_object_size, is recorded in a SplitInfo record and the -// partial_object_size field in the summary data is set to zero. The zeroing is -// possible (and necessary) since the partial object will move to a different -// destination space than anything to its right, thus the partial object should -// not affect the locations of any objects to its right. -// -// The recorded data is used during the compaction phase, but only rarely: when -// the partial object on the split region will be copied across a destination -// region boundary. This test is made once each time a region is filled, and is -// a simple address comparison, so the overhead is negligible (see -// PSParallelCompact::first_src_addr()). -// -// Notes: -// -// Only regions with partial objects are split; a region without a partial -// object does not need any extra bookkeeping. -// -// At most one region is split per space, so the amount of data required is -// constant. -// -// A region is split only when the destination space would overflow. Once that -// happens, the destination space is abandoned and no other data (even from -// other source spaces) is targeted to that destination space. Abandoning the -// destination space may leave a somewhat large unused area at the end, if a -// large object caused the overflow. -// -// Future work: -// -// More bookkeeping would be required to continue to use the destination space. -// The most general solution would allow data from regions in two different -// source spaces to be "joined" in a single destination region. At the very -// least, additional code would be required in next_src_region() to detect the -// join and skip to an out-of-order source region. If the join region was also -// the last destination region to which a split region was copied (the most -// likely case), then additional work would be needed to get fill_region() to -// stop iteration and switch to a new source region at the right point. Basic -// idea would be to use a fake value for the top of the source space. It is -// doable, if a bit tricky. -// -// A simpler (but less general) solution would fill the remainder of the -// destination region with a dummy object and continue filling the next -// destination region. - -class SplitInfo -{ -public: - // Return true if this split info is valid (i.e., if a split has been - // recorded). The very first region cannot have a partial object and thus is - // never split, so 0 is the 'invalid' value. - bool is_valid() const { return _split_region_idx > 0; } - - // Return true if this split holds data for the specified source region. - inline bool is_split(size_t region_idx) const; - - // Obj at the split point doesn't fit the previous space and will be relocated to the next space. - HeapWord* split_point() const { return _split_point; } - - // Number of live words before the split point on this region. - size_t preceding_live_words() const { return _preceding_live_words; } - - // A split region has two "destinations", living in two spaces. This method - // returns the first one -- destination for the first live word on - // this split region. - HeapWord* preceding_destination() const { - assert(_preceding_destination != nullptr, "inv"); - return _preceding_destination; - } - - // Number of regions the preceding live words are relocated into. - uint preceding_destination_count() const { return _preceding_destination_count; } - - void record(size_t split_region_idx, HeapWord* split_point, size_t preceding_live_words); - - void clear(); - - DEBUG_ONLY(void verify_clear();) - -private: - size_t _split_region_idx; - HeapWord* _split_point; - size_t _preceding_live_words; - HeapWord* _preceding_destination; - uint _preceding_destination_count; -}; - -inline bool SplitInfo::is_split(size_t region_idx) const -{ - return _split_region_idx == region_idx && is_valid(); -} - class SpaceInfo { public: - MutableSpace* space() const { return _space; } - - // Where the free space will start after the collection. Valid only after the - // summary phase completes. - HeapWord* new_top() const { return _new_top; } - - // Allows new_top to be set. - HeapWord** new_top_addr() { return &_new_top; } - - // Where the dense prefix ends, or the compacted region begins. - HeapWord* dense_prefix() const { return _dense_prefix; } - - // The start array for the (generation containing the) space, or null if there - // is no start array. - ObjectStartArray* start_array() const { return _start_array; } - - SplitInfo& split_info() { return _split_info; } + MutableSpace* space() const { return _space; } + void set_space(MutableSpace* s) { _space = s; } - void set_space(MutableSpace* s) { _space = s; } - void set_new_top(HeapWord* addr) { _new_top = addr; } - void set_dense_prefix(HeapWord* addr) { _dense_prefix = addr; } - void set_start_array(ObjectStartArray* s) { _start_array = s; } + // Live words belonging to this space. + size_t live_words() const { return _live_words; } + void set_live_words(size_t live_words) { _live_words = live_words; } private: - MutableSpace* _space; - HeapWord* _new_top; - HeapWord* _dense_prefix; - ObjectStartArray* _start_array; - SplitInfo _split_info; + MutableSpace* _space; + size_t _live_words; }; class ParallelCompactData @@ -346,7 +217,6 @@ class ParallelCompactData #ifdef ASSERT public: uint _pushed; // 0 until region is pushed onto a stack - private: #endif }; @@ -361,18 +231,12 @@ class ParallelCompactData inline RegionData* region(size_t region_idx) const; inline size_t region(const RegionData* const region_ptr) const; - HeapWord* summarize_split_space(size_t src_region, SplitInfo& split_info, - HeapWord* destination, HeapWord* target_end, - HeapWord** target_next); - size_t live_words_in_space(const MutableSpace* space, HeapWord** full_region_prefix_end = nullptr); - bool summarize(SplitInfo& split_info, - HeapWord* source_beg, HeapWord* source_end, - HeapWord** source_next, - HeapWord* target_beg, HeapWord* target_end, - HeapWord** target_next); + void summarize(HeapWord* source_beg, + HeapWord* source_end, + HeapWord** new_top_addr); void clear_range(size_t beg_region, size_t end_region); @@ -675,12 +539,20 @@ class PSParallelCompact : AllStatic { // Convenient access to type names. typedef ParallelCompactData::RegionData RegionData; - // By the end of full-gc, all live objs are compacted into the first three spaces, old, eden, and from. + // By the end of full-gc, all live objs are compacted into the old-gen. typedef enum { + // Old-gen; single space old_space_id, - eden_space_id, + + // Young-gen; 3 spaces. Use [to, from, eden] layout so that the subsequent + // young-gc after this full-gc can do resize. Young-gc can resize only when + // objs are at the beginning of the young-gen. + first_young_gen_space_id, + to_space_id = first_young_gen_space_id, from_space_id, - to_space_id, + eden_space_id, + + // Place holder for iteration (exclusive) last_space_id } SpaceId; @@ -701,6 +573,10 @@ class PSParallelCompact : AllStatic { static ParallelCompactData _summary_data; static IsAliveClosure _is_alive_closure; static SpaceInfo _space_info[last_space_id]; + static HeapWord* _old_space_dense_prefix; + + // The new top pointer of old-space (old-gen) after full-gc. + static HeapWord* _old_space_new_top; // Reference processing (used in ...follow_contents) static SpanSubjectToDiscoveryClosure _span_based_discoverer; @@ -717,23 +593,37 @@ class PSParallelCompact : AllStatic { static void clear_data_covering_space(SpaceId id); static void pre_compact(); - static void post_compact(); + static void post_compact(PSPendingAllocation pending_allocation); static bool check_maximum_compaction(bool should_do_max_compaction, size_t total_live_words, MutableSpace* const old_space, HeapWord* full_region_prefix_end); - // Mark live objects - static void marking_phase(ParallelOldTracer *gc_tracer); - - // Identify the dense-fix in the old-space to avoid moving much memory with little reclaimed. + // Compute the dense prefix end for old space. + // When should_do_max_compaction is true, the dense prefix starts at + // full_region_prefix_end; otherwise the prefix end is determined by the + // max_waste_bytes budget. Does NOT set _old_space_dense_prefix. static HeapWord* compute_dense_prefix_for_old_space(MutableSpace* old_space, - HeapWord* full_region_prefix_end); + HeapWord* full_region_prefix_end, + size_t max_waste_bytes, + bool should_do_max_compaction); + + // Try to place a 2-word filler at the dense-prefix boundary when + // there is a 1-word gap right before the boundary. Returns true if + // the filler was placed. _old_space_dense_prefix must have been set. + static bool try_fill_gap_at_dense_prefix_end(); + + // Compute the dense prefix for old space and the assumed post-GC live bytes. + // Calls compute_dense_prefix_for_old_space and try_fill_gap_at_dense_prefix_end. + // Sets _old_space_dense_prefix as a side effect. + static size_t compute_dense_prefix_and_assumed_live_bytes(bool should_do_max_compaction, + size_t total_live_words, + PSOldGen* old_gen, + HeapWord* full_region_prefix_end); - // Create a filler obj (if needed) right before the dense-prefix-boundary to - // make the heap parsable. - static void fill_dense_prefix_end(SpaceId id); + // Mark live objects + static void marking_phase(ParallelOldTracer *gc_tracer); static void summary_phase(bool should_do_max_compaction); @@ -752,6 +642,8 @@ class PSParallelCompact : AllStatic { static void fill_range_in_dense_prefix(HeapWord* start, HeapWord* end); + static void summarize_spaces(size_t assumed_live_bytes); + public: static void fill_dead_objs_in_dense_prefix(); @@ -759,6 +651,10 @@ class PSParallelCompact : AllStatic { // clear_all_soft_refs controls whether soft-refs should be cleared or not. // should_do_max_compaction controls whether all spaces for dead objs should be reclaimed. static bool invoke(bool clear_all_soft_refs, bool should_do_max_compaction); + static bool invoke(bool clear_all_soft_refs, + bool should_do_max_compaction, + PSPendingAllocation pending_allocation, + size_t promoted_before_full_gc = 0); static void adjust_in_space_helper(SpaceId id, Atomic* claim_counter); @@ -766,10 +662,6 @@ class PSParallelCompact : AllStatic { static void adjust_in_stripe(HeapWord* stripe_start, HeapWord* stripe_end); - static void adjust_in_old_space(Atomic* claim_counter); - - static void adjust_in_young_space(SpaceId id, Atomic* claim_counter); - static void adjust_pointers_in_spaces(uint worker_id, Atomic* claim_counter); static void post_initialize(); @@ -793,9 +685,8 @@ class PSParallelCompact : AllStatic { // Convenience wrappers for per-space data kept in _space_info. static inline MutableSpace* space(SpaceId space_id); - static inline HeapWord* new_top(SpaceId space_id); - static inline HeapWord* dense_prefix(SpaceId space_id); - static inline ObjectStartArray* start_array(SpaceId space_id); + + static HeapWord* old_space_new_top() { return _old_space_new_top; } // 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); @@ -803,7 +694,6 @@ class PSParallelCompact : AllStatic { // Return the address of the word to be copied to dest_addr, which must be // aligned to a region boundary. static HeapWord* first_src_addr(HeapWord* const dest_addr, - SpaceId src_space_id, size_t src_region_idx); // Determine the next source region, set closure.source() to the start of the @@ -854,7 +744,7 @@ class PSParallelCompact : AllStatic { // Sanity check the new location of a word in the heap. static inline void check_new_location(HeapWord* old_addr, HeapWord* new_addr); // Verify that all the regions have been emptied. - static void verify_complete(SpaceId space_id); + static void verify_regions_after_compaction(); #endif // #ifdef ASSERT }; @@ -910,19 +800,23 @@ inline void MoveAndUpdateClosure::decrement_words_remaining(size_t words) { inline size_t MoveAndUpdateClosure::calculate_words_remaining(size_t region) { HeapWord* dest_addr = PSParallelCompact::summary_data().region_to_addr(region); - PSParallelCompact::SpaceId dest_space_id = PSParallelCompact::space_id(dest_addr); - HeapWord* new_top = PSParallelCompact::new_top(dest_space_id); + HeapWord* new_top = PSParallelCompact::old_space_new_top(); return MIN2(pointer_delta(new_top, dest_addr), ParallelCompactData::RegionSize); } +static ObjectStartArray* start_array_for_addr(void* addr) { + assert(addr < PSParallelCompact::old_space_new_top(), "precondition"); + return ParallelScavengeHeap::heap()->start_array(); +} + inline MoveAndUpdateClosure::MoveAndUpdateClosure(ParMarkBitMap* bitmap, size_t region_idx) : _bitmap(bitmap), _words_remaining(calculate_words_remaining(region_idx)), _source(nullptr), _destination(PSParallelCompact::summary_data().region_to_addr(region_idx)), - _start_array(PSParallelCompact::start_array(PSParallelCompact::space_id(_destination))), + _start_array(start_array_for_addr(_destination)), _offset(0) {} inline void MoveAndUpdateClosure::update_state(size_t words) diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp index aa62d474a556..5db5e99d3313 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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,25 +46,9 @@ inline MutableSpace* PSParallelCompact::space(SpaceId id) { return _space_info[id].space(); } -inline HeapWord* PSParallelCompact::new_top(SpaceId id) { - assert(id < last_space_id, "id out of range"); - return _space_info[id].new_top(); -} - -inline HeapWord* PSParallelCompact::dense_prefix(SpaceId id) { - assert(id < last_space_id, "id out of range"); - return _space_info[id].dense_prefix(); -} - -inline ObjectStartArray* PSParallelCompact::start_array(SpaceId id) { - assert(id < last_space_id, "id out of range"); - return _space_info[id].start_array(); -} - #ifdef ASSERT inline void PSParallelCompact::check_new_location(HeapWord* old_addr, HeapWord* new_addr) { - assert(old_addr >= new_addr || space_id(old_addr) != space_id(new_addr), - "must move left or to a different space"); + assert(old_addr >= new_addr, "must move left"); assert(is_object_aligned(old_addr) && is_object_aligned(new_addr), "checking alignment"); } diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index 883bcb81a504..9001bb29f9ff 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -324,6 +324,7 @@ bool PSScavenge::invoke(bool clear_soft_refs) { PSAdaptiveSizePolicy* size_policy = heap->size_policy(); assert(young_gen->to_space()->is_empty(), "precondition"); + assert(young_gen->reserved_size() != 0, "precondition"); heap->increment_total_collections(); @@ -415,9 +416,9 @@ bool PSScavenge::invoke(bool clear_soft_refs) { size_policy->minor_collection_end(young_gen->eden_space()->capacity_in_bytes()); if (!promotion_failure_occurred) { - // Swap the survivor spaces. - young_gen->eden_space()->clear(SpaceDecorator::Mangle); - young_gen->from_space()->clear(SpaceDecorator::Mangle); + // Clear now empty eden/from spaces. Don't mangle yet since we can potentially resize later on. + young_gen->eden_space()->clear(SpaceDecorator::DontMangle); + young_gen->from_space()->clear(SpaceDecorator::DontMangle); young_gen->swap_spaces(); size_t survived = young_gen->from_space()->used_in_bytes(); @@ -428,6 +429,7 @@ bool PSScavenge::invoke(bool clear_soft_refs) { if (UseAdaptiveSizePolicy) { if (young_gen->is_from_to_layout()) { + GCTraceTime(Debug, gc, phases) tm_info("Adaptive: Resizing after young-gc", &_gc_timer); size_policy->print_stats(_survivor_overflow); heap->resize_after_young_gc(_survivor_overflow); _tenuring_threshold = size_policy->compute_tenuring_threshold(young_gen->sizing_state(), @@ -449,6 +451,16 @@ bool PSScavenge::invoke(bool clear_soft_refs) { } } + // Resizing completed. After young-gc, all live-objs, if any, are in from-space for young-gen. + { + if (ZapUnusedHeapArea) { + if (!UseNUMA) { + young_gen->eden_space()->mangle_unused_area(); + } + young_gen->to_space()->mangle_unused_area(); + } + } + // Update the structure of the eden. With NUMA-eden CPU hotplugging or offlining can // cause the change of the heap layout. Make sure eden is reshaped if that's the case. // Also update() will case adaptive NUMA chunk resizing. @@ -500,11 +512,18 @@ void PSScavenge::clean_up_failed_promotion() { NOT_PRODUCT(ParallelScavengeHeap::heap()->reset_promotion_should_fail();) } -// Adaptive size policy support. void PSScavenge::set_young_generation_boundary(HeapWord* v) { _young_generation_boundary = v; if (UseCompressedOops) { - _young_generation_boundary_compressed = (uintptr_t)CompressedOops::encode(cast_to_oop(v)); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); + bool is_gen_boundary_at_heap_end = (v == heap->reserved_region().end()); + if (!is_gen_boundary_at_heap_end) { + _young_generation_boundary_compressed = (uintptr_t)CompressedOops::encode_not_null(cast_to_oop(v)); + } else { + // To work around asserts inside encode_not_null; + // just use the max value + 1, so all coops are below this threshold. + _young_generation_boundary_compressed = (uintptr_t)std::numeric_limits::max() + 1; + } } } @@ -528,10 +547,8 @@ void PSScavenge::initialize() { // Set boundary between young_gen and old_gen assert(old_gen->reserved().end() == young_gen->reserved().start(), "old above young"); - set_young_generation_boundary(young_gen->reserved().start()); + reset_young_gen_reserved(young_gen->reserved()); - // Initialize ref handling object for scavenging. - _span_based_discoverer.set_span(young_gen->reserved()); _ref_processor = new ReferenceProcessor(&_span_based_discoverer, ParallelGCThreads, // mt processing degree diff --git a/src/hotspot/share/gc/parallel/psScavenge.hpp b/src/hotspot/share/gc/parallel/psScavenge.hpp index e7db634c8e15..ffcf16aecc27 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.hpp +++ b/src/hotspot/share/gc/parallel/psScavenge.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ #define SHARE_GC_PARALLEL_PSSCAVENGE_HPP #include "gc/parallel/psCardTable.hpp" -#include "gc/parallel/psVirtualspace.hpp" #include "gc/shared/collectorCounters.hpp" #include "gc/shared/gcTrace.hpp" #include "gc/shared/referenceProcessor.hpp" @@ -68,6 +67,8 @@ class PSScavenge: AllStatic { static PSCardTable* card_table() { assert(_card_table != nullptr, "Sanity"); return _card_table; } static const ParallelScavengeTracer* gc_tracer() { return &_gc_tracer; } + static void set_young_generation_boundary(HeapWord* v); + public: // Accessors static uint tenuring_threshold() { return _tenuring_threshold; } @@ -76,20 +77,21 @@ class PSScavenge: AllStatic { // Performance Counters static CollectorCounters* counters() { return _counters; } - static void set_subject_to_discovery_span(MemRegion mr) { + static void reset_young_gen_reserved(MemRegion mr) { + set_young_generation_boundary(mr.start()); _span_based_discoverer.set_span(mr); } + // Used by scavenge_contents static ReferenceProcessor* reference_processor() { assert(_ref_processor != nullptr, "Sanity"); return _ref_processor; } + // The promotion managers tell us if they encountered overflow static void set_survivor_overflow(bool state) { _survivor_overflow = state; } - // Adaptive size policy support. - static void set_young_generation_boundary(HeapWord* v); // Called by parallelScavengeHeap to init the tenuring threshold static void initialize(); diff --git a/src/hotspot/share/gc/parallel/psVirtualspace.hpp b/src/hotspot/share/gc/parallel/psVirtualspace.hpp index 87ea86809f08..ac3b4845f683 100644 --- a/src/hotspot/share/gc/parallel/psVirtualspace.hpp +++ b/src/hotspot/share/gc/parallel/psVirtualspace.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, 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 @@ -137,6 +137,8 @@ inline size_t PSVirtualSpace::uncommitted_size() const { } inline void PSVirtualSpace::set_reserved(char* low_addr, char* high_addr, bool special) { + assert(low_addr <= high_addr, "precondition"); + _reserved_low_addr = low_addr; _reserved_high_addr = high_addr; _special = special; @@ -147,6 +149,9 @@ inline void PSVirtualSpace::set_reserved(ReservedSpace rs) { } inline void PSVirtualSpace::set_committed(char* low_addr, char* high_addr) { + assert(low_addr <= high_addr, "precondition"); + assert(low_addr == _reserved_low_addr, "precondition"); + _committed_low_addr = low_addr; _committed_high_addr = high_addr; } diff --git a/src/hotspot/share/gc/parallel/psYoungGen.cpp b/src/hotspot/share/gc/parallel/psYoungGen.cpp index 297fdde09ae4..b2dab144ffa7 100644 --- a/src/hotspot/share/gc/parallel/psYoungGen.cpp +++ b/src/hotspot/share/gc/parallel/psYoungGen.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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 @@ -24,6 +24,7 @@ #include "gc/parallel/mutableNUMASpace.hpp" #include "gc/parallel/parallelScavengeHeap.hpp" +#include "gc/parallel/psAdaptiveSizePolicy.hpp" #include "gc/parallel/psScavenge.hpp" #include "gc/parallel/psYoungGen.hpp" #include "gc/shared/gcUtil.hpp" @@ -35,9 +36,11 @@ #include "runtime/java.hpp" #include "utilities/align.hpp" -PSYoungGen::PSYoungGen(ReservedSpace rs, size_t initial_size, size_t min_size, size_t max_size) : - _reserved(), - _virtual_space(nullptr), +PSYoungGen::PSYoungGen(PSHeapVirtualSpace* vs, + size_t initial_size, + size_t min_size, + size_t max_size) : + _heap_vs(vs), _eden_space(nullptr), _from_space(nullptr), _to_space(nullptr), @@ -49,33 +52,17 @@ PSYoungGen::PSYoungGen(ReservedSpace rs, size_t initial_size, size_t min_size, s _from_counters(nullptr), _to_counters(nullptr) { - initialize(rs, initial_size, SpaceAlignment); -} - -void PSYoungGen::initialize_virtual_space(ReservedSpace rs, - size_t initial_size, - size_t alignment) { - assert(initial_size != 0, "Should have a finite size"); - _virtual_space = new PSVirtualSpace(rs, alignment); - if (!virtual_space()->expand_by(initial_size)) { + if (!_heap_vs->expand_young_gen(initial_size)) { vm_exit_during_initialization("Could not reserve enough space for object heap"); } -} -void PSYoungGen::initialize(ReservedSpace rs, size_t initial_size, size_t alignment) { - initialize_virtual_space(rs, initial_size, alignment); initialize_work(); } void PSYoungGen::initialize_work() { - - _reserved = MemRegion((HeapWord*)virtual_space()->low_boundary(), - (HeapWord*)virtual_space()->high_boundary()); - assert(_reserved.byte_size() == max_gen_size(), "invariant"); - - MemRegion cmr((HeapWord*)virtual_space()->low(), - (HeapWord*)virtual_space()->high()); - ParallelScavengeHeap::heap()->card_table()->resize_covered_region(cmr); + MemRegion cmr = committed(); + ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); + heap->card_table()->resize_covered_region(cmr); if (ZapUnusedHeapArea) { // Mangle newly committed space immediately because it @@ -85,20 +72,26 @@ void PSYoungGen::initialize_work() { } if (UseNUMA) { - _eden_space = new MutableNUMASpace(virtual_space()->page_size()); + _eden_space = new MutableNUMASpace(_heap_vs->page_size()); } else { - _eden_space = new MutableSpace(virtual_space()->page_size()); + _eden_space = new MutableSpace(_heap_vs->page_size()); } - _from_space = new MutableSpace(virtual_space()->page_size()); - _to_space = new MutableSpace(virtual_space()->page_size()); + _from_space = new MutableSpace(_heap_vs->page_size()); + _to_space = new MutableSpace(_heap_vs->page_size()); + // Young-gen can become zero-sized in old-gen only mode. + size_t young_gen_min_size = 0; // Generation Counters - generation 0, 3 subspaces - _gen_counters = new GenerationCounters("new", 0, 3, min_gen_size(), - max_gen_size(), virtual_space()->committed_size()); + _gen_counters = new GenerationCounters("new", + 0, + 3, + young_gen_min_size, + max_gen_size(), + committed_size()); // Compute maximum space sizes for performance counters size_t alignment = SpaceAlignment; - size_t size = virtual_space()->reserved_size(); + size_t size = reserved_size(); size_t max_survivor_size; size_t max_eden_size; @@ -156,7 +149,7 @@ void PSYoungGen::initialize_work() { void PSYoungGen::compute_initial_space_boundaries() { // Compute sizes - size_t size = virtual_space()->committed_size(); + size_t size = committed_size(); assert(size >= 3 * SpaceAlignment, "Young space is not large enough for eden + 2 survivors"); size_t survivor_size = size / InitialSurvivorRatio; @@ -179,18 +172,27 @@ void PSYoungGen::compute_initial_space_boundaries() { } void PSYoungGen::set_space_boundaries(size_t eden_size, size_t survivor_size) { - assert(eden_size < virtual_space()->committed_size(), "just checking"); - assert(eden_size > 0 && survivor_size > 0, "just checking"); +#ifdef ASSERT + { + if (eden_size != 0) { + assert(survivor_size != 0, "precondition"); + assert(eden_size < committed_size(), "precondition"); + } else { + assert(survivor_size == 0, "precondition"); + assert(committed_size() == 0, "precondition"); + } + } +#endif // Layout: to, from, eden - char *to_start = virtual_space()->low(); + char *to_start = _heap_vs->young_gen_low_addr(); char *to_end = to_start + survivor_size; char *from_start = to_end; char *from_end = from_start + survivor_size; char *eden_start = from_end; char *eden_end = eden_start + eden_size; - assert(eden_end == virtual_space()->high(), "just checking"); + assert(eden_end == _heap_vs->young_gen_committed_high_addr(), "just checking"); assert(is_object_aligned(eden_start), "checking alignment"); assert(is_object_aligned(to_start), "checking alignment"); @@ -208,8 +210,6 @@ void PSYoungGen::set_space_boundaries(size_t eden_size, size_t survivor_size) { #ifndef PRODUCT void PSYoungGen::space_invariants() { - guarantee(eden_space()->capacity_in_bytes() >= SpaceAlignment, "eden too small"); - guarantee(from_space()->capacity_in_bytes() >= SpaceAlignment, "from too small"); assert(from_space()->capacity_in_bytes() == to_space()->capacity_in_bytes(), "inv"); HeapWord* eden_bottom = eden_space()->bottom(); @@ -229,7 +229,7 @@ void PSYoungGen::space_invariants() { assert(to_bottom <= to_top && to_top <= to_end, "inv"); // Relationship of spaces to each other; from/to, eden - guarantee((char*)MIN2(from_bottom, to_bottom) == virtual_space()->low(), "inv"); + guarantee((char*)MIN2(from_bottom, to_bottom) == _heap_vs->young_gen_low_addr(), "inv"); guarantee(is_aligned(eden_bottom, SpaceAlignment), "inv"); guarantee(is_aligned(from_bottom, SpaceAlignment), "inv"); @@ -245,16 +245,16 @@ void PSYoungGen::space_invariants() { guarantee(to_end == from_bottom, "inv"); guarantee(from_end == eden_bottom, "inv"); } - guarantee((char*)eden_end <= virtual_space()->high(), "inv"); + guarantee((char*)eden_end <= _heap_vs->young_gen_committed_high_addr(), "inv"); guarantee(is_aligned(eden_end, SpaceAlignment), "inv"); // More checks that the virtual space is consistent with the spaces - assert(virtual_space()->committed_size() >= + assert(committed_size() >= (eden_space()->capacity_in_bytes() + 2 * from_space()->capacity_in_bytes()), "Committed size is inconsistent"); - assert(virtual_space()->committed_size() <= virtual_space()->reserved_size(), + assert(committed_size() <= reserved_size(), "Space invariant"); - virtual_space()->verify(); + _heap_vs->verify(); } #endif @@ -268,31 +268,31 @@ bool PSYoungGen::try_expand_to_hold(size_t word_size) { } // For logging purpose - size_t original_committed_size = virtual_space()->committed_size(); + size_t original_committed_size = committed_size(); - assert(is_aligned(virtual_space()->committed_high_addr(), SpaceAlignment), "inv"); - if (pointer_delta(virtual_space()->committed_high_addr(), eden_space()->top(), sizeof(HeapWord)) >= word_size) { + assert(is_aligned(_heap_vs->young_gen_committed_high_addr(), SpaceAlignment), "inv"); + if (pointer_delta(_heap_vs->young_gen_committed_high_addr(), eden_space()->top(), sizeof(HeapWord)) >= word_size) { // eden needs expansion but no OS committing - assert(virtual_space()->committed_high_addr() > (char*)eden_space()->end(), "inv"); + assert(_heap_vs->young_gen_committed_high_addr() > (char*)eden_space()->end(), "inv"); } else { // eden needs OS committing and expansion - assert(virtual_space()->reserved_high_addr() > virtual_space()->committed_high_addr(), "inv"); + assert(_heap_vs->young_gen_high_addr() > _heap_vs->young_gen_committed_high_addr(), "inv"); const size_t existing_free_in_eden = eden_space()->free_in_words(); assert(existing_free_in_eden < word_size, "inv"); size_t delta_words = word_size - existing_free_in_eden; size_t delta_bytes = delta_words * HeapWordSize; - delta_bytes = align_up(delta_bytes, virtual_space()->alignment()); - if (!virtual_space()->expand_by(delta_bytes)) { + delta_bytes = align_up(delta_bytes, _heap_vs->alignment()); + if (!_heap_vs->expand_young_gen(delta_bytes)) { // Expansion fails at OS level. return false; } - assert(is_aligned(virtual_space()->committed_high_addr(), SpaceAlignment), "inv"); + assert(is_aligned(_heap_vs->young_gen_committed_high_addr(), SpaceAlignment), "inv"); } - HeapWord* new_eden_end = (HeapWord*) virtual_space()->committed_high_addr(); + HeapWord* new_eden_end = (HeapWord*) _heap_vs->young_gen_committed_high_addr(); assert(new_eden_end > eden_space()->end(), "inv"); MemRegion edenMR = MemRegion(eden_space()->bottom(), new_eden_end); @@ -307,7 +307,7 @@ bool PSYoungGen::try_expand_to_hold(size_t word_size) { } post_resize(); log_debug(gc, ergo)("PSYoung size changed (eden expansion): %zuK->%zuK", - original_committed_size / K, virtual_space()->committed_size() / K); + original_committed_size / K, committed_size() / K); return true; } @@ -315,7 +315,7 @@ HeapWord* PSYoungGen::expand_and_allocate(size_t word_size) { assert(Heap_lock->is_locked(), "precondition"); { - size_t available_word_size = pointer_delta(virtual_space()->reserved_high_addr(), + size_t available_word_size = pointer_delta(_heap_vs->young_gen_high_addr(), eden_space()->top(), sizeof(HeapWord)); if (word_size > available_word_size) { @@ -334,33 +334,69 @@ HeapWord* PSYoungGen::expand_and_allocate(size_t word_size) { return result; } -void PSYoungGen::compute_desired_sizes(bool is_survivor_overflowing, - size_t& eden_size, - size_t& survivor_size) { - assert(eden_space()->is_empty() && to_space()->is_empty(), "precondition"); +void PSYoungGen::resize_inner(size_t desired_eden_size, + size_t desired_survivor_size) { + assert(desired_eden_size != 0, "precondition"); + assert(desired_survivor_size != 0, "precondition"); + assert(is_aligned(desired_eden_size, SpaceAlignment), "precondition"); + assert(is_aligned(desired_survivor_size, SpaceAlignment), "precondition"); + + size_t desired_young_gen_size = desired_eden_size + 2 * desired_survivor_size; + + assert(desired_young_gen_size >= min_gen_size(), "precondition"); + assert(desired_young_gen_size <= reserved_size(), "precondition"); + + if (eden_space()->capacity_in_bytes() == desired_eden_size + && from_space()->capacity_in_bytes() == desired_survivor_size) { + // no change + return; + } + + bool resize_success = resize_generation(desired_young_gen_size); + + if (resize_success) { + resize_spaces(desired_eden_size, desired_survivor_size); + + space_invariants(); + + log_trace(gc, ergo)("Young generation size: " + "desired eden: %zu survivor: %zu" + " used: %zu capacity: %zu" + " gen limits: %zu / %zu", + desired_eden_size, desired_survivor_size, used_in_bytes(), capacity_in_bytes(), + reserved_size(), min_gen_size()); + } +} + +bool PSYoungGen::try_resize(bool is_survivor_overflowing, + size_t old_gen_total_free_bytes, + size_t* out_eden_size, + size_t* out_survivor_size) { + assert(eden_space()->is_empty(), "precondition"); + assert(to_space()->is_empty(), "precondition"); assert(is_from_to_layout(), "precondition"); + assert(is_aligned(old_gen_total_free_bytes, SpaceAlignment), "precondition"); + + ParallelScavengeHeap* const heap = ParallelScavengeHeap::heap(); + PSAdaptiveSizePolicy* const size_policy = heap->size_policy(); + const size_t young_reserved_size = reserved_size(); + assert(young_reserved_size >= min_gen_size(), "inv"); - // Current sizes for all three spaces const size_t current_eden_size = eden_space()->capacity_in_bytes(); - assert(from_space()->capacity_in_bytes() == to_space()->capacity_in_bytes(), "inv"); const size_t current_survivor_size = from_space()->capacity_in_bytes(); - assert(current_eden_size + 2 * current_survivor_size <= max_gen_size(), "inv"); - - PSAdaptiveSizePolicy* size_policy = ParallelScavengeHeap::heap()->size_policy(); + const size_t current_young_gen_size = current_eden_size + 2 * current_survivor_size; + assert(current_survivor_size == to_space()->capacity_in_bytes(), "inv"); + assert(current_young_gen_size <= young_reserved_size, "inv"); - // eden-space - eden_size = size_policy->compute_desired_eden_size(is_survivor_overflowing, current_eden_size); + size_t eden_size = size_policy->compute_desired_eden_size(is_survivor_overflowing, + current_eden_size); eden_size = align_up(eden_size, SpaceAlignment); assert(eden_size >= SpaceAlignment, "inv"); - // from-space; survivor - const size_t survivor_used = from_space()->used_in_bytes(); - // When survivor usage is below this ratio, consider survivor space sparse. - constexpr double survivor_sparse_threshold = 0.8; - - survivor_size = size_policy->compute_desired_survivor_size(current_survivor_size, max_gen_size()); + size_t survivor_size = size_policy->compute_desired_survivor_size(current_survivor_size, + young_reserved_size); survivor_size = MAX3(survivor_size, - survivor_used, + from_space()->used_in_bytes(), SpaceAlignment); survivor_size = align_up(survivor_size, SpaceAlignment); @@ -368,149 +404,148 @@ void PSYoungGen::compute_desired_sizes(bool is_survivor_overflowing, eden_size / K, survivor_size / K); - _sizing_state = SizingState::balanced; + size_t desired_young_gen_size = eden_size + 2 * survivor_size; - if (max_gen_size() < eden_size + 2 * survivor_size) { - log_info(gc, ergo)("Requested sizes exceed MaxNewSize (K): %zu vs %zu", - (eden_size + 2 * survivor_size) / K, - max_gen_size() / K); - // Must reduce eden/survivor to satisfy the max_gen_size constraint. Prioritize survivor_space to reduce promotion. - // Check if survivor is actually using its requested size. + if (desired_young_gen_size > young_reserved_size) { + // Exceed current reserve-size; check if survivor is sparse and can be trimmed. + const size_t survivor_used = from_space()->used_in_bytes(); + constexpr double survivor_sparse_threshold = 0.8; if (!is_survivor_overflowing && survivor_used < survivor_sparse_threshold * survivor_size) { - // When survivor usage is sparse, trim survivor reservation and keep more room for eden. size_t target_survivor_size = survivor_used + survivor_used / 4; target_survivor_size = align_up(target_survivor_size, SpaceAlignment); target_survivor_size = MAX2(target_survivor_size, SpaceAlignment); if (target_survivor_size < survivor_size) { - // Decrease survivor gradually to avoid abrupt sizing swings. - // Simplified: new_survivor_size = survivor_size / 2 + 3 * survivor_used / 8. const size_t survivor_delta = survivor_size - target_survivor_size; const size_t survivor_decrement = align_up(survivor_delta / 2, SpaceAlignment); survivor_size = MAX2(target_survivor_size, survivor_size - survivor_decrement); - log_debug(gc, ergo)("Trim survivor under MaxNewSize pressure (used: %zu K, target: %zu K, new: %zu K)", + log_debug(gc, ergo)("Trim survivor under pressure (used: %zu K, target: %zu K, new: %zu K)", survivor_used / K, target_survivor_size / K, survivor_size / K); + // Recompute desired size after trimming. + desired_young_gen_size = eden_size + 2 * survivor_size; } } - - // Recheck after potential survivor_size adjustment. - if (max_gen_size() < eden_size + 2 * survivor_size) { - if (2 * survivor_size >= max_gen_size()) { - // If requested survivor size is too large - survivor_size = align_down((max_gen_size() - SpaceAlignment) / 2, SpaceAlignment); - } - - // Respect survivor size and reduce eden - eden_size = max_gen_size() - 2 * survivor_size; - - _sizing_state = SizingState::constrained; - } } - if (eden_size + 2 * survivor_size < min_gen_size()) { - // Keep survivor and adjust eden to meet min-gen-size. - eden_size = min_gen_size() - 2 * survivor_size; - - _sizing_state = SizingState::surplus; - } + // Recheck after potential trimming. + if (desired_young_gen_size > young_reserved_size) { + // Need to keep from-space parseable so that live-obj is at the start of from-space. + if (survivor_size >= young_reserved_size) { + survivor_size = young_reserved_size - SpaceAlignment; + } - const size_t final_gen_size = eden_size + 2 * survivor_size; - // A balanced result fills max_gen_size; otherwise there is surplus young-gen headroom. - if (_sizing_state == SizingState::balanced) { - if (final_gen_size < max_gen_size()) { - _sizing_state = SizingState::surplus; + if (survivor_size <= old_gen_total_free_bytes) { + eden_size = young_reserved_size - survivor_size; + const size_t new_young_gen_size = eden_size + 2 * survivor_size; + if (desired_young_gen_size > new_young_gen_size) { + set_sizing_state(SizingState::constrained); + } else if (desired_young_gen_size < new_young_gen_size) { + set_sizing_state(SizingState::surplus); + } else { + set_sizing_state(SizingState::balanced); + } + *out_eden_size = eden_size; + *out_survivor_size = survivor_size; + return false; } } -#ifdef ASSERT - { - assert(eden_size >= SpaceAlignment, "inv"); - assert(survivor_size >= SpaceAlignment, "inv"); - - assert(is_aligned(eden_size, SpaceAlignment), "inv"); - assert(is_aligned(survivor_size, SpaceAlignment), "inv"); - - assert(final_gen_size >= min_gen_size(), "inv"); - assert(final_gen_size <= max_gen_size(), "inv"); - if (final_gen_size < max_gen_size()) { - assert(_sizing_state == SizingState::surplus, "inv"); + if (desired_young_gen_size > young_reserved_size) { + set_sizing_state(SizingState::constrained); + // Cannot resize by moving the boundary; revise sizes to fit current reservation. + // Favor survivor over eden in order to reduce promotion (overflow). + if (2 * survivor_size >= young_reserved_size) { + survivor_size = align_down((young_reserved_size - SpaceAlignment) / 2, SpaceAlignment); } + eden_size = young_reserved_size - 2 * survivor_size; + } else if (desired_young_gen_size < young_reserved_size) { + set_sizing_state(SizingState::surplus); + size_t old_gen_committed_size = heap->old_gen()->committed_size(); + size_t min_young_gen_committed_size = min_gen_size(); + // To respect MinHeapSize constraint. + if (min_gen_size() + old_gen_committed_size < MinHeapSize) { + min_young_gen_committed_size = MinHeapSize - old_gen_committed_size; + } + if (desired_young_gen_size < min_young_gen_committed_size) { + // Adjust eden to meet min-gen-size while keeping survivor. + eden_size = min_young_gen_committed_size - 2 * survivor_size; + } + } else { + set_sizing_state(SizingState::balanced); } -#endif + + *out_eden_size = eden_size; + *out_survivor_size = survivor_size; + resize_inner(eden_size, survivor_size); + return true; } -void PSYoungGen::resize_inner(size_t desired_eden_size, - size_t desired_survivor_size) { +void PSYoungGen::reinit_to_from_layout(size_t desired_eden_size, size_t desired_survivor_size) { assert(desired_eden_size != 0, "precondition"); assert(desired_survivor_size != 0, "precondition"); + assert(_heap_vs->gen_boundary() + desired_survivor_size == (void*)from_space()->bottom(), "precondition"); + assert(_heap_vs->gen_boundary() == (char*) reserved().start(), "precondition"); - size_t desired_young_gen_size = desired_eden_size + 2 * desired_survivor_size; - - assert(desired_young_gen_size >= min_gen_size(), "precondition"); - assert(desired_young_gen_size <= max_gen_size(), "precondition"); - - if (eden_space()->capacity_in_bytes() == desired_eden_size - && from_space()->capacity_in_bytes() == desired_survivor_size) { - // no change - return; - } + const size_t new_gen_size = desired_eden_size + 2 * desired_survivor_size; + assert(new_gen_size > min_gen_size(), "precondition"); + assert(new_gen_size == reserved_size(), "precondition"); - bool resize_success = resize_generation(desired_young_gen_size); + assert(desired_eden_size != eden_space()->capacity_in_bytes() + || desired_survivor_size != from_space()->capacity_in_bytes(), "precondition"); - if (resize_success) { - resize_spaces(desired_eden_size, desired_survivor_size); + // to, from, eden layout + reinit_to_from_layout_inner(desired_eden_size, desired_survivor_size); - space_invariants(); + space_invariants(); - log_trace(gc, ergo)("Young generation size: " - "desired eden: %zu survivor: %zu" - " used: %zu capacity: %zu" - " gen limits: %zu / %zu", - desired_eden_size, desired_survivor_size, used_in_bytes(), capacity_in_bytes(), - max_gen_size(), min_gen_size()); - } + log_trace(gc, ergo)("Young generation size: " + "desired eden: %zu survivor: %zu" + " used: %zu capacity: %zu" + " gen limits: %zu / %zu", + desired_eden_size, desired_survivor_size, used_in_bytes(), capacity_in_bytes(), + reserved_size(), min_gen_size()); } -void PSYoungGen::resize_after_young_gc(bool is_survivor_overflowing) { +void PSYoungGen::resize(size_t desired_eden_size, size_t desired_survivor_size) { assert(eden_space()->is_empty(), "precondition"); assert(to_space()->is_empty(), "precondition"); + assert(is_from_to_layout(), "precondition"); - size_t desired_eden_size = 0; - size_t desired_survivor_size = 0; - - compute_desired_sizes(is_survivor_overflowing, - desired_eden_size, - desired_survivor_size); + size_t new_gen_size = desired_eden_size + 2 * desired_survivor_size; + if (new_gen_size < min_gen_size()) { + // Keep survivor and adjust eden to meet min-gen-size + desired_eden_size = min_gen_size() - 2 * desired_survivor_size; + } resize_inner(desired_eden_size, desired_survivor_size); } bool PSYoungGen::resize_generation(size_t desired_young_gen_size) { - const size_t alignment = virtual_space()->alignment(); - size_t orig_size = virtual_space()->committed_size(); + const size_t alignment = _heap_vs->alignment(); + size_t orig_size = committed_size(); bool size_changed = false; - assert(min_gen_size() <= orig_size && orig_size <= max_gen_size(), "just checking"); + assert(min_gen_size() <= orig_size && orig_size <= reserved_size(), "just checking"); size_t desired_size = clamp(align_up(desired_young_gen_size, alignment), min_gen_size(), - max_gen_size()); + reserved_size()); if (desired_size > orig_size) { // Grow the generation size_t change = desired_size - orig_size; assert(change % alignment == 0, "just checking"); - HeapWord* prev_high = (HeapWord*) virtual_space()->high(); - if (!virtual_space()->expand_by(change)) { + HeapWord* prev_high = (HeapWord*) _heap_vs->young_gen_committed_high_addr(); + if (!_heap_vs->expand_young_gen(change)) { return false; // Error if we fail to resize! } if (ZapUnusedHeapArea) { // Mangle newly committed space immediately because it - // can be done here more simply that after the new + // can be done here more simply than after the new // spaces have been computed. - HeapWord* new_high = (HeapWord*) virtual_space()->high(); + HeapWord* new_high = (HeapWord*) _heap_vs->young_gen_committed_high_addr(); MemRegion mangle_region(prev_high, new_high); SpaceMangler::mangle_region(mangle_region); } @@ -518,10 +553,10 @@ bool PSYoungGen::resize_generation(size_t desired_young_gen_size) { } else if (desired_size < orig_size) { size_t desired_change = orig_size - desired_size; assert(desired_change % alignment == 0, "just checking"); - virtual_space()->shrink_by(desired_change); + _heap_vs->shrink_young_gen(desired_change); size_changed = true; } else { - if (orig_size == max_gen_size()) { + if (orig_size == reserved_size()) { log_trace(gc)("PSYoung generation size at maximum: %zuK", orig_size/K); } else if (orig_size == min_gen_size()) { log_trace(gc)("PSYoung generation size at minimum: %zuK", orig_size/K); @@ -531,32 +566,87 @@ bool PSYoungGen::resize_generation(size_t desired_young_gen_size) { if (size_changed) { post_resize(); log_trace(gc)("PSYoung generation size changed: %zuK->%zuK", - orig_size/K, virtual_space()->committed_size()/K); + orig_size/K, committed_size()/K); } - guarantee(desired_young_gen_size <= virtual_space()->committed_size() || - virtual_space()->committed_size() == max_gen_size(), "Sanity"); + guarantee(desired_young_gen_size <= committed_size() || + committed_size() == reserved_size(), "Sanity"); return true; } +void PSYoungGen::reinit_to_from_layout_inner(size_t requested_eden_size, + size_t requested_survivor_size) { + assert(requested_eden_size > 0 && requested_survivor_size > 0, + "precondition"); + assert(is_aligned(requested_eden_size, SpaceAlignment), "precondition"); + assert(is_aligned(requested_survivor_size, SpaceAlignment), "precondition"); + + // layout: to, from, eden + char* to_start = _heap_vs->young_gen_low_addr(); + char* to_end = to_start + requested_survivor_size; + char* from_start = to_end; + char* from_end = from_start + requested_survivor_size; + char* eden_start = from_end; + char* eden_end = eden_start + requested_eden_size; + + assert(eden_end == _heap_vs->young_gen_committed_high_addr(), "inv"); + + MemRegion edenMR((HeapWord*)eden_start, (HeapWord*)eden_end); + MemRegion fromMR((HeapWord*)from_start, (HeapWord*)from_end); + MemRegion toMR ((HeapWord*)to_start, (HeapWord*)to_end); + +#ifdef ASSERT + if (!from_space()->is_empty()) { + assert(fromMR.start() == from_space()->bottom(), "inv"); + assert(fromMR.contains(from_space()->used_region()), "inv"); + } +#endif + // For logging below + size_t old_from_capacity = from_space()->capacity_in_bytes(); + size_t old_to_capacity = to_space()->capacity_in_bytes(); + + WorkerThreads* workers = &ParallelScavengeHeap::heap()->workers(); + + eden_space()->initialize(edenMR, + SpaceDecorator::Clear, + SpaceDecorator::DontMangle, + MutableSpace::SetupPages, + workers); + to_space()->initialize(toMR, + SpaceDecorator::Clear, + SpaceDecorator::DontMangle, + MutableSpace::SetupPages, + workers); + from_space()->initialize(fromMR, + from_space()->is_empty(), + SpaceDecorator::DontMangle, + MutableSpace::SetupPages, + workers); + + log_trace(gc, ergo)("AdaptiveSizePolicy::survivor sizes: (%zu, %zu) -> (%zu, %zu) ", + old_from_capacity, old_to_capacity, + from_space()->capacity_in_bytes(), + to_space()->capacity_in_bytes()); +} + void PSYoungGen::resize_spaces(size_t requested_eden_size, size_t requested_survivor_size) { assert(requested_eden_size > 0 && requested_survivor_size > 0, "precondition"); assert(is_aligned(requested_eden_size, SpaceAlignment), "precondition"); assert(is_aligned(requested_survivor_size, SpaceAlignment), "precondition"); - assert(from_space()->bottom() < to_space()->bottom(), "precondition"); + assert(is_from_to_layout(), "precondition"); // layout: from, to, eden - char* from_start = virtual_space()->low(); + char* from_start = _heap_vs->young_gen_low_addr(); char* from_end = from_start + requested_survivor_size; char* to_start = from_end; char* to_end = to_start + requested_survivor_size; char* eden_start = to_end; char* eden_end = eden_start + requested_eden_size; - assert(eden_end <= virtual_space()->high(), "inv"); + assert(eden_end <= _heap_vs->young_gen_committed_high_addr(), "inv"); MemRegion edenMR((HeapWord*)eden_start, (HeapWord*)eden_end); MemRegion fromMR((HeapWord*)from_start, (HeapWord*)from_end); @@ -590,20 +680,49 @@ void PSYoungGen::resize_spaces(size_t requested_eden_size, MutableSpace::SetupPages, workers); - if (ZapUnusedHeapArea) { - if (!UseNUMA) { - eden_space()->mangle_unused_area(); - } - to_space()->mangle_unused_area(); - from_space()->mangle_unused_area(); - } - log_trace(gc, ergo)("AdaptiveSizePolicy::survivor sizes: (%zu, %zu) -> (%zu, %zu) ", old_from_capacity, old_to_capacity, from_space()->capacity_in_bytes(), to_space()->capacity_in_bytes()); } +void PSYoungGen::reinit_after_gen_boundary_change() { + PSScavenge::reset_young_gen_reserved(reserved()); + + size_t committed_size = this->committed_size(); + + if (committed_size > 0) { + assert(committed_size >= min_gen_size(), "precondition"); + } + + size_t survivor_size = committed_size / InitialSurvivorRatio; + survivor_size = align_down(survivor_size, SpaceAlignment); + if (survivor_size == 0 && committed_size > 0) { + survivor_size = SpaceAlignment; + // For from/to/eden spaces + assert(committed_size >= 3 * SpaceAlignment, "inv"); + } + + size_t eden_size = committed_size - 2 * survivor_size; + + set_space_boundaries(eden_size, survivor_size); + +#ifdef ASSERT + { + bool is_eden_zero_sized = eden_space()->capacity_in_bytes() == 0; + bool is_from_zero_sized = from_space()->capacity_in_bytes() == 0; + bool is_to_zero_sized = to_space()->capacity_in_bytes() == 0; + bool is_young_gen_zero_sized = reserved_size() == 0; + assert(is_eden_zero_sized == is_from_zero_sized, "inv"); + assert(is_from_zero_sized == is_to_zero_sized, "inv"); + assert(is_eden_zero_sized == is_young_gen_zero_sized, "inv"); + if (is_young_gen_zero_sized) { + assert(_heap_vs->gen_boundary() == (char*)ParallelScavengeHeap::heap()->reserved_region().end(), "inv"); + } + } +#endif +} + void PSYoungGen::swap_spaces() { MutableSpace* s = from_space(); _from_space = to_space(); @@ -654,7 +773,10 @@ void PSYoungGen::print() const { print_on(tty); } void PSYoungGen::print_on(outputStream* st) const { st->print("%-15s", name()); st->print(" total %zuK, used %zuK ", capacity_in_bytes() / K, used_in_bytes() / K); - virtual_space()->print_space_boundaries_on(st); + st->print_cr("Young Gen: [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ")", + p2i(_heap_vs->young_gen_low_addr()), + p2i(_heap_vs->young_gen_committed_high_addr()), + p2i(_heap_vs->young_gen_high_addr())); StreamIndentor si(st, 1); eden_space()->print_on(st, "eden "); @@ -665,8 +787,8 @@ void PSYoungGen::print_on(outputStream* st) const { void PSYoungGen::post_resize() { assert_locked_or_safepoint(Heap_lock); - MemRegion cmr((HeapWord*)virtual_space()->low(), - (HeapWord*)virtual_space()->high()); + MemRegion cmr((HeapWord*)_heap_vs->young_gen_low_addr(), + (HeapWord*)_heap_vs->young_gen_committed_high_addr()); ParallelScavengeHeap::heap()->card_table()->resize_covered_region(cmr); } @@ -675,7 +797,7 @@ void PSYoungGen::update_counters() { _eden_counters->update_all(_eden_space->capacity_in_bytes(), _eden_space->used_in_bytes()); _from_counters->update_all(_from_space->capacity_in_bytes(), _from_space->used_in_bytes()); _to_counters->update_all(_to_space->capacity_in_bytes(), _to_space->used_in_bytes()); - _gen_counters->update_capacity(_virtual_space->committed_size()); + _gen_counters->update_capacity(committed_size()); } } diff --git a/src/hotspot/share/gc/parallel/psYoungGen.hpp b/src/hotspot/share/gc/parallel/psYoungGen.hpp index d2c483f638aa..6fb130356537 100644 --- a/src/hotspot/share/gc/parallel/psYoungGen.hpp +++ b/src/hotspot/share/gc/parallel/psYoungGen.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,7 @@ #define SHARE_GC_PARALLEL_PSYOUNGGEN_HPP #include "gc/parallel/mutableSpace.hpp" -#include "gc/parallel/objectStartArray.hpp" -#include "gc/parallel/psVirtualspace.hpp" +#include "gc/parallel/psHeapVirtualSpace.hpp" #include "gc/shared/generationCounters.hpp" #include "gc/shared/hSpaceCounters.hpp" @@ -54,8 +53,7 @@ class PSYoungGen : public CHeapObj { }; private: - MemRegion _reserved; - PSVirtualSpace* _virtual_space; + PSHeapVirtualSpace* _heap_vs; // Spaces MutableSpace* _eden_space; @@ -66,9 +64,13 @@ class PSYoungGen : public CHeapObj { const size_t _min_gen_size; const size_t _max_gen_size; - // Current young-gen sizing state, updated by compute_desired_sizes(). + size_t min_gen_size() const { return _min_gen_size; } + + // Current young-gen sizing state, updated after young-gen resizing. SizingState _sizing_state; + void set_sizing_state(SizingState sizing_state) { _sizing_state = sizing_state; } + // Performance counters GenerationCounters* _gen_counters; HSpaceCounters* _eden_counters; @@ -85,6 +87,9 @@ class PSYoungGen : public CHeapObj { void resize_spaces(size_t requested_eden_size, size_t requested_survivor_size); + void reinit_to_from_layout_inner(size_t requested_eden_size, + size_t requested_survivor_size); + // Try to expand eden to hold at least word_size. // Return true iff the expansion is successful. bool try_expand_to_hold(size_t word_size); @@ -92,38 +97,45 @@ class PSYoungGen : public CHeapObj { // Adjust the spaces to be consistent with the virtual space. void post_resize(); - void initialize(ReservedSpace rs, size_t inital_size, size_t alignment); void initialize_work(); - void initialize_virtual_space(ReservedSpace rs, size_t initial_size, size_t alignment); - - void compute_desired_sizes(bool is_survivor_overflowing, - size_t& eden_size, - size_t& survivor_size); void resize_inner(size_t desired_eden_size, size_t desired_survivor_size); public: // Initialize the generation. - PSYoungGen(ReservedSpace rs, + PSYoungGen(PSHeapVirtualSpace* vs, size_t initial_byte_size, - size_t minimum_byte_size, - size_t maximum_byte_size); + size_t min_gen_size, + size_t max_gen_size); - MemRegion reserved() const { return _reserved; } + MemRegion reserved() const { + return MemRegion((HeapWord*) _heap_vs->young_gen_low_addr(), + (HeapWord*) _heap_vs->young_gen_high_addr()); + } + + MemRegion committed() const { + return MemRegion((HeapWord*) _heap_vs->young_gen_low_addr(), + (HeapWord*) _heap_vs->young_gen_committed_high_addr()); + } + + size_t reserved_size() const { return reserved().byte_size(); } + size_t committed_size() const { return committed().byte_size(); } + size_t uncommitted_size() const { return reserved_size() - committed_size(); } bool is_in(const void* p) const { - return _virtual_space->is_in_committed(p); + return committed().contains(p); } bool is_in_reserved(const void* p) const { - return reserved().contains((void *)p); + return reserved().contains(p); } + void reinit_after_gen_boundary_change(); + MutableSpace* eden_space() const { return _eden_space; } MutableSpace* from_space() const { return _from_space; } MutableSpace* to_space() const { return _to_space; } - PSVirtualSpace* virtual_space() const { return _virtual_space; } // Called during/after GC void swap_spaces(); @@ -132,7 +144,14 @@ class PSYoungGen : public CHeapObj { return from_space()->bottom() < to_space()->bottom(); } - void resize_after_young_gc(bool is_survivor_overflowing); + void resize(size_t desired_eden_size, size_t desired_survivor_size); + // Returns true if resizing was completed within the current young-gen reservation. + // Returns false if desired sizes were prepared for a caller-managed gen-boundary left shift. + bool try_resize(bool is_survivor_overflowing, + size_t old_gen_total_free_bytes, + size_t* out_eden_size, + size_t* out_survivor_size); + void reinit_to_from_layout(size_t desired_eden_size, size_t desired_survivor_size); // Size info size_t capacity_in_bytes() const; @@ -143,7 +162,6 @@ class PSYoungGen : public CHeapObj { size_t used_in_words() const; size_t free_in_words() const; - size_t min_gen_size() const { return _min_gen_size; } size_t max_gen_size() const { return _max_gen_size; } SizingState sizing_state() const { return _sizing_state; } diff --git a/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp b/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp index f8dabc4539ed..cdcc7aec7869 100644 --- a/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp +++ b/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,10 +27,10 @@ #include "gc/parallel/mutableSpace.hpp" #include "gc/parallel/parallelScavengeHeap.hpp" +#include "gc/parallel/psHeapVirtualSpace.hpp" #include "gc/parallel/psOldGen.hpp" #include "gc/parallel/psVirtualspace.hpp" #include "gc/parallel/psYoungGen.hpp" -#include "gc/parallel/vmStructs_parallelgc.hpp" #define VM_STRUCTS_PARALLELGC(nonstatic_field, \ volatile_nonstatic_field, \ @@ -46,23 +46,25 @@ nonstatic_field(PSVirtualSpace, _committed_low_addr, char*) \ nonstatic_field(PSVirtualSpace, _committed_high_addr, char*) \ \ + nonstatic_field(PSHeapVirtualSpace, _alignment, const size_t) \ + nonstatic_field(PSHeapVirtualSpace, _page_size, const size_t) \ + nonstatic_field(PSHeapVirtualSpace, _reserved_low_addr, char*) \ + nonstatic_field(PSHeapVirtualSpace, _reserved_high_addr, char*) \ + nonstatic_field(PSHeapVirtualSpace, _gen_boundary, char*) \ + nonstatic_field(PSHeapVirtualSpace, _old_gen_committed_high_addr, char*) \ + nonstatic_field(PSHeapVirtualSpace, _young_gen_committed_high_addr, char*) \ + \ nonstatic_field(MutableSpace, _bottom, HeapWord*) \ nonstatic_field(MutableSpace, _end, Atomic) \ volatile_nonstatic_field(MutableSpace, _top, Atomic) \ \ - nonstatic_field(PSYoungGen, _reserved, MemRegion) \ - nonstatic_field(PSYoungGen, _virtual_space, PSVirtualSpace*) \ + nonstatic_field(PSYoungGen, _heap_vs, PSHeapVirtualSpace*) \ nonstatic_field(PSYoungGen, _eden_space, MutableSpace*) \ nonstatic_field(PSYoungGen, _from_space, MutableSpace*) \ nonstatic_field(PSYoungGen, _to_space, MutableSpace*) \ - nonstatic_field(PSYoungGen, _min_gen_size, const size_t) \ - nonstatic_field(PSYoungGen, _max_gen_size, const size_t) \ \ - nonstatic_field(PSOldGen, _virtual_space, PSVirtualSpace*) \ + nonstatic_field(PSOldGen, _heap_vs, PSHeapVirtualSpace*) \ nonstatic_field(PSOldGen, _object_space, MutableSpace*) \ - nonstatic_field(PSOldGen, _min_gen_size, const size_t) \ - nonstatic_field(PSOldGen, _max_gen_size, const size_t) \ - \ \ nonstatic_field(ParallelScavengeHeap, _young_gen, PSYoungGen*) \ nonstatic_field(ParallelScavengeHeap, _old_gen, PSOldGen*) \ @@ -79,6 +81,7 @@ declare_type(ParallelScavengeHeap, CollectedHeap) \ \ declare_toplevel_type(PSVirtualSpace) \ + declare_toplevel_type(PSHeapVirtualSpace) \ declare_toplevel_type(MutableSpace) \ declare_toplevel_type(PSYoungGen) \ declare_toplevel_type(PSOldGen) \ @@ -88,6 +91,7 @@ /*****************************/ \ \ declare_toplevel_type(PSVirtualSpace*) \ + declare_toplevel_type(PSHeapVirtualSpace*) \ declare_toplevel_type(MutableSpace*) \ declare_toplevel_type(PSYoungGen*) \ declare_toplevel_type(PSOldGen*) \ diff --git a/src/hotspot/share/gc/shared/barrierSetRuntime.cpp b/src/hotspot/share/gc/shared/barrierSetRuntime.cpp index 2f4babd21a27..173ab0eda4b9 100644 --- a/src/hotspot/share/gc/shared/barrierSetRuntime.cpp +++ b/src/hotspot/share/gc/shared/barrierSetRuntime.cpp @@ -28,13 +28,13 @@ #include "runtime/interfaceSupport.inline.hpp" #include "utilities/macros.hpp" -JRT_LEAF(void, BarrierSetRuntime::value_copy(address src, address dst, InlineLayoutInfo* li)) +JRT_LEAF(void, BarrierSetRuntime::value_copy(address src, address dst, ValueFieldLayoutInfo* li)) ValuePayload src_payload = ValuePayload::construct_from_parts(src, li->klass(), li->kind()); ValuePayload dst_payload = ValuePayload::construct_from_parts(dst, li->klass(), li->kind()); HeapAccess<>::value_copy(src_payload, dst_payload); JRT_END -JRT_LEAF(void, BarrierSetRuntime::value_copy_is_dest_uninitialized(address src, address dst, InlineLayoutInfo* li)) +JRT_LEAF(void, BarrierSetRuntime::value_copy_is_dest_uninitialized(address src, address dst, ValueFieldLayoutInfo* li)) ValuePayload src_payload = ValuePayload::construct_from_parts(src, li->klass(), li->kind()); ValuePayload dst_payload = ValuePayload::construct_from_parts(dst, li->klass(), li->kind()); HeapAccess::value_copy(src_payload, dst_payload); diff --git a/src/hotspot/share/gc/shared/barrierSetRuntime.hpp b/src/hotspot/share/gc/shared/barrierSetRuntime.hpp index 8c74aac6c60a..67061f8c158e 100644 --- a/src/hotspot/share/gc/shared/barrierSetRuntime.hpp +++ b/src/hotspot/share/gc/shared/barrierSetRuntime.hpp @@ -26,14 +26,14 @@ #define SHARE_GC_SHARED_BARRIERSETRUNTIME_HPP #include "memory/allocation.hpp" -#include "oops/inlineKlass.hpp" +#include "oops/valueKlass.hpp" #include "utilities/globalDefinitions.hpp" class BarrierSetRuntime: public AllStatic { public: // Template interpreter... - static void value_copy(address src, address dst, InlineLayoutInfo* layout_info); - static void value_copy_is_dest_uninitialized(address src, address dst, InlineLayoutInfo* layout_info); + static void value_copy(address src, address dst, ValueFieldLayoutInfo* li); + static void value_copy_is_dest_uninitialized(address src, address dst, ValueFieldLayoutInfo* li); }; #endif // SHARE_GC_SHARED_BARRIERSETRUNTIME_HPP diff --git a/src/hotspot/share/gc/shared/c1/barrierSetC1.hpp b/src/hotspot/share/gc/shared/c1/barrierSetC1.hpp index 042a3ffb35ad..f6e0f765d51b 100644 --- a/src/hotspot/share/gc/shared/c1/barrierSetC1.hpp +++ b/src/hotspot/share/gc/shared/c1/barrierSetC1.hpp @@ -70,12 +70,12 @@ class LIRAccess: public StackObj { LIR_Opr _resolved_addr; CodeEmitInfo* _patch_emit_info; CodeEmitInfo* _access_emit_info; - ciInlineKlass* _vk; // For flat, atomic accesses that might require GC barriers on oop fields + ciValueKlass* _vk; // For flat, atomic accesses that might require GC barriers on oop fields public: LIRAccess(LIRGenerator* gen, DecoratorSet decorators, LIRAddressOpr base, LIRAddressOpr offset, BasicType type, - CodeEmitInfo* patch_emit_info = nullptr, CodeEmitInfo* access_emit_info = nullptr, ciInlineKlass* vk = nullptr) : + CodeEmitInfo* patch_emit_info = nullptr, CodeEmitInfo* access_emit_info = nullptr, ciValueKlass* vk = nullptr) : _gen(gen), _decorators(AccessInternal::decorator_fixup(decorators, type)), _base(base), @@ -106,7 +106,7 @@ class LIRAccess: public StackObj { DecoratorSet decorators() const { return _decorators; } void clear_decorators(DecoratorSet ds) { _decorators &= ~ds; } bool is_raw() const { return (_decorators & AS_RAW) != 0; } - ciInlineKlass* vk() const { return _vk; } + ciValueKlass* vk() const { return _vk; } }; // The BarrierSetC1 class is the main entry point for the GC backend of the Access API in C1. diff --git a/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp b/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp index d478840578f2..b848c9687d8c 100644 --- a/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp +++ b/src/hotspot/share/gc/shared/c1/cardTableBarrierSetC1.cpp @@ -23,7 +23,7 @@ */ #include "c1/c1_IR.hpp" -#include "ci/ciInlineKlass.hpp" +#include "ci/ciValueKlass.hpp" #include "code/aotCodeCache.hpp" #include "gc/shared/c1/cardTableBarrierSetC1.hpp" #include "gc/shared/cardTable.hpp" @@ -43,7 +43,7 @@ void CardTableBarrierSetC1::store_at_resolved(LIRAccess& access, LIR_Opr value) bool on_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0; // Is this a flat, atomic access that might require gc barriers on oop fields? - ciInlineKlass* vk = access.vk(); + ciValueKlass* vk = access.vk(); if (vk != nullptr && vk->has_object_fields()) { // Add pre-barriers for oop fields for (int i = 0; i < vk->nof_nonstatic_fields(); i++) { diff --git a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp index 8ff93029e832..e116b4c94fc6 100644 --- a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp +++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp @@ -148,14 +148,14 @@ class C2ParseAccess: public C2Access { protected: GraphKit* _kit; Node* _ctl; - const InlineTypeNode* _vt; // For flat, atomic accesses that might require GC barriers on oop fields + const ValueTypeNode* _vt; // For flat, atomic accesses that might require GC barriers on oop fields void* barrier_set_state() const; public: C2ParseAccess(GraphKit* kit, DecoratorSet decorators, BasicType type, Node* base, C2AccessValuePtr& addr, - Node* ctl = nullptr, const InlineTypeNode* vt = nullptr) : + Node* ctl = nullptr, const ValueTypeNode* vt = nullptr) : C2Access(decorators, type, base, addr), _kit(kit), _ctl(ctl), @@ -165,7 +165,7 @@ class C2ParseAccess: public C2Access { GraphKit* kit() const { return _kit; } Node* control() const; - const InlineTypeNode* vt() const { return _vt; } + const ValueTypeNode* vt() const { return _vt; } virtual PhaseGVN& gvn() const; virtual bool is_parse_access() const { return true; } diff --git a/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp b/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp index 2114865c25ee..eda65eccdf45 100644 --- a/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp @@ -47,7 +47,7 @@ Node* CardTableBarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& bool use_precise = is_array || anonymous; bool tightly_coupled_alloc = (decorators & C2_TIGHTLY_COUPLED_ALLOC) != 0; - const InlineTypeNode* vt = nullptr; + const ValueTypeNode* vt = nullptr; if (access.is_parse_access() && static_cast(access).vt() != nullptr) { vt = static_cast(access).vt(); } @@ -69,7 +69,7 @@ Node* CardTableBarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& ciField* field = vt->field(i); ciType* type = field->type(); if (!type->is_primitive_type()) { - ciInlineKlass* vk = vt->bottom_type()->inline_klass(); + ciValueKlass* vk = vt->bottom_type()->value_klass(); int field_offset = field->offset_in_bytes() - vk->payload_offset(); Node* value = vt->field_value(i); Node* field_adr = kit->basic_plus_adr(access.base(), adr, field_offset); diff --git a/src/hotspot/share/gc/shared/cardTable.cpp b/src/hotspot/share/gc/shared/cardTable.cpp index dcf13ab48e95..dc44801edb07 100644 --- a/src/hotspot/share/gc/shared/cardTable.cpp +++ b/src/hotspot/share/gc/shared/cardTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -107,14 +107,25 @@ void CardTable::initialize(void* region0_start, void* region1_start) { } MemRegion CardTable::committed_for(const MemRegion mr) const { + assert(mr.start() == _covered[0].start() + || mr.start() == _covered[1].start(), "precondition"); + + if (mr.start() == _whole_heap.end()) { + assert(mr.is_empty(), "inv"); + HeapWord* addr = (HeapWord*) byte_after(_whole_heap.end() - 1); + assert(is_aligned(addr, _page_size), "inv"); + return MemRegion{addr, (size_t)0}; + } HeapWord* addr_l = (HeapWord*)align_down(byte_for(mr.start()), _page_size); HeapWord* addr_r = mr.is_empty() ? addr_l : (HeapWord*)align_up(byte_after(mr.last()), _page_size); - if (mr.start() == _covered[0].start()) { - // In case the card for gen-boundary is not page-size aligned, the crossing page belongs to _covered[1]. - addr_r = MIN2(addr_r, (HeapWord*)align_down(byte_for(_covered[1].start()), _page_size)); + if (mr.start() == _whole_heap.start()) { + if (!_covered[1].is_empty()) { + // In case the card for gen-boundary is not page-size aligned, the crossing page belongs to _covered[1]. + addr_r = MIN2(addr_r, (HeapWord*)align_down(byte_for(_covered[1].start()), _page_size)); + } } return MemRegion(addr_l, addr_r); diff --git a/src/hotspot/share/gc/shared/cardTable.hpp b/src/hotspot/share/gc/shared/cardTable.hpp index ab26055e522f..93099683056a 100644 --- a/src/hotspot/share/gc/shared/cardTable.hpp +++ b/src/hotspot/share/gc/shared/cardTable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -94,10 +94,11 @@ class CardTable: public CHeapObj { return cards_required(_whole_heap.word_size()) - 1; } + MemRegion committed_for(const MemRegion mr) const; + private: void initialize_covered_region(void* region0_start, void* region1_start); - MemRegion committed_for(const MemRegion mr) const; public: CardTable(MemRegion whole_heap); virtual ~CardTable() = default; diff --git a/src/hotspot/share/gc/shared/cardTableBarrierSet.inline.hpp b/src/hotspot/share/gc/shared/cardTableBarrierSet.inline.hpp index dcc84bfe9c81..761d90be3a52 100644 --- a/src/hotspot/share/gc/shared/cardTableBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/shared/cardTableBarrierSet.inline.hpp @@ -30,10 +30,10 @@ #include "gc/shared/barrierSet.hpp" #include "gc/shared/cardTable.hpp" #include "oops/compressedOops.inline.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/layoutKind.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.hpp" +#include "oops/valueKlass.inline.hpp" #include "utilities/debug.hpp" template @@ -173,7 +173,7 @@ inline void CardTableBarrierSet::AccessBarrier:: value_copy_in_heap(const ValuePayload& src, const ValuePayload& dst) { precond(src.klass() == dst.klass()); - const InlineKlass* md = src.klass(); + const ValueKlass* md = src.klass(); if (!md->contains_oops()) { // If we do not have oops in the flat array, we can just do a raw copy. Raw::value_copy(src, dst); @@ -214,7 +214,7 @@ value_copy_in_heap(const ValuePayload& src, const ValuePayload& dst) { template inline void CardTableBarrierSet::AccessBarrier:: value_store_null_in_heap(const ValuePayload& dst) { - const InlineKlass* md = dst.klass(); + const ValueKlass* md = dst.klass(); if (!md->contains_oops()) { // If we do not have oops in the flat array, we can just do a raw clear. Raw::value_store_null(dst); diff --git a/src/hotspot/share/gc/shared/gcHeapSummary.hpp b/src/hotspot/share/gc/shared/gcHeapSummary.hpp index 4d209d01afbb..3dd9ac6f8adf 100644 --- a/src/hotspot/share/gc/shared/gcHeapSummary.hpp +++ b/src/hotspot/share/gc/shared/gcHeapSummary.hpp @@ -178,7 +178,7 @@ class G1EvacSummary : public StackObj { size_t _used; size_t _region_end_waste; // Number of words wasted due to skipping to the next region. - uint _regions_filled; // Number of regions filled completely. + uint _num_regions_filled; // Number of regions filled completely. size_t _num_plab_filled; // Number of PLABs refilled/retired. size_t _direct_allocated; // Number of words allocated directly into the regions. size_t _num_direct_allocated; // Number of direct allocations. @@ -205,7 +205,7 @@ class G1EvacSummary : public StackObj { size_t failure_waste) : _allocated(allocated), _wasted(wasted), _undo_wasted(undo_wasted), _unused(unused), _used(used), _region_end_waste(region_end_waste), - _regions_filled(regions_filled), _num_plab_filled(num_plab_filled), + _num_regions_filled(regions_filled), _num_plab_filled(num_plab_filled), _direct_allocated(direct_allocated),_num_direct_allocated(num_direct_allocated), _failure_used(failure_used), _failure_waste(failure_waste) { } @@ -216,7 +216,7 @@ class G1EvacSummary : public StackObj { size_t unused() const { return _unused; } size_t used() const { return _used; } size_t region_end_waste() const { return _region_end_waste; } - uint regions_filled() const { return _regions_filled; } + uint num_regions_filled() const { return _num_regions_filled; } size_t num_plab_filled() const { return _num_plab_filled; } size_t direct_allocated() const { return _direct_allocated; } size_t num_direct_allocated() const { return _num_direct_allocated; } diff --git a/src/hotspot/share/gc/shared/workerUtils.cpp b/src/hotspot/share/gc/shared/workerUtils.cpp index 736a9b007dd0..dcb2850617d0 100644 --- a/src/hotspot/share/gc/shared/workerUtils.cpp +++ b/src/hotspot/share/gc/shared/workerUtils.cpp @@ -31,12 +31,12 @@ WorkerThreadsBarrierSync::WorkerThreadsBarrierSync() : _monitor(Mutex::nosafepoint, "WorkerThreadsBarrierSync_lock"), - _n_workers(0), _n_completed(0), _should_reset(false), _aborted(false) { + _num_workers(0), _num_completed(0), _should_reset(false), _aborted(false) { } -void WorkerThreadsBarrierSync::set_n_workers(uint n_workers) { - _n_workers = n_workers; - _n_completed = 0; +void WorkerThreadsBarrierSync::set_num_workers(uint num_workers) { + _num_workers = num_workers; + _num_completed = 0; _should_reset = false; _aborted = false; } @@ -45,26 +45,26 @@ bool WorkerThreadsBarrierSync::enter() { MonitorLocker ml(monitor(), Mutex::_no_safepoint_check_flag); if (should_reset()) { // The should_reset() was set and we are the first worker to enter - // the sync barrier. We will zero the n_completed() count which + // the sync barrier. We will zero the num_completed() count which // effectively resets the barrier. zero_completed(); set_should_reset(false); } inc_completed(); - if (n_completed() == n_workers()) { + if (num_completed() == num_workers()) { // At this point we would like to reset the barrier to be ready in - // case it is used again. However, we cannot set n_completed() to + // case it is used again. However, we cannot set num_completed() to // 0, even after the notify_all(), given that some other workers - // might still be waiting for n_completed() to become == - // n_workers(). So, if we set n_completed() to 0, those workers - // will get stuck (as they will wake up, see that n_completed() != - // n_workers() and go back to sleep). Instead, we raise the + // might still be waiting for num_completed() to become == + // num_workers(). So, if we set num_completed() to 0, those workers + // will get stuck (as they will wake up, see that num_completed() != + // num_workers() and go back to sleep). Instead, we raise the // should_reset() flag and the barrier will be reset the first // time a worker enters it again. set_should_reset(true); ml.notify_all(); } else { - while (n_completed() != n_workers() && !aborted()) { + while (num_completed() != num_workers() && !aborted()) { ml.wait(); } } @@ -80,9 +80,9 @@ void WorkerThreadsBarrierSync::abort() { // SubTasksDone functions. SubTasksDone::SubTasksDone(uint n) : - _tasks(nullptr), _n_tasks(n) { + _tasks(nullptr), _num_tasks(n) { _tasks = NEW_C_HEAP_ARRAY(Atomic, n, mtInternal); - for (uint i = 0; i < _n_tasks; i++) { + for (uint i = 0; i < _num_tasks; i++) { ::new (&_tasks[i]) Atomic(false); } } @@ -94,7 +94,7 @@ void SubTasksDone::all_tasks_claimed_impl(uint skipped[], size_t skipped_size) { return; } // all non-skipped tasks are claimed - for (uint i = 0; i < _n_tasks; ++i) { + for (uint i = 0; i < _num_tasks; ++i) { if (!_tasks[i].load_relaxed()) { auto is_skipped = false; for (size_t j = 0; j < skipped_size; ++j) { @@ -109,14 +109,14 @@ void SubTasksDone::all_tasks_claimed_impl(uint skipped[], size_t skipped_size) { // all skipped tasks are *not* claimed for (size_t i = 0; i < skipped_size; ++i) { auto task_index = skipped[i]; - assert(task_index < _n_tasks, "Array in range."); + assert(task_index < _num_tasks, "Array in range."); assert(!_tasks[task_index].load_relaxed(), "%d is both claimed and skipped.", task_index); } } #endif bool SubTasksDone::try_claim_task(uint t) { - assert(t < _n_tasks, "bad task id."); + assert(t < _num_tasks, "bad task id."); return !_tasks[t].load_relaxed() && _tasks[t].compare_set(false, true); } diff --git a/src/hotspot/share/gc/shared/workerUtils.hpp b/src/hotspot/share/gc/shared/workerUtils.hpp index 7bf9d7d76564..b8f239db4cbe 100644 --- a/src/hotspot/share/gc/shared/workerUtils.hpp +++ b/src/hotspot/share/gc/shared/workerUtils.hpp @@ -38,21 +38,20 @@ // before any of them may leave. class WorkerThreadsBarrierSync : public StackObj { -protected: Monitor _monitor; - uint _n_workers; - uint _n_completed; + uint _num_workers; + uint _num_completed; bool _should_reset; bool _aborted; Monitor* monitor() { return &_monitor; } - uint n_workers() { return _n_workers; } - uint n_completed() { return _n_completed; } + uint num_workers() { return _num_workers; } + uint num_completed() { return _num_completed; } bool should_reset() { return _should_reset; } bool aborted() { return _aborted; } - void zero_completed() { _n_completed = 0; } - void inc_completed() { _n_completed++; } + void zero_completed() { _num_completed = 0; } + void inc_completed() { _num_completed++; } void set_aborted() { _aborted = true; } void set_should_reset(bool v) { _should_reset = v; } @@ -61,7 +60,7 @@ class WorkerThreadsBarrierSync : public StackObj { // Set the number of workers that will use the barrier. // Must be called before any of the workers start running. - void set_n_workers(uint n_workers); + void set_num_workers(uint num_workers); // Enter the barrier. A worker that enters the barrier will // not be allowed to leave until all other threads have @@ -71,7 +70,7 @@ class WorkerThreadsBarrierSync : public StackObj { // Aborts the barrier and wakes up any threads waiting for // the barrier to complete. The barrier will remain in the - // aborted state until the next call to set_n_workers(). + // aborted state until the next call to set_num_workers(). void abort(); }; @@ -81,7 +80,7 @@ class WorkerThreadsBarrierSync : public StackObj { class SubTasksDone: public CHeapObj { Atomic* _tasks; - uint _n_tasks; + uint _num_tasks; // make sure verification logic is run exactly once to avoid duplicate assertion failures DEBUG_ONLY(Atomic _verification_done;) diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index 298c756ef2b3..19ddeb57e612 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -460,13 +460,19 @@ void ShenandoahBarrierSetC2::elide_dominated_barrier(MachNode* node, MachNode* d } if (orig_bd != bd) { - // We are already in final output. - // Strip the extra barrier data if no real bits are left. - if ((bd & ShenandoahBitsReal) != 0) { - node->set_barrier_data(bd); - } else { - node->set_barrier_data(0); - } +#ifdef ASSERT + PhaseRegAlloc* ra = Compile::current()->regalloc(); + uint old_size = node->size(ra); +#endif + // We are already in final output. This means all nodes have already matched, + // and we are about to use Shenandoah match rules with stripped-down barriers. + // In this case, we must *not* strip non-real bits, because it would shift the + // encoding. + node->set_barrier_data(bd); +#ifdef ASSERT + uint new_size = node->size(ra); + assert(new_size <= old_size, "Node must not grow: %u -> %u", old_size, new_size); +#endif } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp index a27516f97378..33823ad1d8f4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp @@ -398,7 +398,7 @@ template void ShenandoahBarrierSet::AccessBarrier::value_copy_in_heap(const ValuePayload& src, const ValuePayload& dst) { precond(src.klass() == dst.klass()); - const InlineKlass* md = src.klass(); + const ValueKlass* md = src.klass(); if (!md->contains_oops()) { // If we do not have oops in the flat array, we can just do a raw copy. Raw::value_copy(src, dst); @@ -442,7 +442,7 @@ void ShenandoahBarrierSet::AccessBarrier::value_copy_in template void ShenandoahBarrierSet::AccessBarrier::value_store_null_in_heap(const ValuePayload& dst) { - const InlineKlass* md = dst.klass(); + const ValueKlass* md = dst.klass(); if (!md->contains_oops()) { // If we do not have oops in the flat array, we can just do a raw clear. Raw::value_store_null(dst); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 31ffbc817f12..2196083e1249 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -136,7 +136,7 @@ void ShenandoahConcurrentMark::mark_concurrent_roots() { WorkerThreads* workers = heap->workers(); ShenandoahReferenceProcessor* rp = _generation->ref_processor(); - _generation->reserve_task_queues(workers->active_workers()); + switch (_generation->type()) { case YOUNG: { ShenandoahMarkConcurrentRootsTask task(task_queues(), old_task_queues(), rp, @@ -172,7 +172,11 @@ void ShenandoahConcurrentMark::concurrent_mark() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); WorkerThreads* workers = heap->workers(); uint nworkers = workers->active_workers(); - task_queues()->reserve(nworkers); + + { + ShenandoahTimingsTracker t(ShenandoahPhaseTimings::conc_mark_rebalance_queues); + task_queues()->rebalance(nworkers); + } ShenandoahGenerationType gen_type = _generation->type(); ShenandoahSATBMarkQueueSet& qset = ShenandoahBarrierSet::satb_mark_queue_set(); @@ -257,12 +261,16 @@ void ShenandoahConcurrentMark::finish_mark_work() { // There is a very high chance we have already completed the marking. // But if there is outstanding work, finish it now. if (!task_queues()->is_empty() || satb_mq_set.completed_buffers_num() > 0) { + uint nworkers = heap->workers()->active_workers(); + + { + ShenandoahTimingsTracker t(ShenandoahPhaseTimings::final_mark_rebalance_queues); + task_queues()->rebalance(nworkers); + } + ShenandoahGCPhase phase(ShenandoahPhaseTimings::finish_mark); - uint nworkers = heap->workers()->active_workers(); - task_queues()->reserve(nworkers); TaskTerminator terminator(nworkers, task_queues()); - switch (_generation->type()) { case YOUNG:{ ShenandoahFinalMarkingTask task(this, &terminator); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index 40463a525ba5..f171e2984a1e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -389,10 +389,6 @@ void ShenandoahGeneration::post_initialize(ShenandoahHeap* heap) { assert(_free_set != nullptr, "bad initialization order"); } -void ShenandoahGeneration::reserve_task_queues(uint workers) { - _task_queues->reserve(workers); -} - ShenandoahObjToScanQueueSet* ShenandoahGeneration::old_gen_task_queues() const { return nullptr; } @@ -402,7 +398,6 @@ void ShenandoahGeneration::scan_remembered_set(bool is_concurrent) { ShenandoahGenerationalHeap* const heap = ShenandoahGenerationalHeap::heap(); uint nworkers = heap->workers()->active_workers(); - reserve_task_queues(nworkers); ShenandoahReferenceProcessor* rp = ref_processor(); ShenandoahRegionChunkIterator work_list(nworkers); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp index b58f91e7a7e9..b81b2fe3ee85 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.hpp @@ -172,7 +172,6 @@ class ShenandoahGeneration : public CHeapObj, public ShenandoahSpaceInfo { // Task queues ShenandoahObjToScanQueueSet* task_queues() const { return _task_queues; } - virtual void reserve_task_queues(uint workers); virtual ShenandoahObjToScanQueueSet* old_gen_task_queues() const; // Scan remembered set at start of concurrent young-gen marking. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index 9354ef25f3de..9c6ede961d4e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -64,10 +64,6 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, StringDedup::R ShenandoahHeap* const heap = ShenandoahHeap::heap(); ShenandoahLiveData* ld = heap->get_liveness_cache(w); - // Take outstanding work from queues not covered by current workers. - // We expect there is little work in those queues. - mark_drain_extra_queues(queues, q); - // TODO: We can clean up this if we figure out how to do templated oop closures that // play nice with specialized_oop_iterators. if (update_refs) { @@ -133,35 +129,6 @@ void ShenandoahMark::mark_loop(uint worker_id, TaskTerminator* terminator, Shena } } -template -void ShenandoahMark::mark_drain_extra_queues(ShenandoahObjToScanQueueSet* queues, ShenandoahObjToScanQueue* local_q) { - uintx stride = ShenandoahMarkLoopStride; - - ShenandoahHeap* heap = ShenandoahHeap::heap(); - ShenandoahMarkTask t; - - assert(queues->get_reserved() == heap->workers()->active_workers(), - "Safety: claimable queues do not intersect with worker queues: %u == %u", - queues->get_reserved(), heap->workers()->active_workers()); - - ShenandoahObjToScanQueue* q = queues->claim_next(); - while (q != nullptr) { - while (!q->is_empty()) { - if (CANCELLABLE && heap->check_cancelled_gc_and_yield()) { - return; - } - for (uint i = 0; i < stride; i++) { - if (q->pop(t)) { - local_q->push(t); - } else { - break; - } - } - } - q = queues->claim_next(); - } -} - template void ShenandoahMark::mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint worker_id, TaskTerminator *terminator, StringDedup::Requests* const req) { uintx stride = ShenandoahMarkLoopStride; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp index e67acccc8048..cb003bfbaab2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp @@ -109,10 +109,6 @@ class ShenandoahMark: public StackObj { NOINLINE // Main hot loop, start inlining from here void mark_loop_work(T* cl, ShenandoahLiveData* live_data, uint worker_id, TaskTerminator *t, StringDedup::Requests* const req); - template - NOINLINE // Utility loop, maybe hot, start inlining from here - void mark_drain_extra_queues(ShenandoahObjToScanQueueSet* queues, ShenandoahObjToScanQueue* local_q); - protected: template void mark_loop(uint worker_id, TaskTerminator* terminator, ShenandoahGenerationType generation_type, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp index 0e19f8fd4b4e..d1cd6440ccf0 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp @@ -73,9 +73,9 @@ void ShenandoahMark::do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveD InstanceKlass::cast(klass)->oop_oop_iterate(obj, cl); break; } - case Klass::InlineKlassKind: { - // Inline instance. - InlineKlass::cast(klass)->oop_oop_iterate(obj, cl); + case Klass::ValueKlassKind: { + // Value instance. + ValueKlass::cast(klass)->oop_oop_iterate(obj, cl); break; } case Klass::InstanceRefKlassKind: { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.cpp b/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.cpp index 82b027faca26..07b883653dc7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.cpp @@ -29,7 +29,7 @@ #include "runtime/atomicAccess.hpp" HdrSeq::HdrSeq() { - _hdr = NEW_C_HEAP_ARRAY(int*, MagBuckets, mtInternal); + _hdr = NEW_C_HEAP_ARRAY(int*, MagBuckets, mtGC); for (int c = 0; c < MagBuckets; c++) { _hdr[c] = nullptr; } @@ -95,7 +95,7 @@ void HdrSeq::add(double val) { int* b = _hdr[bucket]; if (b == nullptr) { - b = NEW_C_HEAP_ARRAY(int, ValBuckets, mtInternal); + b = NEW_C_HEAP_ARRAY(int, ValBuckets, mtGC); for (int c = 0; c < ValBuckets; c++) { b[c] = 0; } @@ -141,7 +141,7 @@ void HdrSeq::add(const HdrSeq& other) { } } else { // Create our bucket and copy the contents over - bucket = NEW_C_HEAP_ARRAY(int, ValBuckets, mtInternal); + bucket = NEW_C_HEAP_ARRAY(int, ValBuckets, mtGC); for (int val = 0; val < ValBuckets; val++) { bucket[val] = other_bucket[val]; } @@ -186,7 +186,7 @@ void HdrSeq::clear() { } BinaryMagnitudeSeq::BinaryMagnitudeSeq() { - _mags = NEW_C_HEAP_ARRAY(size_t, BitsPerSize_t, mtInternal); + _mags = NEW_C_HEAP_ARRAY(size_t, BitsPerSize_t, mtGC); clear(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp index 25ff982a9e4d..0eb5a1e6092d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp @@ -67,11 +67,13 @@ class outputStream; " CMR: ") \ SHENANDOAH_WORKER_PHASE_DEF(f, conc_mark, "Concurrent Marking", \ " CM: ") \ + SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_mark_rebalance_queues, " Rebalance Queues") \ SHENANDOAH_SIMPLE_PHASE_DEF(f, conc_mark_satb_flush, " Flush SATB") \ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_mark_gross, "Pause Final Mark (G)") \ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_mark, "Pause Final Mark (N)") \ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_mark_verify, " Verify") \ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_mark_flush_satb_roots, " Flush SATB and Roots") \ + SHENANDOAH_SIMPLE_PHASE_DEF(f, final_mark_rebalance_queues, " Rebalance Queues") \ SHENANDOAH_WORKER_PHASE_DEF(f, finish_mark, " Finish Mark", \ " FM: ") \ SHENANDOAH_SIMPLE_PHASE_DEF(f, final_mark_propagate_gc_state, " Propagate GC State") \ diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index 18fdfff125df..d482c83dd802 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -89,7 +89,7 @@ void ShenandoahSTWMark::mark() { start_mark(); uint nworkers = heap->workers()->active_workers(); - task_queues()->reserve(nworkers); + task_queues()->rebalance(nworkers); TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats()); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.cpp b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.cpp index 637bbfcb898a..670f1640027d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.cpp @@ -28,6 +28,7 @@ #include "logging/log.hpp" #include "logging/logStream.hpp" #include "memory/resourceArea.hpp" +#include "utilities/stack.inline.hpp" void ShenandoahObjToScanQueueSet::clear() { uint size = GenericTaskQueueSet::size(); @@ -50,6 +51,108 @@ bool ShenandoahObjToScanQueueSet::is_empty() { return true; } +void ShenandoahObjToScanQueueSet::rebalance(size_t target_queues) { + assert(target_queues > 0 && target_queues <= size(), "Should be in bounds: %zu", target_queues); + + // Figure out the population target. + size_t total = 0; + for (uint i = 0; i < GenericTaskQueueSet::size(); i++) { + ShenandoahObjToScanQueue* q = queue(i); + assert(q != nullptr, "Sanity"); + total += q->full_size(); + } + if (total == 0) { + // Nothing to do. + return; + } + + size_t target_size = total / target_queues; + + // Redistribute the work between queues. + // Do two passes to make sure all queues had a chance to push and pop. + Stack ts; + ShenandoahMarkTask t; + + for (int p = 0; p < 2; p++) { + for (uint i = 0; i < GenericTaskQueueSet::size(); i++) { + ShenandoahObjToScanQueue* q = queue(i); + + // Push and pop targets relative to expected average size. + size_t q_size = q->full_size(); + size_t to_pop = (q_size > target_size) ? (q_size - target_size) : 0; + size_t to_push = (q_size < target_size) ? MIN2(ts.size(), target_size - q_size) : 0; + + if (i >= target_queues) { + // Queue must be emptied out. + to_pop = q_size; + to_push = 0; + } + + for (size_t c = 0; c < to_pop; c++) { + bool succ = q->pop(t); + assert(succ, "Must succeed"); + ts.push(t); + } + assert(q->full_size() <= target_size, + "After pops, queue size (%zu) must fit the target (%zu)", + q->full_size(), target_size); + + for (size_t c = 0; c < to_push; c++) { + assert(!ts.is_empty(), "Must not be empty"); + bool succ = q->push(ts.pop()); + assert(succ, "Must succeed"); + } + } + } + + // Round-robin the remaining elements. + assert(ts.size() <= target_queues, + "Only a small tail (%zu) should remain for %zu queues", + ts.size(), target_queues); + uint rr_idx = 0; + while (!ts.is_empty()) { + queue(rr_idx)->push(ts.pop()); + if (++rr_idx >= target_queues) { + rr_idx = 0; + } + } + + // Every queue is now balanced population-wise. Balance the split between overflow + // stack and local queue. This exposes tasks to work-stealing. Avoid filling out + // the local queue completely: leave some space for local pushes. + for (uint i = 0; i < target_queues; i++) { + ShenandoahObjToScanQueue* q = queue(i); + size_t q_limit = q->capacity() / 4 * 3; + size_t q_free = (q_limit > q->size()) ? (q_limit - q->size()) : 0; + size_t to_balance = MIN2(q->overflow_stack()->size(), q_free); + for (size_t c = 0; c < to_balance; c++) { + bool succ_pop = q->pop_overflow(t); + assert(succ_pop, "Must succeed"); + bool succ_push = q->push(t); + assert(succ_push, "Must succeed"); + } + } + +#ifdef ASSERT + // Final checks. + assert(ts.is_empty(), "Must be empty"); + size_t total_after = 0; + for (uint i = 0; i < GenericTaskQueueSet::size(); i++) { + ShenandoahObjToScanQueue* q = queue(i); + if (i < target_queues) { + size_t full_size = q->full_size(); + assert((target_size <= full_size + 1) && (full_size <= target_size + 1), + "Queue size (%zu) is off the target (%zu)", + full_size, target_size); + total_after += full_size; + } else { + assert(q->is_empty(), "Queue must be empty"); + } + } + assert(total == total_after, "Lost elements: %zu vs %zu", total, total_after); +#endif +} + bool ShenandoahTerminatorTerminator::should_exit_termination() { return _heap->cancelled_gc(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp index 486a84f204ff..a7d553e1208e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp @@ -65,6 +65,10 @@ class BufferedOverflowTaskQueue: public OverflowTaskQueue NOINLINE void pop_more_overflow(); + inline size_t full_size(); + + inline size_t capacity() const; + private: bool _buf_empty; E _elem; @@ -308,56 +312,11 @@ class ShenandoahMarkTask typedef BufferedOverflowTaskQueue ShenandoahBufferedOverflowTaskQueue; typedef Padded ShenandoahObjToScanQueue; -template -class ParallelClaimableQueueSet: public GenericTaskQueueSet { -private: - shenandoah_padding(0); - Atomic _claimed_index; - shenandoah_padding(1); - - DEBUG_ONLY(uint _reserved; ) - +class ShenandoahObjToScanQueueSet: public GenericTaskQueueSet { public: - using GenericTaskQueueSet::size; - -public: - ParallelClaimableQueueSet(int n) : GenericTaskQueueSet(n), _claimed_index(0) { - DEBUG_ONLY(_reserved = 0; ) - } - - void clear_claimed() { _claimed_index.store_relaxed(0); } - T* claim_next(); - - // reserve queues that not for parallel claiming - void reserve(uint n) { - assert(n <= size(), "Sanity"); - _claimed_index.store_relaxed((jint)n); - DEBUG_ONLY(_reserved = n;) - } - - DEBUG_ONLY(uint get_reserved() const { return (uint)_reserved; }) -}; - -template -T* ParallelClaimableQueueSet::claim_next() { - jint size = (jint)GenericTaskQueueSet::size(); - - if (_claimed_index.load_relaxed() >= size) { - return nullptr; - } - - jint index = _claimed_index.add_then_fetch(1, memory_order_relaxed); + ShenandoahObjToScanQueueSet(int n) : GenericTaskQueueSet(n) {} - if (index <= size) { - return GenericTaskQueueSet::queue((uint)index - 1); - } else { - return nullptr; - } -} - -class ShenandoahObjToScanQueueSet: public ParallelClaimableQueueSet { -public: - ShenandoahObjToScanQueueSet(int n) : ParallelClaimableQueueSet(n) {} + void rebalance(size_t target_queues); bool is_empty(); void clear(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.inline.hpp index 6c070564af00..7a8bbfe55329 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.inline.hpp @@ -88,5 +88,14 @@ void BufferedOverflowTaskQueue::clear() { taskqueue_t::overflow_stack()->clear(); } +template +inline size_t BufferedOverflowTaskQueue::full_size() { + return taskqueue_t::size() + taskqueue_t::overflow_stack()->size() + (_buf_empty ? 0 : 1); +} + +template +inline size_t BufferedOverflowTaskQueue::capacity() const { + return N; +} #endif // SHARE_GC_SHENANDOAH_SHENANDOAHTASKQUEUE_INLINE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.cpp index 54572405f5f2..fbf8eb3ab3ed 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.cpp @@ -77,13 +77,6 @@ bool ShenandoahYoungGeneration::is_concurrent_mark_in_progress() { return ShenandoahHeap::heap()->is_concurrent_young_mark_in_progress(); } -void ShenandoahYoungGeneration::reserve_task_queues(uint workers) { - ShenandoahGeneration::reserve_task_queues(workers); - if (is_old_marking_active()) { - _old_gen_task_queues->reserve(workers); - } -} - bool ShenandoahYoungGeneration::contains(oop obj) const { return ShenandoahHeap::heap()->is_in_young(obj); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.hpp b/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.hpp index 6050c78a08c6..ed0c9c68bfac 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahYoungGeneration.hpp @@ -59,7 +59,6 @@ class ShenandoahYoungGeneration : public ShenandoahGeneration { bool contains(ShenandoahHeapRegion* region) const override; bool contains(oop obj) const override; - void reserve_task_queues(uint workers) override; void set_old_gen_task_queues(ShenandoahObjToScanQueueSet* old_gen_queues) { _old_gen_task_queues = old_gen_queues; } diff --git a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp index b68bf8ce35e7..566e503ccf38 100644 --- a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp @@ -33,8 +33,8 @@ #include "gc/z/zNMethod.hpp" #include "gc/z/zUtils.inline.hpp" #include "oops/accessBackend.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/objArrayOop.hpp" +#include "oops/valueKlass.inline.hpp" #include "utilities/copy.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" @@ -451,7 +451,7 @@ inline void ZBarrierSet::AccessBarrier::clone_in_heap(o // Iterate over a value payload and visit all blocks of primitive fields and all oops. template -void value_primitive_and_oop_iterate(InlineKlass* klass, +void value_primitive_and_oop_iterate(ValueKlass* klass, address payload, size_t payload_size, PrimitiveFunction primitive_function, @@ -495,7 +495,7 @@ template inline void ZBarrierSet::AccessBarrier::value_copy_in_heap(const ValuePayload& src, const ValuePayload& dst) { precond(src.klass() == dst.klass()); - InlineKlass* const klass = src.klass(); + ValueKlass* const klass = src.klass(); const LayoutKind layout_kind = LayoutKindHelper::get_copy_layout(src.layout_kind(), dst.layout_kind()); const size_t payload_size = klass->layout_size_in_bytes(layout_kind); @@ -525,7 +525,7 @@ inline void ZBarrierSet::AccessBarrier::value_copy_in_h template inline void ZBarrierSet::AccessBarrier::value_store_null_in_heap(const ValuePayload& dst) { - InlineKlass* const klass = dst.klass(); + ValueKlass* const klass = dst.klass(); const LayoutKind layout_kind = dst.layout_kind(); assert(!LayoutKindHelper::is_null_free_flat(layout_kind), diff --git a/src/hotspot/share/interpreter/bytecodeUtils.cpp b/src/hotspot/share/interpreter/bytecodeUtils.cpp index 8dd1f2288e29..88661a4a309c 100644 --- a/src/hotspot/share/interpreter/bytecodeUtils.cpp +++ b/src/hotspot/share/interpreter/bytecodeUtils.cpp @@ -313,7 +313,7 @@ static bool might_be_null_restricted_field(Method* method, address code_base, in bool is_resolved = field->is_resolved(bc); if (is_resolved) { - return field->is_null_free_inline_type(); + return field->is_null_free_value_type(); } else { // This is rare. The compiler might not have resolved the field or the klass // in the interpreter first. Just say it might be null restricted because we don't know. diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index f081d7d0968d..5f364777cdd4 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -49,7 +49,6 @@ #include "oops/cpCache.inline.hpp" #include "oops/flatArrayKlass.hpp" #include "oops/flatArrayOop.inline.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/klass.inline.hpp" #include "oops/method.inline.hpp" @@ -59,6 +58,7 @@ #include "oops/oop.inline.hpp" #include "oops/oopsHierarchy.hpp" #include "oops/symbol.hpp" +#include "oops/valueKlass.inline.hpp" #include "oops/valuePayload.inline.hpp" #include "prims/jvmtiExport.hpp" #include "prims/methodHandles.hpp" @@ -254,7 +254,7 @@ JRT_ENTRY(void, InterpreterRuntime::write_flat_field(JavaThread* current, oopDes assert(oopDesc::is_oop_or_null(value), "Sanity check"); FlatFieldPayload payload(instanceOop(obj), entry); - payload.write(inlineOop(value), CHECK); + payload.write(valueOop(value), CHECK); JRT_END JRT_ENTRY(void, InterpreterRuntime::newarray(JavaThread* current, BasicType type, jint size)) diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp index fa53c3e51150..cc3c768c0307 100644 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp +++ b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp @@ -2677,7 +2677,7 @@ void BytecodeInterpreter::run(interpreterState istate) { int field_offset = entry->field_offset(); oop val = STACK_OBJECT(-1); - if (entry->is_null_free_inline_type()) { + if (entry->is_null_free_value_type()) { CHECK_NULL_MSG(val, "Value is null"); } diff --git a/src/hotspot/share/memory/allocation.hpp b/src/hotspot/share/memory/allocation.hpp index b123d9a2b9dd..7cc76f9f1d72 100644 --- a/src/hotspot/share/memory/allocation.hpp +++ b/src/hotspot/share/memory/allocation.hpp @@ -330,7 +330,7 @@ class MetaspaceObj { f(ConstantPoolCache) \ f(Annotations) \ f(MethodCounters) \ - f(InlineLayoutInfo) \ + f(ValueFieldLayoutInfo) \ f(RecordComponent) \ f(KlassTrainingData) \ f(MethodTrainingData) \ diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index 82a4a369a5f7..bd0b0f4d88ea 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -35,8 +35,8 @@ #include "nmt/memTracker.hpp" #include "oops/fieldInfo.hpp" #include "oops/fieldStreams.inline.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/oop.inline.hpp" +#include "oops/valueKlass.inline.hpp" #include "runtime/atomicAccess.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/os.hpp" @@ -551,26 +551,26 @@ class FieldDesc { int index() const { return _index; } const InstanceKlass* holder() { return _holder; } const AccessFlags& access_flags() { return _access_flags; } - bool is_null_free_inline_type() const { return _field_flags.is_null_free_inline_type(); } + bool is_null_free_value_type() const { return _field_flags.is_null_free_value_type(); } }; static int compare_offset(FieldDesc* f1, FieldDesc* f2) { return f1->offset() > f2->offset() ? 1 : -1; } -static void print_field(outputStream* st, int level, int offset, FieldDesc& fd, bool is_inline_type, bool is_flat ) { +static void print_field(outputStream* st, int level, int offset, FieldDesc& fd, bool is_value_type, bool is_flat ) { const char* flat_field_msg = is_flat ? "flat" : ""; st->print_cr(" @ %d %*s \"%s\" %s %s %s", offset, level * 3, "", fd.name()->as_C_string(), fd.signature()->as_C_string(), - is_inline_type ? " // inline type " : "", + is_value_type ? " // value type " : "", flat_field_msg); } static void print_flat_field(outputStream* st, int level, int offset, InstanceKlass* klass) { - assert(klass->is_inline_klass(), "Only inline types can be flat"); - InlineKlass* vklass = InlineKlass::cast(klass); + assert(klass->is_value_klass(), "Only value types can be flat"); + ValueKlass* vklass = ValueKlass::cast(klass); GrowableArray* fields = new (mtServiceability) GrowableArray(100, mtServiceability); for (AllFieldStream fd(klass); !fd.done(); fd.next()) { if (!fd.access_flags().is_static()) { @@ -582,10 +582,10 @@ static void print_flat_field(outputStream* st, int level, int offset, InstanceKl FieldDesc fd = fields->at(i); int offset2 = offset + fd.offset() - vklass->payload_offset(); print_field(st, level, offset2, fd, - fd.is_null_free_inline_type(), fd.holder()->field_is_flat(fd.index())); + fd.is_null_free_value_type(), fd.holder()->field_is_flat(fd.index())); if (fd.holder()->field_is_flat(fd.index())) { print_flat_field(st, level + 1, offset2 , - InstanceKlass::cast(fd.holder()->get_inline_type_field_klass(fd.index()))); + InstanceKlass::cast(fd.holder()->get_value_type_field_klass(fd.index()))); } } } @@ -628,10 +628,10 @@ void ClassPrintLayout::class_print_layout(outputStream* st, char* class_name) { fields->sort(compare_offset); for(int i = 0; i < fields->length(); i++) { FieldDesc fd = fields->at(i); - print_field(st, 0, fd.offset(), fd, fd.is_null_free_inline_type(), fd.holder()->field_is_flat(fd.index())); + print_field(st, 0, fd.offset(), fd, fd.is_null_free_value_type(), fd.holder()->field_is_flat(fd.index())); if (fd.holder()->field_is_flat(fd.index())) { print_flat_field(st, 1, fd.offset(), - InstanceKlass::cast(fd.holder()->get_inline_type_field_klass(fd.index()))); + InstanceKlass::cast(fd.holder()->get_value_type_field_klass(fd.index()))); } } } diff --git a/src/hotspot/share/memory/iterator.inline.hpp b/src/hotspot/share/memory/iterator.inline.hpp index ca39e21dbbda..bdb4725fcad2 100644 --- a/src/hotspot/share/memory/iterator.inline.hpp +++ b/src/hotspot/share/memory/iterator.inline.hpp @@ -144,7 +144,7 @@ class OopOopIterateDispatch : public AllStatic { Table(){ set_init_function(); - set_init_function(); + set_init_function(); set_init_function(); set_init_function(); set_init_function(); @@ -210,7 +210,7 @@ class OopOopIterateBoundedDispatch { Table(){ set_init_function(); - set_init_function(); + set_init_function(); set_init_function(); set_init_function(); set_init_function(); @@ -276,7 +276,7 @@ class OopOopIterateBackwardsDispatch { Table(){ set_init_function(); - set_init_function(); + set_init_function(); set_init_function(); set_init_function(); set_init_function(); diff --git a/src/hotspot/share/memory/oopFactory.cpp b/src/hotspot/share/memory/oopFactory.cpp index 178878607d37..90d03dd8c5ff 100644 --- a/src/hotspot/share/memory/oopFactory.cpp +++ b/src/hotspot/share/memory/oopFactory.cpp @@ -135,7 +135,7 @@ refArrayOop oopFactory::new_refArray(Klass* klass, int length, TRAPS) { return new_refArray(klass, length, ArrayProperties::Default(), THREAD); } -flatArrayOop oopFactory::new_flatArray(InlineKlass* ik, int length, ArrayProperties props, TRAPS) { +flatArrayOop oopFactory::new_flatArray(ValueKlass* ik, int length, ArrayProperties props, TRAPS) { ArrayKlass* ak = ik->array_klass(CHECK_NULL); ObjArrayKlass* oak = ObjArrayKlass::cast(ak)->klass_with_properties(props, CHECK_NULL); FlatArrayKlass* fak = FlatArrayKlass::cast(oak); diff --git a/src/hotspot/share/memory/oopFactory.hpp b/src/hotspot/share/memory/oopFactory.hpp index 1d869785087d..f2be4ccb6017 100644 --- a/src/hotspot/share/memory/oopFactory.hpp +++ b/src/hotspot/share/memory/oopFactory.hpp @@ -31,7 +31,7 @@ #include "runtime/handles.hpp" #include "utilities/exceptions.hpp" -class InlineKlass; +class ValueKlass; // oopFactory is a class used for creating new objects. @@ -65,7 +65,7 @@ class oopFactory: AllStatic { static refArrayOop new_refArray(Klass* klass, int length, ArrayProperties properties, TRAPS); // Factory to create flat arrays. - static flatArrayOop new_flatArray(InlineKlass* klass, int length, ArrayProperties props, TRAPS); + static flatArrayOop new_flatArray(ValueKlass* klass, int length, ArrayProperties props, TRAPS); // Helper that returns a Handle static refArrayHandle new_refArray_handle(Klass* klass, int length, TRAPS); diff --git a/src/hotspot/share/nmt/memBaseline.cpp b/src/hotspot/share/nmt/memBaseline.cpp index 65168fd4e09b..0e66e686f544 100644 --- a/src/hotspot/share/nmt/memBaseline.cpp +++ b/src/hotspot/share/nmt/memBaseline.cpp @@ -28,6 +28,7 @@ #include "nmt/memBaseline.hpp" #include "nmt/memTracker.hpp" #include "nmt/regionsTree.inline.hpp" +#include "nmt/virtualMemoryTracker.hpp" /* * Sizes are sorted in descenting order for reporting @@ -42,7 +43,6 @@ int compare_malloc_size(const MallocSite& s1, const MallocSite& s2) { } } - int compare_virtual_memory_size(const VirtualMemoryAllocationSite& s1, const VirtualMemoryAllocationSite& s2) { if (s1.reserved() == s2.reserved()) { @@ -138,8 +138,6 @@ bool MemBaseline::baseline_allocation_sites() { if (!aggregate_virtual_memory_allocation_sites()) { return false; } - // Virtual memory allocation sites are aggregrated in call stack order - _virtual_memory_sites_order = by_address; return true; } @@ -162,31 +160,26 @@ void MemBaseline::baseline(bool summaryOnly) { } } -int compare_allocation_site(const VirtualMemoryAllocationSite& s1, - const VirtualMemoryAllocationSite& s2) { - return s1.call_stack()->compare(*s2.call_stack()); -} - bool MemBaseline::aggregate_virtual_memory_allocation_sites() { - - SortedLinkedList allocation_sites; - + auto hash = [](const VirtualMemoryAllocationSite& vmas) { return vmas.call_stack()->calculate_hash(); }; + auto equals = [](const VirtualMemoryAllocationSite& a, const VirtualMemoryAllocationSite& b) { return a.equals(b); }; + using VirtualMemorySiteTable = OpenAddressedHashTable; + VirtualMemorySiteTable vht(hash, equals); VirtualMemoryAllocationSite* site; bool failed_oom = false; _vma_allocations->visit_reserved_regions([&](VirtualMemoryRegion& rgn) { VirtualMemoryAllocationSite tmp(*rgn.reserved_call_stack(), rgn.mem_tag()); - site = allocation_sites.find(tmp); + bool found; + site = vht.put_if_absent(tmp, &found); if (site == nullptr) { - LinkedListNode* node = - allocation_sites.add(tmp); - if (node == nullptr) { - failed_oom = true; - return false; - } - site = node->data(); + failed_oom = true; + return false; } site->reserve_memory(rgn.size()); - site->commit_memory(_vma_allocations->committed_size(rgn)); return true; }); @@ -194,8 +187,11 @@ bool MemBaseline::aggregate_virtual_memory_allocation_sites() { if (failed_oom) { return false; } - - _virtual_memory_sites.move(&allocation_sites); + _virtual_memory_sites = vht.detach(&_virtual_memory_sites_length); + if (_virtual_memory_sites == nullptr) { + return false; + } + sort_virtual_memory_sites(by_site); return true; } @@ -211,15 +207,14 @@ MallocSiteIterator MemBaseline::malloc_sites(SortingOrder order) { case by_site_and_tag: malloc_sites_to_allocation_site_and_tag_order(); break; - case by_address: default: ShouldNotReachHere(); } return MallocSiteIterator(_malloc_sites.head()); } -VirtualMemorySiteIterator MemBaseline::virtual_memory_sites(SortingOrder order) { - assert(!_virtual_memory_sites.is_empty(), "Not detail baseline"); +void MemBaseline::sort_virtual_memory_sites(SortingOrder order) { + assert(_virtual_memory_sites_length != 0, "Not detail baseline"); switch(order) { case by_size: virtual_memory_sites_to_size_order(); @@ -227,11 +222,9 @@ VirtualMemorySiteIterator MemBaseline::virtual_memory_sites(SortingOrder order) case by_site: virtual_memory_sites_to_reservation_site_order(); break; - case by_address: default: ShouldNotReachHere(); } - return VirtualMemorySiteIterator(_virtual_memory_sites.head()); } @@ -272,26 +265,22 @@ void MemBaseline::malloc_sites_to_allocation_site_and_tag_order() { void MemBaseline::virtual_memory_sites_to_size_order() { if (_virtual_memory_sites_order != by_size) { - SortedLinkedList tmp; - - tmp.move(&_virtual_memory_sites); - - _virtual_memory_sites.set_head(tmp.head()); - tmp.set_head(nullptr); + ::qsort(_virtual_memory_sites, _virtual_memory_sites_length, sizeof(VirtualMemoryAllocationSite), + [](const void* a, const void* b) { + return compare_virtual_memory_size(*static_cast(a), + *static_cast(b)); + }); _virtual_memory_sites_order = by_size; } } void MemBaseline::virtual_memory_sites_to_reservation_site_order() { - if (_virtual_memory_sites_order != by_size) { - SortedLinkedList tmp; - - tmp.move(&_virtual_memory_sites); - - _virtual_memory_sites.set_head(tmp.head()); - tmp.set_head(nullptr); - - _virtual_memory_sites_order = by_size; + if (_virtual_memory_sites_order != by_site) { + ::qsort(_virtual_memory_sites, _virtual_memory_sites_length, sizeof(VirtualMemoryAllocationSite), + [](const void* a, const void* b) { + return compare_virtual_memory_site(*static_cast(a), + *static_cast(b)); + }); + _virtual_memory_sites_order = by_site; } } - diff --git a/src/hotspot/share/nmt/memBaseline.hpp b/src/hotspot/share/nmt/memBaseline.hpp index a9d604deb195..f0e02a202dd2 100644 --- a/src/hotspot/share/nmt/memBaseline.hpp +++ b/src/hotspot/share/nmt/memBaseline.hpp @@ -29,12 +29,12 @@ #include "nmt/mallocSiteTable.hpp" #include "nmt/mallocTracker.hpp" #include "nmt/nmtCommon.hpp" +#include "nmt/nmtHashTable.hpp" #include "nmt/virtualMemoryTracker.hpp" #include "runtime/mutex.hpp" #include "utilities/linkedlist.hpp" typedef LinkedListIterator MallocSiteIterator; -typedef LinkedListIterator VirtualMemorySiteIterator; /* * Baseline a memory snapshot @@ -49,10 +49,10 @@ class MemBaseline { }; enum SortingOrder { - by_address, // by memory address - by_size, // by memory size - by_site, // by call site where the memory is allocated from - by_site_and_tag // by call site and memory tag + by_size, // by memory size + by_site, // by call site where the memory is allocated from + by_site_and_tag, // by call site and memory tag + invalid }; private: @@ -72,9 +72,10 @@ class MemBaseline { // All virtual memory allocations RegionsTree* _vma_allocations; - // Virtual memory allocations by allocation sites, always in by_address + // Virtual memory allocations by allocation sites, always in by_site // order - LinkedListImpl _virtual_memory_sites; + VirtualMemoryAllocationSite* _virtual_memory_sites; + int _virtual_memory_sites_length; SortingOrder _malloc_sites_order; SortingOrder _virtual_memory_sites_order; @@ -86,11 +87,14 @@ class MemBaseline { MemBaseline(): _instance_class_count(0), _array_class_count(0), _thread_count(0), _vma_allocations(nullptr), + _virtual_memory_sites(nullptr), _virtual_memory_sites_length(0), + _malloc_sites_order(invalid), + _virtual_memory_sites_order(invalid), _baseline_type(Not_baselined) { } ~MemBaseline() { - delete _vma_allocations; + reset(); } void baseline(bool summaryOnly = true); @@ -110,7 +114,10 @@ class MemBaseline { } MallocSiteIterator malloc_sites(SortingOrder order); - VirtualMemorySiteIterator virtual_memory_sites(SortingOrder order); + void sort_virtual_memory_sites(SortingOrder order); + + VirtualMemoryAllocationSite* virtual_memory_sites() { return _virtual_memory_sites; } + int virtual_memory_sites_length() { return _virtual_memory_sites_length; } // Virtual memory allocation iterator always returns in virtual memory // base address order. @@ -188,7 +195,10 @@ class MemBaseline { _thread_count = 0; _malloc_sites.clear(); - _virtual_memory_sites.clear(); + os::free(_virtual_memory_sites); + _virtual_memory_sites_length = 0; + _virtual_memory_sites = nullptr; + _virtual_memory_sites_order = invalid; delete _vma_allocations; _vma_allocations = nullptr; } diff --git a/src/hotspot/share/nmt/memReporter.cpp b/src/hotspot/share/nmt/memReporter.cpp index 429db6ad31f0..c226b4d3078f 100644 --- a/src/hotspot/share/nmt/memReporter.cpp +++ b/src/hotspot/share/nmt/memReporter.cpp @@ -352,33 +352,30 @@ int MemDetailReporter::report_malloc_sites() { } int MemDetailReporter::report_virtual_memory_allocation_sites() { - VirtualMemorySiteIterator virtual_memory_itr = - _baseline.virtual_memory_sites(MemBaseline::by_size); - - if (virtual_memory_itr.is_empty()) return 0; + _baseline.sort_virtual_memory_sites(MemBaseline::by_size); outputStream* out = output(); - const VirtualMemoryAllocationSite* virtual_memory_site; int num_omitted = 0; - while ((virtual_memory_site = virtual_memory_itr.next()) != nullptr) { + for (int i = 0; i < _baseline.virtual_memory_sites_length(); i++) { + const VirtualMemoryAllocationSite& virtual_memory_site = _baseline.virtual_memory_sites()[i]; // Don't report free sites; does not count toward omitted count. - if (virtual_memory_site->reserved() == 0) { + if (virtual_memory_site.reserved() == 0) { continue; } // Omit printing if the current value and the historic peak value both fall below the // reporting scale threshold - if (amount_in_current_scale(MAX2(virtual_memory_site->reserved(), - virtual_memory_site->peak_size())) == 0) { + if (amount_in_current_scale(MAX2(virtual_memory_site.reserved(), + virtual_memory_site.peak_size())) == 0) { num_omitted++; continue; } - const NativeCallStack* stack = virtual_memory_site->call_stack(); + const NativeCallStack* stack = virtual_memory_site.call_stack(); _stackprinter.print_stack(stack); INDENT_BY(29, out->print("("); - print_total(virtual_memory_site->reserved(), virtual_memory_site->committed()); - const MemTag mem_tag = virtual_memory_site->mem_tag(); + print_total(virtual_memory_site.reserved(), virtual_memory_site.committed()); + const MemTag mem_tag = virtual_memory_site.mem_tag(); if (mem_tag != mtNone) { out->print(" Tag=%s", NMTUtil::tag_to_name(mem_tag)); } @@ -835,38 +832,61 @@ void MemDetailDiffReporter::diff_malloc_sites() const { } void MemDetailDiffReporter::diff_virtual_memory_sites() const { - VirtualMemorySiteIterator early_itr = _early_baseline.virtual_memory_sites(MemBaseline::by_site); - VirtualMemorySiteIterator current_itr = _current_baseline.virtual_memory_sites(MemBaseline::by_site); + _early_baseline.sort_virtual_memory_sites(MemBaseline::by_site); + _current_baseline.sort_virtual_memory_sites(MemBaseline::by_site); + + const VirtualMemoryAllocationSite* early_site = nullptr; + const VirtualMemoryAllocationSite* current_site = nullptr; + int early_i = 0; + int current_i = 0; + auto early_next = [&]() -> const VirtualMemoryAllocationSite* { + if (early_i < _early_baseline.virtual_memory_sites_length()) { + const VirtualMemoryAllocationSite* e = &_early_baseline.virtual_memory_sites()[early_i]; + early_i++; + return e; + } else { + return nullptr; + } + }; + auto current_next = [&]() -> const VirtualMemoryAllocationSite* { + if (current_i < _current_baseline.virtual_memory_sites_length()) { + const VirtualMemoryAllocationSite* e = &_current_baseline.virtual_memory_sites()[current_i]; + current_i++; + return e; + } else { + return nullptr; + } + }; - const VirtualMemoryAllocationSite* early_site = early_itr.next(); - const VirtualMemoryAllocationSite* current_site = current_itr.next(); + early_site = early_next(); + current_site = current_next(); while (early_site != nullptr || current_site != nullptr) { if (early_site == nullptr) { new_virtual_memory_site(current_site); - current_site = current_itr.next(); + current_site = current_next(); } else if (current_site == nullptr) { old_virtual_memory_site(early_site); - early_site = early_itr.next(); + early_site = early_next(); } else { int compVal = current_site->call_stack()->compare(*early_site->call_stack()); if (compVal < 0) { new_virtual_memory_site(current_site); - current_site = current_itr.next(); + current_site = current_next(); } else if (compVal > 0) { old_virtual_memory_site(early_site); - early_site = early_itr.next(); + early_site = early_next(); } else if (early_site->mem_tag() != current_site->mem_tag()) { // This site was originally allocated with one memory tag, then released, // then re-allocated at the same site (as far as we can tell) with a different memory tag. old_virtual_memory_site(early_site); - early_site = early_itr.next(); + early_site = early_next(); new_virtual_memory_site(current_site); - current_site = current_itr.next(); + current_site = current_next(); } else { diff_virtual_memory_site(early_site, current_site); - early_site = early_itr.next(); - current_site = current_itr.next(); + early_site = early_next(); + current_site = current_next(); } } } diff --git a/src/hotspot/share/nmt/nmtHashTable.hpp b/src/hotspot/share/nmt/nmtHashTable.hpp new file mode 100644 index 000000000000..f81567305e1c --- /dev/null +++ b/src/hotspot/share/nmt/nmtHashTable.hpp @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_NMT_NMTHASHTABLE_HPP +#define SHARE_NMT_NMTHASHTABLE_HPP + +#include "cppstdlib/new.hpp" +#include "cppstdlib/type_traits.hpp" +#include "memory/allocation.hpp" +#include "utilities/bitMap.hpp" +#include "utilities/bitMap.inline.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/powerOfTwo.hpp" + +// This is an open-addressed hashtable which stores trivial key-value pairs. +// It is backed by a CHeap allocated array which it reallocates, causing underlying pointers to be invalidated. +// Membership is stored in an occupancy bitmap, so the memory overhead of this hashtable is fairly low. +// The KVElement is a container for your key and value. HashFun, and EqualsFun are function object types. +// HashFun returns an int as the hash of the KVElement, and +// Equals returns a boolean and is a comparison function of the KVElement. +// Instances are supplied via the constructor. +// Lookups, and not only insertions, may resize the array, causing all previously acquired pointers to become invalidated. +// For example, this is unsafe code: +// OAHT<...> ht; +// auto A = {a_key, ...}; +// auto B = {b_key, ...}; +// auto a_lookup = ht.put_if_absent(A); +// auto b_lookup = ht.put_if_absent(B); +// do_thing(a_lookup, b_lookup); +// Here, a_lookup may have been invalidated at the point of b_lookup. +template // Load factor until resizing +class OpenAddressedHashTable : public StackObj { + static_assert(std::is_trivially_copyable::value && + std::is_trivially_destructible::value, + "These are required for the hashtable to function correctly"); + static_assert(LoadFactorPercentage <= 100, "Load factor cannot be higher than 100% in an open addressed hashtable"); + static_assert(LoadFactorPercentage > 0, "Load factor must be at least 1%"); + +private: + // Load factor before resize is necessary + static constexpr double load_factor = LoadFactorPercentage * 0.01; + static constexpr int small_size = 4; + using OccupancyBitMap = CHeapBitMap; + + HashFun _hash; + EqualsFun _equals; + alignas(KVElement) char _small[small_size * sizeof(KVElement)]; + KVElement* small() { return reinterpret_cast(_small); }; + KVElement* _members; + int _length; + int _occupied; + OccupancyBitMap _occupied_map; + + NONCOPYABLE(OpenAddressedHashTable); + + static void clear_members(KVElement* members, int length) { + // Zap all memory. KVElement is trivially destructible, + // so this is correct. + memset(static_cast(members), 0, sizeof(KVElement) * length); + } + + static KVElement* allocate_kvelement_array(int length) { + if constexpr (alloc_failmode == AllocFailStrategy::RETURN_NULL) { + return NEW_C_HEAP_ARRAY_RETURN_NULL(KVElement, length, MT); + } + return NEW_C_HEAP_ARRAY(KVElement, length, MT); + } + + bool is_occupied(int index) const { + assert(_occupied_map.size() == (size_t)_length, "must be"); + return _occupied_map.at(index); + } + + void clear_occupied_map() { + if (_occupied_map.size() == (size_t)_length) { + _occupied_map.clear_range(0, _length); + } else { + _occupied_map.reinitialize(_length); + } + } + // We can't discern whether keys and values should be pointers, references or passed by-value. + // So we use decltype(auto) to automatically follow the implementation for us. + KVElement& insert_into(KVElement* members, + int length, + OccupancyBitMap& occupied_map, + int* occupied, + const KVElement& kv, + bool* found) const { + assert(is_power_of_2(length), "must be"); + assert(*occupied < length, "must still have room for insertion"); + int index = _hash(kv) & (length - 1); + for (int probes = 0; probes < length; probes++) { + KVElement& element = members[index]; + if (!occupied_map.at(index)) { + *found = false; + ::new (&element) KVElement(kv); + occupied_map.set_bit(index); + (*occupied)++; + return element; + } + if (_equals(element, kv)) { + *found = true; + return element; + } + // index = (index + 1) % length but for POW2 + index = (index + 1) & (length - 1); + } + ShouldNotReachHere(); + } + + bool grow_and_rehash() { + int new_length = _length * 2; + + KVElement* new_members = allocate_kvelement_array(new_length); + if (new_members == nullptr) { + if constexpr (alloc_failmode == AllocFailStrategy::EXIT_OOM) { + vm_exit_out_of_memory(new_length, OOM_MALLOC_ERROR, "Hashtable resize failed, out of memory"); + } + return false; + } + clear_members(new_members, new_length); + OccupancyBitMap new_occupied_map(MT); + new_occupied_map.initialize(new_length); + + KVElement* const old_members = _members; + const int old_length = _length; + const bool old_members_on_c_heap = old_members != small(); + + int new_occupied = 0; + if (_occupied > 0) { + assert(_occupied_map.size() == (size_t)old_length, "must be"); + for (int index = 0; index < old_length; index++) { + if (is_occupied(index)) { + bool found = false; + KVElement& result = insert_into(new_members, new_length, new_occupied_map, + &new_occupied, old_members[index], &found); + assert(!found, "must be"); + } + } + } + assert(new_occupied == _occupied, "must preserve all entries"); + + _members = new_members; + _length = new_length; + _occupied = new_occupied; + _occupied_map.move(new_occupied_map); + + if (old_members_on_c_heap) { + FREE_C_HEAP_ARRAY(old_members); + } + return true; + } + + bool has_capacity_for_insert() const { + return (_occupied + 1) / double(_length) < load_factor; + } + + public: + OpenAddressedHashTable(HashFun hash, EqualsFun equals) : + _hash(hash), _equals(equals), + _small(), _members(small()), _length(small_size), _occupied(0), + _occupied_map(small_size, MT) { + clear_members(small(), small_size); + } + + ~OpenAddressedHashTable() { + if (_members != small()) { + FREE_C_HEAP_ARRAY(_members); + } + } + + int occupied() const { + return _occupied; + } + + KVElement* put_if_absent(const KVElement& kv, bool* found) { + assert(found != nullptr, "must be"); + assert(_occupied_map.size() == (size_t)_length, "must be"); + if (!has_capacity_for_insert()) { + if (!grow_and_rehash()) { + *found = false; + return nullptr; + } + } + KVElement& result = insert_into(_members, _length, _occupied_map, &_occupied, kv, found); + return &result; + } + + template + void visit(F f) const { + if (_occupied == 0) { + return; + } + int hits = 0; + for (int index = 0; index < _length; index++) { + if (is_occupied(index)) { + const KVElement& element = _members[index]; + f(element); + hits++; + } + if (hits == _occupied) { + return; + } + } + } + + void clear() { + if (_members != small()) { + FREE_C_HEAP_ARRAY(_members); + _members = small(); + _length = small_size; + } + _occupied = 0; + clear_members(small(), small_size); + clear_occupied_map(); + } + + KVElement* detach(int* length) { + assert(length != nullptr, "must be"); + + if (_occupied == 0) { + *length = 0; + return nullptr; + } + + KVElement* resulting_array = nullptr; + int result_index = 0; + if (_members == small()) { + // Can't return the _small array, need to allocate one. + resulting_array = allocate_kvelement_array(_occupied); + if (resulting_array == nullptr) { + *length = 0; + return nullptr; + } + // Remove all empty spaces in the array, making it dense. + for (int i = 0; i < _length; i++) { + if (is_occupied(i)) { + ::new (&resulting_array[result_index]) KVElement(small()[i]); + result_index++; + } + } + } else { + resulting_array = _members; + // Remove all empty spaces in the array, making it dense. + int index = 0; + while (result_index < _occupied) { + if (is_occupied(index)) { + if (result_index != index) { + ::new (&resulting_array[result_index]) KVElement(resulting_array[index]); + } + result_index++; + } + index++; + } + } + assert(result_index == _occupied, "must be"); + *length = _occupied; + _members = small(); + _length = small_size; + clear(); + return resulting_array; + } +}; + +#endif // SHARE_NMT_NMTHASHTABLE_HPP diff --git a/src/hotspot/share/nmt/virtualMemoryTracker.hpp b/src/hotspot/share/nmt/virtualMemoryTracker.hpp index f6cb18983a35..4fcdd8c4ad56 100644 --- a/src/hotspot/share/nmt/virtualMemoryTracker.hpp +++ b/src/hotspot/share/nmt/virtualMemoryTracker.hpp @@ -93,6 +93,8 @@ class VirtualMemoryAllocationSite : public AllocationSite { VirtualMemoryAllocationSite(const NativeCallStack& stack, MemTag mem_tag) : AllocationSite(stack, mem_tag) { } + VirtualMemoryAllocationSite(const VirtualMemoryAllocationSite& other) = default; + inline void reserve_memory(size_t sz) { _c.reserve_memory(sz); } inline void commit_memory (size_t sz) { _c.commit_memory(sz); } inline size_t reserved() const { return _c.reserved(); } diff --git a/src/hotspot/share/nmt/vmatree.cpp b/src/hotspot/share/nmt/vmatree.cpp index 1fc05133d222..808a3644d70e 100644 --- a/src/hotspot/share/nmt/vmatree.cpp +++ b/src/hotspot/share/nmt/vmatree.cpp @@ -193,13 +193,17 @@ void VMATree::compute_summary_diff(const SingleDiff::delta region_size, {0,a, 0,a, -a,a }, // op == Commit {0,0, 0,0, -a,0 } // op == Uncommit }; - SingleDiff& from_rescom = diff.tag(current_tag); - SingleDiff& to_rescom = diff.tag(operation_tag); int st = state_to_index(ex); - from_rescom.reserve += reserve[op][st * 2 ]; + { + SingleDiff& from_rescom = diff.tag(current_tag); + from_rescom.reserve += reserve[op][st * 2 ]; + from_rescom.commit += commit[op][st * 2 ]; + } + { + SingleDiff& to_rescom = diff.tag(operation_tag); to_rescom.reserve += reserve[op][st * 2 + 1]; - from_rescom.commit += commit[op][st * 2 ]; to_rescom.commit += commit[op][st * 2 + 1]; + } } // update the region state between n1 and n2. Since n1 and n2 are pointers, any update of them will be visible from tree. @@ -748,85 +752,11 @@ bool VMATree::is_empty() { return _tree.size() == 0; } -VMATree::SummaryDiff::KVEntry& -VMATree::SummaryDiff::hash_insert_or_get(const KVEntry& kv, bool* found) { - DEBUG_ONLY(int counter = 0); - // If the length is large (picked as 32) - // then we apply a load-factor check and rehash if it exceeds it. - // When the length is small we're OK with a full linear search for an empty space - // to avoid a grow and rehash. - constexpr float load_factor = 0.5; - constexpr int load_factor_cutoff_length = 32; - if (_length > load_factor_cutoff_length && - (float)_occupied / _length > load_factor) { - grow_and_rehash(); - } - while (true) { - DEBUG_ONLY(counter++); - assert(counter < 8, "Infinite loop?"); - int i = hash_to_bucket(kv.mem_tag); - while (i < _length && _members[i].marker == Marker::Occupied) { - if (_members[i].mem_tag == kv.mem_tag) { - // Found previous - *found = true; - return _members[i]; - } - i++; - } - *found = false; - // We didn't find it but ran out of space, grow and rehash - // Then look at again - if (i >= _length) { - assert(_length < std::numeric_limits>::max(), ""); - grow_and_rehash(); - continue; - } - // We didn't find it, but _members[i] is empty, allocate a new one - assert(_members[i].marker == Marker::Empty, "must be"); - _members[i] = kv; - _occupied++; - return _members[i]; - } -} - -void VMATree::SummaryDiff::grow_and_rehash() { - assert(is_power_of_2(_length), "must be"); - constexpr int length_limit = std::numeric_limits>::max() + 1; - assert(is_power_of_2(length_limit), "must be"); - if (_length == length_limit) { - // If we are at MemTag's maximum size, then just continue with the current size. - return; - } - - int new_len = _length * 2; - // Save old entries (can't use ResourceMark, too early) - GrowableArrayCHeap tmp(_length); - for (int i = 0; i < _length; i++) { - tmp.push(_members[i]); - } - - // Clear previous -- if applicable - if (_members != _small) { - FREE_C_HEAP_ARRAY(_members); - } - - _members = NEW_C_HEAP_ARRAY(KVEntry, new_len, mtNMT); - // Clear new array - memset(_members, 0, sizeof(KVEntry) * new_len); - _length = new_len; - _occupied = 0; - - for (int i = 0; i < tmp.length(); i++) { - bool _found = false; - hash_insert_or_get(tmp.at(i), &_found); - } -} - VMATree::SingleDiff& VMATree::SummaryDiff::tag(MemTag tag) { - KVEntry kv{Marker::Occupied, tag, {}}; - bool _found = false; - KVEntry& inserted = hash_insert_or_get(kv, &_found); - return inserted.single_diff; + KVEntry kv{tag, {0,0}}; + bool found = false; + KVEntry* inserted = _table.put_if_absent(kv, &found); + return inserted->single_diff; } VMATree::SingleDiff& VMATree::SummaryDiff::tag(int mt_index) { @@ -836,24 +766,15 @@ VMATree::SingleDiff& VMATree::SummaryDiff::tag(int mt_index) { void VMATree::SummaryDiff::add(const SummaryDiff& other) { other.visit([&](MemTag mt, const SingleDiff& single_diff) { bool found = false; - KVEntry other_kv = {Marker::Occupied, mt, single_diff}; - KVEntry& this_kv = hash_insert_or_get(other_kv, &found); + KVEntry other_kv{mt, single_diff}; + KVEntry* this_kv = _table.put_if_absent(other_kv, &found); if (found) { - this_kv.single_diff.reserve += other_kv.single_diff.reserve; - this_kv.single_diff.commit += other_kv.single_diff.commit; + this_kv->single_diff.reserve += other_kv.single_diff.reserve; + this_kv->single_diff.commit += other_kv.single_diff.commit; } }); } void VMATree::SummaryDiff::clear() { - if (_members != _small) { - FREE_C_HEAP_ARRAY(_members); - } - memset(_small, 0, sizeof(_small)); -} - -uint32_t VMATree::SummaryDiff::hash_to_bucket(MemTag mt) { - uint32_t hash = primitive_hash((uint32_t)mt); - assert(is_power_of_2(_length), "must be"); - return hash & ((uint32_t)_length - 1); + _table.clear(); } diff --git a/src/hotspot/share/nmt/vmatree.hpp b/src/hotspot/share/nmt/vmatree.hpp index 7054249319f3..c39c9846e211 100644 --- a/src/hotspot/share/nmt/vmatree.hpp +++ b/src/hotspot/share/nmt/vmatree.hpp @@ -28,6 +28,7 @@ #include "memory/resourceArea.hpp" #include "nmt/memTag.hpp" +#include "nmt/nmtHashTable.hpp" #include "nmt/nmtNativeCallStackStorage.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" @@ -240,32 +241,23 @@ class VMATree : public CHeapObjBase { }; class SummaryDiff { - enum class Marker { Empty, Occupied }; - static_assert((int)Marker::Empty == 0, "We memset the array to 0, so this must be true"); - struct KVEntry { - Marker marker; - MemTag mem_tag; + MemTag mt; SingleDiff single_diff; + static int hash(const KVEntry& kv) { return (int)kv.mt; } + static bool equals(const KVEntry& a, const KVEntry& b) { return a.mt == b.mt; } + KVEntry(const KVEntry&) = default; + KVEntry() = default; + KVEntry(MemTag mt, SingleDiff sd) : mt(mt), single_diff(sd) {} }; - static constexpr const int _init_size = 4; - KVEntry _small[_init_size]; - KVEntry* _members; - int _length; - int _occupied; - KVEntry& hash_insert_or_get(const KVEntry& kv, bool* found); - void grow_and_rehash(); - uint32_t hash_to_bucket(MemTag mt); - + using Table = OpenAddressedHashTable; + Table _table; public: - SummaryDiff() : _small(), _members(_small), _length(_init_size), _occupied(0) { - clear(); - } - ~SummaryDiff() { - if (_members != _small) { - FREE_C_HEAP_ARRAY(_members); - } + SummaryDiff() : _table(&KVEntry::hash, &KVEntry::equals) { } SingleDiff& tag(MemTag tag); @@ -273,18 +265,9 @@ class VMATree : public CHeapObjBase { template void visit(F f) const { - int hits = 0; - for (int i = 0; i < _length; i++) { - const KVEntry& kv = _members[i]; - if (kv.marker == Marker::Occupied) { - f(kv.mem_tag, kv.single_diff); - hits++; - } - if (hits == _occupied) { - // Early exit - return; - } - } + _table.visit([&](const KVEntry& entry) { + f(entry.mt, entry.single_diff); + }); } void add(const SummaryDiff& other); diff --git a/src/hotspot/share/oops/access.hpp b/src/hotspot/share/oops/access.hpp index c16824ec6b31..2ab0ed556f53 100644 --- a/src/hotspot/share/oops/access.hpp +++ b/src/hotspot/share/oops/access.hpp @@ -219,7 +219,7 @@ class Access: public AllStatic { AccessInternal::clone(src, dst, size); } - // inline type heap access (when flat)... + // value type heap access (when flat)... // Copy value type data from src to dst static inline void value_copy(const ValuePayload& src, const ValuePayload& dst) { diff --git a/src/hotspot/share/oops/accessBackend.hpp b/src/hotspot/share/oops/accessBackend.hpp index a32cf48948f5..531530c13bae 100644 --- a/src/hotspot/share/oops/accessBackend.hpp +++ b/src/hotspot/share/oops/accessBackend.hpp @@ -30,8 +30,8 @@ #include "memory/allocation.hpp" #include "metaprogramming/enableIf.hpp" #include "oops/accessDecorators.hpp" -#include "oops/inlineKlass.hpp" #include "oops/oopsHierarchy.hpp" +#include "oops/valueKlass.hpp" #include "runtime/globals.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" diff --git a/src/hotspot/share/oops/accessBackend.inline.hpp b/src/hotspot/share/oops/accessBackend.inline.hpp index ad74d0052385..ab99247223df 100644 --- a/src/hotspot/share/oops/accessBackend.inline.hpp +++ b/src/hotspot/share/oops/accessBackend.inline.hpp @@ -31,9 +31,9 @@ #include "oops/access.hpp" #include "oops/arrayOop.hpp" #include "oops/compressedOops.inline.hpp" -#include "oops/inlineKlass.hpp" #include "oops/layoutKind.hpp" #include "oops/oopsHierarchy.hpp" +#include "oops/valueKlass.hpp" #include "oops/valuePayload.inline.hpp" #include "runtime/atomicAccess.hpp" #include "runtime/orderAccess.hpp" @@ -336,7 +336,7 @@ template inline void RawAccessBarrier::value_copy(const ValuePayload& src, const ValuePayload& dst) { precond(src.klass() == dst.klass()); - const InlineKlass* klass = src.klass(); + const ValueKlass* klass = src.klass(); const LayoutKind copy_layout = LayoutKindHelper::get_copy_layout( src.layout_kind(), dst.layout_kind()); const int size = klass->layout_size_in_bytes(copy_layout); @@ -349,7 +349,7 @@ template inline void RawAccessBarrier::value_store_null(const ValuePayload& dst) { address dst_addr = dst.addr(); const LayoutKind lk = dst.layout_kind(); - const InlineKlass* klass = dst.klass(); + const ValueKlass* klass = dst.klass(); const int size = klass->layout_size_in_bytes(lk); AccessInternal::value_store_null(dst_addr, static_cast(size)); diff --git a/src/hotspot/share/oops/fieldInfo.hpp b/src/hotspot/share/oops/fieldInfo.hpp index 7227e104e9c1..ba7052003d86 100644 --- a/src/hotspot/share/oops/fieldInfo.hpp +++ b/src/hotspot/share/oops/fieldInfo.hpp @@ -73,7 +73,7 @@ class FieldInfo { // flags should come earlier than less frequent ones, because // earlier ones compress better. enum FieldFlagBitPosition { - _ff_null_free_inline_type, // field's type is an inline type and the field is null free + _ff_null_free_value_type, // field's type is a value type and the field is null free _ff_flat, // field is a flat field, optional section includes a layout kind _ff_null_marker, // field has a null marker, optional section includes the null marker offset _ff_initialized, // has ConstantValue initializer attribute @@ -113,7 +113,7 @@ class FieldInfo { } bool is_initialized() const { return test_flag(_ff_initialized); } - bool is_null_free_inline_type() const { return test_flag(_ff_null_free_inline_type); } + bool is_null_free_value_type() const { return test_flag(_ff_null_free_value_type); } bool is_flat() const { return test_flag(_ff_flat); } bool is_injected() const { return test_flag(_ff_injected); } bool is_generic() const { return test_flag(_ff_generic); } @@ -122,7 +122,7 @@ class FieldInfo { bool has_null_marker() const { return test_flag(_ff_null_marker); } void update_initialized(bool z) { update_flag(_ff_initialized, z); } - void update_null_free_inline_type(bool z) { update_flag(_ff_null_free_inline_type, z); } + void update_null_free_value_type(bool z) { update_flag(_ff_null_free_value_type, z); } void update_flat(bool z) { update_flag(_ff_flat, z); } void update_injected(bool z) { update_flag(_ff_injected, z); } void update_generic(bool z) { update_flag(_ff_generic, z); } diff --git a/src/hotspot/share/oops/fieldStreams.hpp b/src/hotspot/share/oops/fieldStreams.hpp index fefcdfbae3ef..bb01b8125705 100644 --- a/src/hotspot/share/oops/fieldStreams.hpp +++ b/src/hotspot/share/oops/fieldStreams.hpp @@ -118,8 +118,8 @@ class FieldStreamBase : public StackObj { return field()->offset(); } - bool is_null_free_inline_type() { - return field()->field_flags().is_null_free_inline_type(); + bool is_null_free_value_type() { + return field()->field_flags().is_null_free_value_type(); } bool is_flat() const { @@ -271,8 +271,8 @@ class HierarchicalFieldStreamBase : public StackObj { return current_stream().is_flat(); } - bool is_null_free_inline_type() { - return current_stream().is_null_free_inline_type(); + bool is_null_free_value_type() { + return current_stream().is_null_free_value_type(); } int null_marker_offset() { diff --git a/src/hotspot/share/oops/flatArrayKlass.cpp b/src/hotspot/share/oops/flatArrayKlass.cpp index c8b2e4a3228e..0c5f5f320980 100644 --- a/src/hotspot/share/oops/flatArrayKlass.cpp +++ b/src/hotspot/share/oops/flatArrayKlass.cpp @@ -40,7 +40,6 @@ #include "oops/flatArrayKlass.hpp" #include "oops/flatArrayOop.hpp" #include "oops/flatArrayOop.inline.hpp" -#include "oops/inlineKlass.hpp" #include "oops/instanceKlass.hpp" #include "oops/klass.inline.hpp" #include "oops/layoutKind.hpp" @@ -48,6 +47,7 @@ #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/oopCast.inline.hpp" +#include "oops/valueKlass.hpp" #include "oops/valuePayload.inline.hpp" #include "oops/verifyOopClosure.hpp" #include "runtime/arguments.hpp" @@ -61,13 +61,13 @@ FlatArrayKlass::FlatArrayKlass(Klass* element_klass, Symbol* name, ArrayProperties props, LayoutKind lk) : ObjArrayKlass(1, element_klass, name, Kind, props), _layout_kind(lk) { - assert(element_klass->is_inline_klass(), "Expected Inline"); + assert(element_klass->is_value_klass(), "Expected Inline"); assert(lk != LayoutKind::NULLABLE_NON_ATOMIC_FLAT, "Layout not supported by arrays yet (needs frozen arrays)"); assert(LayoutKindHelper::is_flat(lk), "Must be a flat layout"); assert(_class_loader_data == element_klass->class_loader_data(), "Sanity check"); - set_layout_helper(array_layout_helper(InlineKlass::cast(element_klass), lk)); + set_layout_helper(array_layout_helper(ValueKlass::cast(element_klass), lk)); assert(is_array_klass(), "sanity"); assert(is_flatArray_klass(), "sanity"); @@ -106,7 +106,7 @@ FlatArrayKlass* FlatArrayKlass::allocate_klass(Klass* eklass, ArrayProperties pr assert(props.is_null_restricted() || !props.is_non_atomic(), "Nullable non-atomic arrays are unsupported"); - InlineKlass* element_klass = InlineKlass::cast(eklass); + ValueKlass* element_klass = ValueKlass::cast(eklass); // If the array is non-atomic, then the element should be one of the following: // a) naturally atomic, so atomicity relaxation has no impact; or // b) explicitly marked as allowing non-atomicity. @@ -159,7 +159,7 @@ oop FlatArrayKlass::multi_allocate(int rank, jint* last_size, TRAPS) { ShouldNotReachHere(); } -jint FlatArrayKlass::array_layout_helper(InlineKlass* vk, LayoutKind lk) { +jint FlatArrayKlass::array_layout_helper(ValueKlass* vk, LayoutKind lk) { BasicType etype = T_FLAT_ELEMENT; int esize = log2i_exact(round_up_power_of_2(vk->layout_size_in_bytes(lk))); int hsize = arrayOopDesc::base_offset_in_bytes(etype); @@ -279,8 +279,8 @@ void FlatArrayKlass::copy_array(arrayOop s, int src_pos, FlatArrayPayload::Handle src_payload_handle = src_payload.make_handle(THREAD); FlatArrayPayload::Handle dst_payload_handle = dst_payload.make_handle(THREAD); - InlineKlass* vk = InlineKlass::cast(s_elem_klass); - inlineOop buffer = vk->allocate_instance(CHECK); + ValueKlass* vk = ValueKlass::cast(s_elem_klass); + valueOop buffer = vk->allocate_instance(CHECK); BufferedValuePayload buf_payload(buffer); // Reload the oops from the payload handles. @@ -424,7 +424,7 @@ void FlatArrayKlass::oop_print_value_on(oop obj, outputStream* st) { } void FlatArrayKlass::oop_print_elements_on(flatArrayOop fa, outputStream* st) { - InlineKlass* vk = element_klass(); + ValueKlass* vk = element_klass(); int print_len = MIN2(fa->length(), MaxElementPrintSize); for(int index = 0; index < print_len; index++) { int off = (address) fa->value_at_addr(index, layout_helper()) - cast_from_oop
(fa); @@ -460,5 +460,5 @@ void FlatArrayKlass::oop_verify_on(oop obj, outputStream* st) { void FlatArrayKlass::verify_on(outputStream* st) { ArrayKlass::verify_on(st); - guarantee(element_klass()->is_inline_klass(), "should be inline type klass"); + guarantee(element_klass()->is_value_klass(), "should be value type klass"); } diff --git a/src/hotspot/share/oops/flatArrayKlass.hpp b/src/hotspot/share/oops/flatArrayKlass.hpp index c2fa4c56f115..d3191a9c55cc 100644 --- a/src/hotspot/share/oops/flatArrayKlass.hpp +++ b/src/hotspot/share/oops/flatArrayKlass.hpp @@ -27,12 +27,12 @@ #include "classfile/classLoaderData.hpp" #include "oops/arrayKlass.hpp" -#include "oops/inlineKlass.hpp" #include "oops/objArrayKlass.hpp" +#include "oops/valueKlass.hpp" #include "utilities/macros.hpp" /** - * Array of inline types, gives a layout of typeArrayOop, but needs oops iterators + * Array of value types, gives a layout of typeArrayOop, but needs oops iterators */ class FlatArrayKlass : public ObjArrayKlass { friend class Deoptimization; @@ -52,7 +52,7 @@ class FlatArrayKlass : public ObjArrayKlass { FlatArrayKlass() {} // used by CppVtableCloner::initialize() - InlineKlass* element_klass() const { return InlineKlass::cast(ObjArrayKlass::element_klass()); } + ValueKlass* element_klass() const { return ValueKlass::cast(ObjArrayKlass::element_klass()); } LayoutKind layout_kind() const { return _layout_kind; } static ByteSize layout_kind_offset() { return in_ByteSize(offset_of(FlatArrayKlass, _layout_kind)); } @@ -87,7 +87,7 @@ class FlatArrayKlass : public ObjArrayKlass { void metaspace_pointers_do(MetaspaceClosure* iter) override; - static jint array_layout_helper(InlineKlass* vklass, LayoutKind lk); // layout helper for values + static jint array_layout_helper(ValueKlass* vklass, LayoutKind lk); // layout helper for values // sizing static int header_size() { return sizeof(FlatArrayKlass) / wordSize; } diff --git a/src/hotspot/share/oops/flatArrayKlass.inline.hpp b/src/hotspot/share/oops/flatArrayKlass.inline.hpp index 11eaa6c78809..674192e4bc9a 100644 --- a/src/hotspot/share/oops/flatArrayKlass.inline.hpp +++ b/src/hotspot/share/oops/flatArrayKlass.inline.hpp @@ -31,10 +31,9 @@ #include "oops/arrayKlass.hpp" #include "oops/flatArrayOop.hpp" #include "oops/flatArrayOop.inline.hpp" -#include "oops/inlineKlass.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/klass.hpp" #include "oops/oop.inline.hpp" +#include "oops/valueKlass.inline.hpp" #include "utilities/devirtualizer.inline.hpp" #include "utilities/macros.hpp" diff --git a/src/hotspot/share/oops/flatArrayOop.hpp b/src/hotspot/share/oops/flatArrayOop.hpp index 063ecbbafe3a..01d1274ba740 100644 --- a/src/hotspot/share/oops/flatArrayOop.hpp +++ b/src/hotspot/share/oops/flatArrayOop.hpp @@ -31,7 +31,7 @@ class FlatArrayKlass; -// A flatArrayOop points to a flat array containing inline types (no indirection). +// A flatArrayOop points to a flat array containing value types (no indirection). // It may include embedded oops in its elements. class flatArrayOopDesc : public objArrayOopDesc { diff --git a/src/hotspot/share/oops/flatArrayOop.inline.hpp b/src/hotspot/share/oops/flatArrayOop.inline.hpp index fefe98461dcf..3006efd1bf2b 100644 --- a/src/hotspot/share/oops/flatArrayOop.inline.hpp +++ b/src/hotspot/share/oops/flatArrayOop.inline.hpp @@ -30,8 +30,8 @@ #include "classfile/vmSymbols.hpp" #include "oops/access.inline.hpp" #include "oops/flatArrayKlass.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/oop.inline.hpp" +#include "oops/valueKlass.inline.hpp" #include "oops/valuePayload.inline.hpp" #include "runtime/globals.hpp" @@ -90,7 +90,7 @@ inline jboolean flatArrayOopDesc::null_marker_of_obj_at(int index) const { inline jboolean flatArrayOopDesc::null_marker_of_obj_at(int index, TRAPS) const { assert(is_within_bounds(index), "index %d out of bounds %d", index, length()); FlatArrayKlass* fak = klass(); - InlineKlass* vk = fak->element_klass(); + ValueKlass* vk = fak->element_klass(); char* this_oop = (char*) (oopDesc*) this; char* val = (char*) value_at_addr(index, fak->layout_helper()); ptrdiff_t offset = val - this_oop + (ptrdiff_t)vk->null_marker_offset_in_payload(); @@ -105,7 +105,7 @@ inline void flatArrayOopDesc::obj_at_put(int index, oop value) { inline void flatArrayOopDesc::obj_at_put(int index, oop value, TRAPS) { assert(is_within_bounds(index), "index %d out of bounds %d", index, length()); FlatArrayKlass* fak = klass(); - InlineKlass* vk = fak->element_klass(); + ValueKlass* vk = fak->element_klass(); if (value != nullptr) { if (value->klass() != vk) { THROW(vmSymbols::java_lang_ArrayStoreException()); @@ -116,7 +116,7 @@ inline void flatArrayOopDesc::obj_at_put(int index, oop value, TRAPS) { FlatArrayPayload payload(flatArrayOop(this), index, fak); // The value and klass has already been checked for null compatibility. - payload.write_without_nullability_check(inlineOop(value)); + payload.write_without_nullability_check(valueOop(value)); } template diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index e4bff1dbf70c..9e9df4b82ac6 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -65,7 +65,6 @@ #include "memory/universe.hpp" #include "oops/constantPool.hpp" #include "oops/fieldStreams.inline.hpp" -#include "oops/inlineKlass.hpp" #include "oops/instanceClassLoaderKlass.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/instanceMirrorKlass.hpp" @@ -79,6 +78,7 @@ #include "oops/recordComponent.hpp" #include "oops/refArrayKlass.hpp" #include "oops/symbol.hpp" +#include "oops/valueKlass.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiRedefineClasses.hpp" #include "prims/jvmtiThreadState.hpp" @@ -156,16 +156,16 @@ #endif // ndef DTRACE_ENABLED -void InlineLayoutInfo::metaspace_pointers_do(MetaspaceClosure* it) { - log_trace(cds)("Iter(InlineFieldInfo): %p", this); +void ValueFieldLayoutInfo::metaspace_pointers_do(MetaspaceClosure* it) { + log_trace(cds)("Iter(ValueFieldLayoutInfo): %p", this); it->push(&_klass); } -void InlineLayoutInfo::print() const { +void ValueFieldLayoutInfo::print() const { print_on(tty); } -void InlineLayoutInfo::print_on(outputStream* st) const { +void ValueFieldLayoutInfo::print_on(outputStream* st) const { st->print_cr("_klass: " PTR_FORMAT, p2i(_klass)); if (_klass != nullptr) { StreamIndentor si(st); @@ -197,7 +197,7 @@ bool InstanceKlass::is_naturally_atomic(bool null_free) const { return _misc_flags.is_naturally_atomic(); } else { // Requires a null-marker, can't have any other fields - return InlineKlass::cast(this)->is_empty_inline_type(); + return ValueKlass::cast(this)->is_empty_value_type(); } } @@ -223,8 +223,8 @@ static inline bool is_class_loader(const Symbol* class_name, return false; } -bool InstanceKlass::field_is_null_free_inline_type(int index) const { - return field(index).field_flags().is_null_free_inline_type(); +bool InstanceKlass::field_is_null_free_value_type(int index) const { + return field(index).field_flags().is_null_free_value_type(); } bool InstanceKlass::is_class_in_loadable_descriptors_attribute(Symbol* name) const { @@ -524,7 +524,7 @@ InstanceKlass* InstanceKlass::allocate_instance_klass(const ClassFileParser& par parser.itable_size(), nonstatic_oop_map_size(parser.total_oop_map_count()), parser.is_interface(), - parser.is_inline_type()); + parser.is_concrete_value_class()); const Symbol* const class_name = parser.class_name(); assert(class_name != nullptr, "invariant"); @@ -546,9 +546,9 @@ InstanceKlass* InstanceKlass::allocate_instance_klass(const ClassFileParser& par } else if (is_class_loader(class_name, parser)) { // class loader - java.lang.ClassLoader ik = new (loader_data, size, THREAD) InstanceClassLoaderKlass(parser); - } else if (parser.is_inline_type()) { - // inline type - ik = new (loader_data, size, THREAD) InlineKlass(parser); + } else if (parser.is_concrete_value_class()) { + // value type + ik = new (loader_data, size, THREAD) ValueKlass(parser); } else { // normal ik = new (loader_data, size, THREAD) InstanceKlass(parser); @@ -606,10 +606,10 @@ InstanceKlass::InstanceKlass(const ClassFileParser& parser, KlassKind kind, mark _reference_type(reference_type), _acmp_maps_offset(0), _init_thread(nullptr), - _inline_layout_info_array(nullptr), + _value_field_layout_info_array(nullptr), _loadable_descriptors(nullptr), _acmp_maps_array(nullptr), - _adr_inline_klass_members(nullptr) + _adr_value_klass_members(nullptr) { set_vtable_length(parser.vtable_size()); set_access_flags(parser.access_flags()); @@ -774,10 +774,10 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { } set_fields_status(nullptr); - if (inline_layout_info_array() != nullptr) { - MetadataFactory::free_array(loader_data, inline_layout_info_array()); + if (value_field_layout_info_array() != nullptr) { + MetadataFactory::free_array(loader_data, value_field_layout_info_array()); } - set_inline_layout_info_array(nullptr); + set_value_field_layout_info_array(nullptr); // If a method from a redefined class is using this constant pool, don't // delete it, yet. The new class's previous version will point to this. @@ -873,13 +873,13 @@ int InstanceKlass::size(int vtable_length, int itable_length, int nonstatic_oop_map_size, bool is_interface, - bool is_inline_type) { + bool is_concrete_value_class) { return align_metadata_size(header_size() + vtable_length + itable_length + nonstatic_oop_map_size + (is_interface ? (int)sizeof(Klass*) / wordSize : 0) + - (is_inline_type ? (int)sizeof(InlineKlass::Members) / wordSize : 0)); + (is_concrete_value_class ? (int)sizeof(ValueKlass::Members) / wordSize : 0)); } int InstanceKlass::size() const { @@ -887,7 +887,7 @@ int InstanceKlass::size() const { itable_length(), nonstatic_oop_map_size(), is_interface(), - is_inline_klass()); + is_value_klass()); } klassItable InstanceKlass::itable() const { @@ -1100,7 +1100,7 @@ static void load_classes_from_loadable_descriptors_attribute(InstanceKlass *ik, log_info(class, preload)("Preloading of class %s during linking of class %s " "(cause: LoadableDescriptors attribute) succeeded", class_name->as_C_string(), ik->name()->as_C_string()); - if (!klass->is_inline_klass()) { + if (!klass->is_value_klass()) { // Non value classes are allowed by the current spec, but it could be an indication // of an issue so let's log a warning log_info(class, preload)("Preloading of class %s during linking of class %s " @@ -1188,7 +1188,7 @@ bool InstanceKlass::link_class_impl(TRAPS) { if (Arguments::is_valhalla_enabled()) { // Aggressively preloading all classes from the LoadableDescriptors attribute - // so inline classes can be scalarized in the calling conventions computed below + // so value classes can be scalarized in the calling conventions computed below load_classes_from_loadable_descriptors_attribute(this, THREAD); assert(!HAS_PENDING_EXCEPTION, "Shouldn't have pending exceptions from call above"); } @@ -1523,8 +1523,8 @@ void InstanceKlass::initialize_impl(TRAPS) { NoPreemptMark npm(THREAD); // Pre-allocating an all-zero value to be used to reset nullable flat storages - if (is_inline_klass()) { - InlineKlass* vk = InlineKlass::cast(this); + if (is_value_klass()) { + ValueKlass* vk = ValueKlass::cast(this); if (vk->supports_nullable_layouts()) { oop val = vk->allocate_instance(THREAD); if (HAS_PENDING_EXCEPTION) { @@ -1747,6 +1747,15 @@ const char* InstanceKlass::format_strict_static_message(Symbol* field_name, cons return ss.as_string(); } +bool InstanceKlass::has_strict_instance_fields_in_hierarchy() const { + for (const InstanceKlass* ik = this; ik != nullptr; ik = ik->java_super()) { + if (ik->has_strict_instance_fields()) { + return true; + } + } + return false; +} + // Update hierarchy. This is done before the new klass has been added to the SystemDictionary. The Compile_lock // is grabbed, to ensure that the compiler is not using the class hierarchy. void InstanceKlass::add_to_hierarchy(JavaThread* current) { @@ -2226,8 +2235,8 @@ Klass* InstanceKlass::find_field(Symbol* name, Symbol* sig, bool is_static, fiel } bool InstanceKlass::contains_field_offset(int offset) { - if (this->is_inline_klass()) { - InlineKlass* vk = InlineKlass::cast(this); + if (this->is_value_klass()) { + ValueKlass* vk = ValueKlass::cast(this); return offset >= vk->payload_offset() && offset < (vk->payload_offset() + vk->payload_size_in_bytes()); } else { fieldDescriptor fd; @@ -2268,7 +2277,7 @@ bool InstanceKlass::find_local_flat_field_containing_offset(int offset, fieldDes } const int offset_in_flat_field = offset - fs.offset(); - const InlineLayoutInfo layout_info = inline_layout_info(fs.index()); + const ValueFieldLayoutInfo layout_info = value_field_layout_info(fs.index()); const int field_size = layout_info.klass()->layout_size_in_bytes(layout_info.kind()); assert(LayoutKindHelper::is_flat(layout_info.kind()), "Must be flat"); @@ -3074,7 +3083,7 @@ void InstanceKlass::metaspace_pointers_do(MetaspaceClosure* it) { it->push(&_loadable_descriptors); it->push(&_acmp_maps_array, MetaspaceClosure::_writable); it->push(&_record_components); - it->push(&_inline_layout_info_array, MetaspaceClosure::_writable); + it->push(&_value_field_layout_info_array, MetaspaceClosure::_writable); if (CDSConfig::is_dumping_full_module_graph() && !defined_by_other_loaders()) { it->push(&_package_entry); @@ -3202,8 +3211,8 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl set_package(loader_data, pkg_entry, CHECK); Klass::restore_unshareable_info(loader_data, protection_domain, CHECK); - if (is_inline_klass()) { - InlineKlass::cast(this)->initialize_calling_convention(CHECK); + if (is_value_klass()) { + ValueKlass::cast(this)->initialize_calling_convention(CHECK); } Array* methods = this->methods(); @@ -3443,7 +3452,7 @@ void InstanceKlass::set_minor_version(u2 minor_version) { _constants->set_minor_ u2 InstanceKlass::major_version() const { return _constants->major_version(); } void InstanceKlass::set_major_version(u2 major_version) { _constants->set_major_version(major_version); } -bool InstanceKlass::supports_inline_types() const { +bool InstanceKlass::supports_value_types() const { return major_version() >= Verifier::VALUE_TYPES_MAJOR_VERSION && minor_version() == Verifier::JAVA_PREVIEW_MINOR_VERSION; } diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 768da36dc4be..3d567f072b8a 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -60,7 +60,7 @@ class RecordComponent; // The embedded nonstatic oop-map blocks are short pairs (offset, length) // indicating where oops are located in instances of this klass. // [EMBEDDED implementor of the interface] only exists for interface -// [EMBEDDED InlineKlass::Members] only if is an InlineKlass instance +// [EMBEDDED ValueKlass::Members] only if is an ValueKlass instance // forward declaration for class -- see below for definition @@ -141,16 +141,16 @@ class OopMapBlock { struct JvmtiCachedClassFileData; -class InlineLayoutInfo : public MetaspaceObj { - InlineKlass* _klass; +class ValueFieldLayoutInfo : public MetaspaceObj { + ValueKlass* _klass; LayoutKind _kind; int _null_marker_offset; // null marker offset for this field, relative to the beginning of the current container public: - InlineLayoutInfo(): _klass(nullptr), _kind(LayoutKind::UNKNOWN), _null_marker_offset(-1) {} + ValueFieldLayoutInfo(): _klass(nullptr), _kind(LayoutKind::UNKNOWN), _null_marker_offset(-1) {} - InlineKlass* klass() const { return _klass; } - void set_klass(InlineKlass* k) { _klass = k; } + ValueKlass* klass() const { return _klass; } + void set_klass(ValueKlass* k) { _klass = k; } LayoutKind kind() const { assert(_kind != LayoutKind::UNKNOWN, "Not set"); @@ -165,10 +165,10 @@ class InlineLayoutInfo : public MetaspaceObj { void set_null_marker_offset(int o) { _null_marker_offset = o; } void metaspace_pointers_do(MetaspaceClosure* it); - MetaspaceObj::Type type() const { return InlineLayoutInfoType; } + MetaspaceObj::Type type() const { return ValueFieldLayoutInfoType; } - static ByteSize klass_offset() { return byte_offset_of(InlineLayoutInfo, _klass); } - static ByteSize null_marker_offset_offset() { return byte_offset_of(InlineLayoutInfo, _null_marker_offset); } + static ByteSize klass_offset() { return byte_offset_of(ValueFieldLayoutInfo, _klass); } + static ByteSize null_marker_offset_offset() { return byte_offset_of(ValueFieldLayoutInfo, _null_marker_offset); } // Print void print() const; @@ -276,7 +276,7 @@ class InstanceKlass: public Klass { u1 _reference_type; // reference type int _acmp_maps_offset; // offset to injected static field storing .acmp_maps for value classes // unfortunately, abstract values need one too so it cannot be stored in - // the InlineKlass::Members that only exist for InlineKlass. + // the ValueKlass::Members that only exist for ValueKlass. AccessFlags _access_flags; // Access flags. The class/interface distinction is stored here. @@ -326,15 +326,15 @@ class InstanceKlass: public Klass { Array* _fieldinfo_search_table; Array* _fields_status; - Array* _inline_layout_info_array; + Array* _value_field_layout_info_array; Array* _loadable_descriptors; Array* _acmp_maps_array; // Metadata copy of the acmp_maps oop used in value classes. - // When loading an inline klass from the CDS/AOT archive + // When loading a value klass from the CDS/AOT archive // this copy can be used to regenerate the ".acmp_maps" oop // if it is not stored in the archive. // Located here because sub-klasses can't have their own C++ fields - address _adr_inline_klass_members; + address _adr_value_klass_members; friend class SystemDictionary; @@ -395,7 +395,7 @@ class InstanceKlass: public Klass { // Query if this class has atomicity requirements (default is yes) // This bit can occur anywhere, but is only significant - // for inline classes *and* their super types. + // for value classes *and* their super types. // It inherits from supers. // Its value depends on the ForceNonTearable VM option, the LooselyConsistentValue annotation // and the presence of flat fields with atomicity requirements @@ -474,10 +474,10 @@ class InstanceKlass: public Klass { inline Symbol* field_signature (int index) const; bool field_is_flat(int index) const { return field_flags(index).is_flat(); } bool field_has_null_marker(int index) const { return field_flags(index).has_null_marker(); } - bool field_is_null_free_inline_type(int index) const; + bool field_is_null_free_value_type(int index) const; bool is_class_in_loadable_descriptors_attribute(Symbol* name) const; - int field_null_marker_offset(int index) const { return inline_layout_info(index).null_marker_offset(); } + int field_null_marker_offset(int index) const { return value_field_layout_info(index).null_marker_offset(); } // Number of Java declared fields int java_fields_count() const; @@ -779,7 +779,7 @@ class InstanceKlass: public Klass { u2 major_version() const; void set_major_version(u2 major_version); - bool supports_inline_types() const; + bool supports_value_types() const; // source debug extension const char* source_debug_extension() const { return _source_debug_extension; } @@ -894,6 +894,11 @@ class InstanceKlass: public Klass { const char* format_strict_static_message(Symbol* field_name, const char* doing_what = nullptr); void throw_strict_static_exception(Symbol* field_name, const char* when, TRAPS); + // strict instance fields + bool has_strict_instance_fields() const { return _misc_flags.has_strict_instance_fields(); } + void set_has_strict_instance_fields(bool b) { _misc_flags.set_has_strict_instance_fields(b); } + bool has_strict_instance_fields_in_hierarchy() const; + // generics support Symbol* generic_signature() const; u2 generic_signature_index() const; @@ -987,8 +992,8 @@ class InstanceKlass: public Klass { JFR_ONLY(DEFINE_KLASS_TRACE_ID_OFFSET;) static ByteSize init_thread_offset() { return byte_offset_of(InstanceKlass, _init_thread); } - static ByteSize inline_layout_info_array_offset() { return byte_offset_of(InstanceKlass, _inline_layout_info_array); } - static ByteSize adr_inline_klass_members_offset() { return byte_offset_of(InstanceKlass, _adr_inline_klass_members); } + static ByteSize value_field_layout_info_array_offset() { return byte_offset_of(InstanceKlass, _value_field_layout_info_array); } + static ByteSize adr_value_klass_members_offset() { return byte_offset_of(InstanceKlass, _adr_value_klass_members); } // subclass/subinterface checks bool implements_interface(Klass* k) const; @@ -1062,7 +1067,7 @@ class InstanceKlass: public Klass { int itable_length, int nonstatic_oop_map_size, bool is_interface, - bool is_inline_type); + bool is_concrete_value_class); int size() const override; @@ -1080,21 +1085,21 @@ class InstanceKlass: public Klass { // Sub-klasses can place their fields after this address. inline address end_of_instance_klass() const; - void set_inline_layout_info_array(Array* array) { _inline_layout_info_array = array; } - Array* inline_layout_info_array() const { return _inline_layout_info_array; } + void set_value_field_layout_info_array(Array* array) { _value_field_layout_info_array = array; } + Array* value_field_layout_info_array() const { return _value_field_layout_info_array; } - InlineLayoutInfo inline_layout_info(int index) const { - assert(_inline_layout_info_array != nullptr, "Array not created"); - return _inline_layout_info_array->at(index); + ValueFieldLayoutInfo value_field_layout_info(int index) const { + assert(_value_field_layout_info_array != nullptr, "Array not created"); + return _value_field_layout_info_array->at(index); } - InlineLayoutInfo* inline_layout_info_adr(int index) { - assert(_inline_layout_info_array != nullptr, "Array not created"); - return _inline_layout_info_array->adr_at(index); + ValueFieldLayoutInfo* value_field_layout_info_adr(int index) { + assert(_value_field_layout_info_array != nullptr, "Array not created"); + return _value_field_layout_info_array->adr_at(index); } - inline InlineKlass* get_inline_type_field_klass(int idx) const ; - inline InlineKlass* get_inline_type_field_klass_or_null(int idx) const; + inline ValueKlass* get_value_type_field_klass(int idx) const ; + inline ValueKlass* get_value_type_field_klass_or_null(int idx) const; // Use this to return the size of an instance in heap words: int size_helper() const { diff --git a/src/hotspot/share/oops/instanceKlass.inline.hpp b/src/hotspot/share/oops/instanceKlass.inline.hpp index c0e658887e2f..7d9f789f0f5d 100644 --- a/src/hotspot/share/oops/instanceKlass.inline.hpp +++ b/src/hotspot/share/oops/instanceKlass.inline.hpp @@ -68,18 +68,18 @@ inline address InstanceKlass::end_of_instance_klass() const { (is_interface() ? sizeof(InstanceKlass*) : 0); } -inline InlineKlass* InstanceKlass::get_inline_type_field_klass(int idx) const { +inline ValueKlass* InstanceKlass::get_value_type_field_klass(int idx) const { assert(has_inlined_fields() || has_null_restricted_static_fields(), "Sanity checking"); assert(idx < java_fields_count(), "IOOB"); - InlineKlass* k = inline_layout_info(idx).klass(); + ValueKlass* k = value_field_layout_info(idx).klass(); assert(k != nullptr, "Should always be set before being read"); return k; } -inline InlineKlass* InstanceKlass::get_inline_type_field_klass_or_null(int idx) const { +inline ValueKlass* InstanceKlass::get_value_type_field_klass_or_null(int idx) const { assert(has_inlined_fields() || has_null_restricted_static_fields(), "Sanity checking"); assert(idx < java_fields_count(), "IOOB"); - InlineKlass* k = inline_layout_info(idx).klass(); + ValueKlass* k = value_field_layout_info(idx).klass(); return k; } diff --git a/src/hotspot/share/oops/instanceKlassFlags.hpp b/src/hotspot/share/oops/instanceKlassFlags.hpp index 05c453c63041..f5054d8ae3b1 100644 --- a/src/hotspot/share/oops/instanceKlassFlags.hpp +++ b/src/hotspot/share/oops/instanceKlassFlags.hpp @@ -54,7 +54,7 @@ class InstanceKlassFlags { flag(has_miranda_methods , 1 << 12) /* True if this class has miranda methods in it's vtable */ \ flag(has_final_method , 1 << 13) /* True if klass has final method */ \ flag(has_inlined_fields , 1 << 14) /* has inlined fields and related embedded section is not empty */ \ - flag(is_empty_inline_type , 1 << 15) /* empty inline type (*) */ \ + flag(is_empty_value_type , 1 << 15) /* empty value type (*) */ \ flag(is_naturally_atomic , 1 << 16) /* loaded/stored in one instruction*/ \ flag(must_be_atomic , 1 << 17) /* doesn't allow tearing */ \ flag(has_loosely_consistent_annotation , 1 << 18) /* the class has the LooselyConsistentValue annotation WARNING: it doesn't automatically mean that the class allows tearing */ \ @@ -62,11 +62,12 @@ class InstanceKlassFlags { flag(trust_final_fields , 1 << 20) /* All instance final fields in this class should be trusted */ \ flag(has_null_restricted_static_fields , 1 << 21) /* True if static null restricted fields declared */ \ flag(fail_over_verified , 1 << 22) /* class failed split verification but passed inference verification */ \ + flag(has_strict_instance_fields , 1 << 23) /* True if strict instance fields declared */ \ /* end of list */ - // (*) An inline type is considered empty if it contains no non-static fields or - // if it contains only empty inline fields. Note that JITs have a slightly different - // definition: empty inline fields must be flat otherwise the container won't + // (*) A value type is considered empty if it contains no non-static fields or + // if it contains only empty value fields. Note that JITs have a slightly different + // definition: empty value fields must be flat otherwise the container won't // be considered empty. public: @@ -124,8 +125,8 @@ class InstanceKlassFlags { u4 flags() const { return _flags; } - static u4 is_empty_inline_type_value() { - return _misc_is_empty_inline_type; + static u4 is_empty_value_type_value() { + return _misc_is_empty_value_type; } void assert_is_safe(bool set) NOT_DEBUG_RETURN; diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index b99fff3da28f..0857a2ec158f 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -1074,23 +1074,23 @@ void Klass::validate_array_description(const ArrayDescription& ad) { assert(ad._layout_kind == LayoutKind::REFERENCE, "Cannot support flattening"); assert(ad._kind == KlassKind::RefArrayKlassKind, "Must be a reference array"); } else { - assert(is_inline_klass(), "Must be"); - InlineKlass* ik = InlineKlass::cast(this); + assert(is_value_klass(), "Must be"); + ValueKlass* vk = ValueKlass::cast(this); switch(ad._layout_kind) { case LayoutKind::BUFFERED: fatal("Invalid layout for an array"); break; case LayoutKind::NULL_FREE_ATOMIC_FLAT: - assert(ik->has_null_free_atomic_layout(), "Sanity check"); + assert(vk->has_null_free_atomic_layout(), "Sanity check"); break; case LayoutKind::NULL_FREE_NON_ATOMIC_FLAT: - assert(ik->has_null_free_non_atomic_layout(), "Sanity check"); + assert(vk->has_null_free_non_atomic_layout(), "Sanity check"); break; case LayoutKind::NULLABLE_ATOMIC_FLAT: - assert(ik->has_nullable_atomic_layout(), "Sanity check"); + assert(vk->has_nullable_atomic_layout(), "Sanity check"); break; case LayoutKind::NULLABLE_NON_ATOMIC_FLAT: - assert(ik->has_nullable_non_atomic_layout(), "Sanity check)"); + assert(vk->has_nullable_non_atomic_layout(), "Sanity check)"); break; case LayoutKind::REFERENCE: break; diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index ea9161b27ed8..88e124769839 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -68,7 +68,7 @@ class Klass : public Metadata { enum KlassKind : u2 { InstanceKlassKind, - InlineKlassKind, + ValueKlassKind, InstanceRefKlassKind, InstanceMirrorKlassKind, InstanceClassLoaderKlassKind, @@ -506,7 +506,7 @@ class Klass : public Metadata { return (juint)_lh_array_tag_flat_value == (juint)(lh >> _lh_array_tag_shift); } static bool layout_helper_is_null_free(jint lh) { - assert(layout_helper_is_flatArray(lh) || layout_helper_is_refArray(lh), "must be array of inline types"); + assert(layout_helper_is_flatArray(lh) || layout_helper_is_refArray(lh), "must be array of value types"); return ((lh >> _lh_null_free_shift) & _lh_null_free_mask); } static jint layout_helper_set_null_free(jint lh) { @@ -698,7 +698,7 @@ class Klass : public Metadata { virtual bool is_flatArray_klass_slow() const { return false; } #endif // ASSERT // current implementation uses this method even in non debug builds - virtual bool is_inline_klass_slow() const { return false; } + virtual bool is_value_klass_slow() const { return false; } public: // Fast non-virtual versions @@ -714,7 +714,7 @@ class Klass : public Metadata { #endif bool is_instance_klass() const { return assert_same_query(_kind <= InstanceStackChunkKlassKind, is_instance_klass_slow()); } - bool is_inline_klass() const { return assert_same_query(_kind == InlineKlassKind, is_inline_klass_slow()); } + bool is_value_klass() const { return assert_same_query(_kind == ValueKlassKind, is_value_klass_slow()); } bool is_reference_instance_klass() const { return _kind == InstanceRefKlassKind; } bool is_mirror_instance_klass() const { return _kind == InstanceMirrorKlassKind; } bool is_class_loader_instance_klass() const { return _kind == InstanceClassLoaderKlassKind; } diff --git a/src/hotspot/share/oops/layoutKind.hpp b/src/hotspot/share/oops/layoutKind.hpp index 2eb8acc58640..00b095fd76cb 100644 --- a/src/hotspot/share/oops/layoutKind.hpp +++ b/src/hotspot/share/oops/layoutKind.hpp @@ -34,7 +34,7 @@ // // REFERENCE : This layout uses a pointer to a heap allocated instance (no flattening). // When used, field_flags().is_flat() is false . The field can be nullable or -// null-restricted, in the later case, field_flags().is_null_free_inline_type() is true. +// null-restricted, in the later case, field_flags().is_null_free_value_type() is true. // In case of a null-restricted field, putfield and putstatic must perform a null-check // before writing a new value. Still for null-restricted fields, if getfield reads a null pointer // from the receiver, it means that the field was not initialized yet, and getfield must substitute diff --git a/src/hotspot/share/oops/markWord.cpp b/src/hotspot/share/oops/markWord.cpp index 3ce3f5dc7405..b85cf956133d 100644 --- a/src/hotspot/share/oops/markWord.cpp +++ b/src/hotspot/share/oops/markWord.cpp @@ -45,8 +45,8 @@ void markWord::print_on(outputStream* st) const { assert(is_fast_locked(), "should be"); st->print("is_fast_locked"); } - if (is_inline_type()) { - st->print(" inline_type"); + if (is_value_type()) { + st->print(" value_type"); } if (has_hash()) { st->print(" hash=" INTPTR_FORMAT, hash()); diff --git a/src/hotspot/share/oops/markWord.hpp b/src/hotspot/share/oops/markWord.hpp index 7cb1e5b57285..7a267bff6b55 100644 --- a/src/hotspot/share/oops/markWord.hpp +++ b/src/hotspot/share/oops/markWord.hpp @@ -68,14 +68,14 @@ // // - valhalla - only supported on 64-bit VMs // -// * inline types: A value class instance +// * value types: A value class instance // * flat arrays: An array with flattened value class elements // * null-free arrays: An array instance without null elements // * valhalla reserved: Reserved for future use // -// Inline types cannot be locked. +// Value types cannot be locked. // -// Inline types have a deterministic hash based on the immutable payload +// Value types have a deterministic hash based on the immutable payload // and class, which may be cached in the markWord. // // - hash - contains the hash value: largest value is 31 bits, see @@ -125,19 +125,19 @@ class markWord { static const int lock_bits = 2; static const int self_fwd_bits = 1; static const int age_bits = 4; - static const int inline_type_bits = LP64_ONLY(1) NOT_LP64(0); + static const int value_type_bits = LP64_ONLY(1) NOT_LP64(0); static const int null_free_array_bits = LP64_ONLY(1) NOT_LP64(0); static const int flat_array_bits = LP64_ONLY(1) NOT_LP64(0); static const int valhalla_reserved_bits = LP64_ONLY(1) NOT_LP64(0); - static const int max_hash_bits = BitsPerWord - age_bits - lock_bits - inline_type_bits - valhalla_reserved_bits - flat_array_bits - null_free_array_bits - self_fwd_bits; + static const int max_hash_bits = BitsPerWord - age_bits - lock_bits - value_type_bits - valhalla_reserved_bits - flat_array_bits - null_free_array_bits - self_fwd_bits; static const int hash_bits = max_hash_bits > 31 ? 31 : max_hash_bits; // Shifts static const int lock_shift = 0; static const int self_fwd_shift = lock_shift + lock_bits; static const int age_shift = self_fwd_shift + self_fwd_bits; - static const int inline_type_shift = age_shift + age_bits; - static const int null_free_array_shift = inline_type_shift + inline_type_bits; + static const int value_type_shift = age_shift + age_bits; + static const int null_free_array_shift = value_type_shift + value_type_bits; static const int flat_array_shift = null_free_array_shift + null_free_array_bits; static const int valhalla_reserved_shift = flat_array_shift + flat_array_bits; static const int hash_shift = valhalla_reserved_shift + valhalla_reserved_bits; @@ -146,7 +146,7 @@ class markWord { static const uintptr_t lock_mask_in_place = right_n_bits(lock_bits) << lock_shift; static const uintptr_t self_fwd_bit_in_place = right_n_bits(self_fwd_bits) << self_fwd_shift; static const uintptr_t age_mask_in_place = right_n_bits(age_bits) << age_shift; - static const uintptr_t inline_type_bit_in_place = right_n_bits(inline_type_bits) << inline_type_shift; + static const uintptr_t value_type_bit_in_place = right_n_bits(value_type_bits) << value_type_shift; static const uintptr_t null_free_array_bit_in_place = right_n_bits(null_free_array_bits) << null_free_array_shift; static const uintptr_t flat_array_bit_in_place = right_n_bits(flat_array_bits) << flat_array_shift; static const uintptr_t valhalla_reserved_bit_in_place = right_n_bits(valhalla_reserved_bits) << valhalla_reserved_shift; @@ -155,7 +155,7 @@ class markWord { // Verify that _bit_in_place refers to constants with only one bit. static_assert(is_power_of_2(self_fwd_bit_in_place)); #ifdef _LP64 - static_assert(is_power_of_2(inline_type_bit_in_place)); + static_assert(is_power_of_2(value_type_bit_in_place)); static_assert(is_power_of_2(null_free_array_bit_in_place)); static_assert(is_power_of_2(flat_array_bit_in_place)); static_assert(is_power_of_2(valhalla_reserved_bit_in_place)); @@ -184,8 +184,8 @@ class markWord { static const uintptr_t monitor_value = 2; static const uintptr_t marked_value = 3; - static const uintptr_t inline_type_pattern = inline_type_bit_in_place; - static const uintptr_t inline_type_pattern_mask = inline_type_bit_in_place; + static const uintptr_t value_type_pattern = value_type_bit_in_place; + static const uintptr_t value_type_pattern_mask = value_type_bit_in_place; static const uintptr_t no_hash = 0 ; // no hash value assigned static const uintptr_t no_hash_in_place = (uintptr_t)no_hash << hash_shift; @@ -196,10 +196,10 @@ class markWord { // Creates a markWord with all bits set to zero. static markWord zero() { return markWord(uintptr_t(0)); } - bool is_inline_type() const { + bool is_value_type() const { precond(!is_marked()); #ifdef _LP64 // 64 bit encodings only - return (mask_bits(value(), inline_type_pattern_mask) == inline_type_pattern); + return (mask_bits(value(), value_type_pattern_mask) == value_type_pattern); #else return false; #endif @@ -312,9 +312,9 @@ class markWord { return markWord(lock_neutral_value); } - static markWord inline_type_prototype() { + static markWord value_type_prototype() { NOT_LP64(assert(false, "Should not be called in 32 bit mode")); - return markWord(lock_neutral_value | inline_type_bit_in_place); + return markWord(lock_neutral_value | value_type_bit_in_place); } static markWord flat_array_prototype(bool null_free) { diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 9ac0543fd497..dfbef61dd3f3 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -53,7 +53,6 @@ #include "nmt/memTracker.hpp" #include "oops/constantPool.hpp" #include "oops/constMethod.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/jmethodIDTable.hpp" #include "oops/klass.inline.hpp" #include "oops/method.inline.hpp" @@ -63,6 +62,7 @@ #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "oops/trainingData.hpp" +#include "oops/valueKlass.inline.hpp" #include "prims/jvmtiExport.hpp" #include "prims/methodHandles.hpp" #include "runtime/arguments.hpp" @@ -168,20 +168,20 @@ address Method::get_c2i_entry() { return adapter()->get_c2i_entry(); } -address Method::get_c2i_inline_entry() { +address Method::get_c2i_value_entry() { if (is_abstract()) { return SharedRuntime::get_handle_wrong_method_abstract_stub(); } assert(adapter() != nullptr, "must have"); - return adapter()->get_c2i_inline_entry(); + return adapter()->get_c2i_value_entry(); } -address Method::get_c2i_inline_ro_entry() { +address Method::get_c2i_value_ro_entry() { if (is_abstract()) { return SharedRuntime::get_handle_wrong_method_abstract_stub(); } assert(adapter() != nullptr, "must have"); - return adapter()->get_c2i_inline_ro_entry(); + return adapter()->get_c2i_value_ro_entry(); } address Method::get_c2i_unverified_entry() { @@ -192,9 +192,9 @@ address Method::get_c2i_unverified_entry() { return adapter()->get_c2i_unverified_entry(); } -address Method::get_c2i_unverified_inline_entry() { +address Method::get_c2i_unverified_value_entry() { assert(adapter() != nullptr, "must have"); - return adapter()->get_c2i_unverified_inline_entry(); + return adapter()->get_c2i_unverified_value_entry(); } address Method::get_c2i_no_clinit_check_entry() { @@ -474,8 +474,8 @@ void Method::restore_unshareable_info(TRAPS) { if (_adapter != nullptr) { assert(_adapter->is_linked(), "must be"); _from_compiled_entry = _adapter->get_c2i_entry(); - _from_compiled_inline_entry = _adapter->get_c2i_inline_entry(); - _from_compiled_inline_ro_entry = _adapter->get_c2i_inline_ro_entry(); + _from_compiled_value_entry = _adapter->get_c2i_value_entry(); + _from_compiled_value_ro_entry = _adapter->get_c2i_value_ro_entry(); } assert(!queued_for_compilation(), "method's queued_for_compilation flag should not be set"); } @@ -765,18 +765,18 @@ int Method::extra_stack_words() { return extra_stack_entries() * Interpreter::stackElementSize; } -// InlineKlass the method is declared to return. This must not +// ValueKlass the method is declared to return. This must not // safepoint as it is called with references live on the stack at // locations the GC is unaware of. -InlineKlass* Method::returns_inline_type() const { - assert(InlineTypeReturnedAsFields, "Inline types should never be returned as fields"); +ValueKlass* Method::returns_value_type() const { + assert(ValueTypeReturnedAsFields, "Value types should never be returned as fields"); if (is_native()) { return nullptr; } NoSafepointVerifier nsv; SignatureStream ss(signature()); ss.skip_to_return_type(); - return ss.as_inline_klass(method_holder()); + return ss.as_value_klass(method_holder()); } bool Method::compute_has_loops_flag() { @@ -927,9 +927,9 @@ bool Method::is_getter() const { default: return false; } - if (InlineTypeReturnedAsFields && returns_inline_type() != nullptr) { + if (ValueTypeReturnedAsFields && returns_value_type() != nullptr) { // Don't treat this as (trivial) getter method because the - // inline type could be returned in a scalarized form. + // value type could be returned in a scalarized form. return false; } return true; @@ -955,7 +955,7 @@ bool Method::is_setter() const { if (java_code_at(5) != Bytecodes::_return) return false; if (has_scalarized_args()) { // Don't treat this as (trivial) setter method because the - // inline type argument should be passed in a scalarized form. + // value type argument should be passed in a scalarized form. return false; } return true; @@ -1232,12 +1232,12 @@ void Method::clear_code() { // Only should happen at allocate time. if (adapter() == nullptr) { _from_compiled_entry = nullptr; - _from_compiled_inline_entry = nullptr; - _from_compiled_inline_ro_entry = nullptr; + _from_compiled_value_entry = nullptr; + _from_compiled_value_ro_entry = nullptr; } else { _from_compiled_entry = adapter()->get_c2i_entry(); - _from_compiled_inline_entry = adapter()->get_c2i_inline_entry(); - _from_compiled_inline_ro_entry = adapter()->get_c2i_inline_ro_entry(); + _from_compiled_value_entry = adapter()->get_c2i_value_entry(); + _from_compiled_value_ro_entry = adapter()->get_c2i_value_ro_entry(); } OrderAccess::storestore(); _from_interpreted_entry = _i2i_entry; @@ -1271,8 +1271,8 @@ void Method::unlink_method() { } _i2i_entry = nullptr; _from_compiled_entry = nullptr; - _from_compiled_inline_entry = nullptr; - _from_compiled_inline_ro_entry = nullptr; + _from_compiled_value_entry = nullptr; + _from_compiled_value_ro_entry = nullptr; _from_interpreted_entry = nullptr; if (is_native()) { @@ -1352,12 +1352,12 @@ void Method::link_method(const methodHandle& h_method, TRAPS) { // problem we'll make these lazily later. // With the scalarized calling convention, create adapters for abstract // methods as well because the adapter is used to propagate the signature. - if (_adapter == nullptr && (!h_method->is_abstract() || InlineTypePassFieldsAsArgs)) { + if (_adapter == nullptr && (!h_method->is_abstract() || ValueTypePassFieldsAsArgs)) { make_adapters(h_method, CHECK); } h_method->_from_compiled_entry = h_method->get_c2i_entry(); - h_method->_from_compiled_inline_entry = h_method->get_c2i_inline_entry(); - h_method->_from_compiled_inline_ro_entry = h_method->get_c2i_inline_ro_entry(); + h_method->_from_compiled_value_entry = h_method->get_c2i_value_entry(); + h_method->_from_compiled_value_ro_entry = h_method->get_c2i_value_ro_entry(); // ONLY USE the h_method now as make_adapter may have blocked @@ -1377,7 +1377,7 @@ void Method::link_method(const methodHandle& h_method, TRAPS) { } void Method::make_adapters(const methodHandle& mh, TRAPS) { - assert(!mh->is_abstract() || InlineTypePassFieldsAsArgs, "abstract methods do not have adapters"); + assert(!mh->is_abstract() || ValueTypePassFieldsAsArgs, "abstract methods do not have adapters"); PerfTraceTime timer(ClassLoader::perf_method_adapters_time()); // Adapters for compiled code are made eagerly here. They are fairly @@ -1416,16 +1416,16 @@ address Method::verified_code_entry() { return _from_compiled_entry; } -address Method::verified_inline_code_entry() { +address Method::verified_value_code_entry() { DEBUG_ONLY(NoSafepointVerifier nsv;) - assert(_from_compiled_inline_entry != nullptr, "must be set"); - return _from_compiled_inline_entry; + assert(_from_compiled_value_entry != nullptr, "must be set"); + return _from_compiled_value_entry; } -address Method::verified_inline_ro_code_entry() { +address Method::verified_value_ro_code_entry() { DEBUG_ONLY(NoSafepointVerifier nsv;) - assert(_from_compiled_inline_ro_entry != nullptr, "must be set"); - return _from_compiled_inline_ro_entry; + assert(_from_compiled_value_ro_entry != nullptr, "must be set"); + return _from_compiled_value_ro_entry; } // Check that if an nmethod ref exists, it has a backlink to this or no backlink at all @@ -1459,8 +1459,8 @@ void Method::set_code(const methodHandle& mh, nmethod *code) { OrderAccess::storestore(); mh->_from_compiled_entry = code->verified_entry_point(); - mh->_from_compiled_inline_entry = code->verified_inline_entry_point(); - mh->_from_compiled_inline_ro_entry = code->verified_inline_ro_entry_point(); + mh->_from_compiled_value_entry = code->verified_value_entry_point(); + mh->_from_compiled_value_ro_entry = code->verified_value_ro_entry_point(); OrderAccess::storestore(); if (mh->is_continuation_native_intrinsic()) { @@ -1653,8 +1653,8 @@ methodHandle Method::make_method_handle_intrinsic(vmIntrinsics::ID iid, void Method::restore_archived_method_handle_intrinsic(methodHandle m, TRAPS) { if (m->adapter() != nullptr) { m->set_from_compiled_entry(m->adapter()->get_c2i_entry()); - m->set_from_compiled_inline_entry(m->adapter()->get_c2i_inline_entry()); - m->set_from_compiled_inline_ro_entry(m->adapter()->get_c2i_inline_ro_entry()); + m->set_from_compiled_value_entry(m->adapter()->get_c2i_value_entry()); + m->set_from_compiled_value_ro_entry(m->adapter()->get_c2i_value_ro_entry()); } m->link_method(m, CHECK); @@ -2362,9 +2362,9 @@ void Method::print_on(outputStream* st) const { st->print_cr(PTR_FORMAT, p2i(a)); else a->print_adapter_on(st); - st->print_cr(" - compiled entry " PTR_FORMAT, p2i(from_compiled_entry())); - st->print_cr(" - compiled inline entry " PTR_FORMAT, p2i(from_compiled_inline_entry())); - st->print_cr(" - compiled inline ro entry " PTR_FORMAT, p2i(from_compiled_inline_ro_entry())); + st->print_cr(" - compiled entry " PTR_FORMAT, p2i(from_compiled_entry())); + st->print_cr(" - compiled value entry " PTR_FORMAT, p2i(from_compiled_value_entry())); + st->print_cr(" - compiled value ro entry " PTR_FORMAT, p2i(from_compiled_value_ro_entry())); st->print_cr(" - code size: %d", code_size()); if (code_size() != 0) { st->print_cr(" - code start: " PTR_FORMAT, p2i(code_base())); diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index d199c25d21a3..8c0f9affa605 100644 --- a/src/hotspot/share/oops/method.hpp +++ b/src/hotspot/share/oops/method.hpp @@ -92,9 +92,9 @@ class Method : public Metadata { address _i2i_entry; // All-args-on-stack calling convention // Entry point for calling from compiled code, to compiled code if it exists // or else the interpreter. - volatile address _from_compiled_entry; // Cache of: _code ? _code->entry_point() : _adapter->c2i_entry() - volatile address _from_compiled_inline_ro_entry; // Cache of: _code ? _code->verified_inline_ro_entry_point() : _adapter->c2i_inline_ro_entry() - volatile address _from_compiled_inline_entry; // Cache of: _code ? _code->verified_inline_entry_point() : _adapter->c2i_inline_entry() + volatile address _from_compiled_entry; // Cache of: _code ? _code->entry_point() : _adapter->c2i_entry() + volatile address _from_compiled_value_ro_entry; // Cache of: _code ? _code->verified_value_ro_entry_point() : _adapter->c2i_value_ro_entry() + volatile address _from_compiled_value_entry; // Cache of: _code ? _code->verified_value_entry_point() : _adapter->c2i_value_entry() // The entry point for calling both from and to compiled code is // "_code->entry_point()". Because of tiered compilation and de-opt, this // field can come and go. It can transition from null to not-null at any @@ -134,8 +134,8 @@ class Method : public Metadata { static void make_adapters(const methodHandle& mh, TRAPS); address from_compiled_entry() const; - address from_compiled_inline_ro_entry() const; - address from_compiled_inline_entry() const; + address from_compiled_value_ro_entry() const; + address from_compiled_value_entry() const; address from_interpreted_entry() const; // access flag @@ -364,8 +364,8 @@ class Method : public Metadata { // nmethod/verified compiler entry address verified_code_entry(); - address verified_inline_code_entry(); - address verified_inline_ro_code_entry(); + address verified_value_code_entry(); + address verified_value_ro_code_entry(); bool check_code() const; // Not inline to avoid circular ref nmethod* code() const; @@ -390,19 +390,19 @@ class Method : public Metadata { void set_from_compiled_entry(address entry) { _from_compiled_entry = entry; } - void set_from_compiled_inline_ro_entry(address entry) { - _from_compiled_inline_ro_entry = entry; + void set_from_compiled_value_ro_entry(address entry) { + _from_compiled_value_ro_entry = entry; } - void set_from_compiled_inline_entry(address entry) { - _from_compiled_inline_entry = entry; + void set_from_compiled_value_entry(address entry) { + _from_compiled_value_entry = entry; } address get_i2c_entry(); address get_c2i_entry(); - address get_c2i_inline_entry(); - address get_c2i_inline_ro_entry(); + address get_c2i_value_entry(); + address get_c2i_value_ro_entry(); address get_c2i_unverified_entry(); - address get_c2i_unverified_inline_entry(); + address get_c2i_unverified_value_entry(); address get_c2i_no_clinit_check_entry(); AdapterHandlerEntry* adapter() const { return _adapter; @@ -516,7 +516,7 @@ class Method : public Metadata { Symbol* klass_name() const; // returns the name of the method holder BasicType result_type() const { return constMethod()->result_type(); } bool is_returning_oop() const { BasicType r = result_type(); return is_reference_type(r); } - InlineKlass* returns_inline_type() const; + ValueKlass* returns_value_type() const; // Checked exceptions thrown by this method (resolved to mirrors) objArrayHandle resolved_checked_exceptions(TRAPS) { return resolved_checked_exceptions_impl(this, THREAD); } @@ -625,8 +625,8 @@ class Method : public Metadata { static ByteSize const_offset() { return byte_offset_of(Method, _constMethod ); } static ByteSize access_flags_offset() { return byte_offset_of(Method, _access_flags ); } static ByteSize from_compiled_offset() { return byte_offset_of(Method, _from_compiled_entry); } - static ByteSize from_compiled_inline_offset() { return byte_offset_of(Method, _from_compiled_inline_entry); } - static ByteSize from_compiled_inline_ro_offset(){ return byte_offset_of(Method, _from_compiled_inline_ro_entry); } + static ByteSize from_compiled_value_offset() { return byte_offset_of(Method, _from_compiled_value_entry); } + static ByteSize from_compiled_value_ro_offset(){ return byte_offset_of(Method, _from_compiled_value_ro_entry); } static ByteSize code_offset() { return byte_offset_of(Method, _code); } static ByteSize flags_offset() { return byte_offset_of(Method, _flags); } diff --git a/src/hotspot/share/oops/method.inline.hpp b/src/hotspot/share/oops/method.inline.hpp index 65f5c4fd3028..bae77f58ef04 100644 --- a/src/hotspot/share/oops/method.inline.hpp +++ b/src/hotspot/share/oops/method.inline.hpp @@ -37,12 +37,12 @@ inline address Method::from_compiled_entry() const { return AtomicAccess::load_acquire(&_from_compiled_entry); } -inline address Method::from_compiled_inline_ro_entry() const { - return AtomicAccess::load_acquire(&_from_compiled_inline_ro_entry); +inline address Method::from_compiled_value_ro_entry() const { + return AtomicAccess::load_acquire(&_from_compiled_value_ro_entry); } -inline address Method::from_compiled_inline_entry() const { - return AtomicAccess::load_acquire(&_from_compiled_inline_entry); +inline address Method::from_compiled_value_entry() const { + return AtomicAccess::load_acquire(&_from_compiled_value_entry); } inline address Method::from_interpreted_entry() const { diff --git a/src/hotspot/share/oops/methodData.hpp b/src/hotspot/share/oops/methodData.hpp index 02072262b16b..443f10512946 100644 --- a/src/hotspot/share/oops/methodData.hpp +++ b/src/hotspot/share/oops/methodData.hpp @@ -2057,8 +2057,8 @@ class ArrayLoadData : public BitData { class ACmpData : public BranchData { private: enum { - left_inline_type_flag = DataLayout::first_flag, - right_inline_type_flag + left_value_type_flag = DataLayout::first_flag, + right_value_type_flag }; SingleTypeEntry _left; @@ -2092,19 +2092,19 @@ class ACmpData : public BranchData { return static_cell_count(); } - void set_left_inline_type() { set_flag_at(left_inline_type_flag); } - bool left_inline_type() const { return flag_at(left_inline_type_flag); } + void set_left_value_type() { set_flag_at(left_value_type_flag); } + bool left_value_type() const { return flag_at(left_value_type_flag); } - void set_right_inline_type() { set_flag_at(right_inline_type_flag); } - bool right_inline_type() const { return flag_at(right_inline_type_flag); } + void set_right_value_type() { set_flag_at(right_value_type_flag); } + bool right_value_type() const { return flag_at(right_value_type_flag); } // Code generation support - static int left_inline_type_byte_constant() { - return flag_number_to_constant(left_inline_type_flag); + static int left_value_type_byte_constant() { + return flag_number_to_constant(left_value_type_flag); } - static int right_inline_type_byte_constant() { - return flag_number_to_constant(right_inline_type_flag); + static int right_value_type_byte_constant() { + return flag_number_to_constant(right_value_type_flag); } static ByteSize left_offset() { diff --git a/src/hotspot/share/oops/objArrayKlass.cpp b/src/hotspot/share/oops/objArrayKlass.cpp index e3e20474ee8a..1fa79b65f7b4 100644 --- a/src/hotspot/share/oops/objArrayKlass.cpp +++ b/src/hotspot/share/oops/objArrayKlass.cpp @@ -38,7 +38,6 @@ #include "oops/arrayKlass.hpp" #include "oops/arrayOop.inline.hpp" #include "oops/flatArrayKlass.hpp" -#include "oops/inlineKlass.hpp" #include "oops/instanceKlass.hpp" #include "oops/klass.inline.hpp" #include "oops/layoutKind.hpp" @@ -49,6 +48,7 @@ #include "oops/oopCast.inline.hpp" #include "oops/refArrayKlass.hpp" #include "oops/symbol.hpp" +#include "oops/valueKlass.hpp" #include "runtime/arguments.hpp" #include "runtime/handles.inline.hpp" #include "runtime/mutexLocker.hpp" @@ -183,7 +183,7 @@ ArrayDescription ObjArrayKlass::array_layout_selection(Klass* element, ArrayProp if (!UseArrayFlattening || element->is_array_klass() || element->is_identity_class() || element->is_abstract()) { return ArrayDescription(RefArrayKlassKind, props, LayoutKind::REFERENCE); } - InlineKlass* vk = InlineKlass::cast(element); + ValueKlass* vk = ValueKlass::cast(element); if (!vk->maybe_flat_in_array()) { return ArrayDescription(RefArrayKlassKind, props, LayoutKind::REFERENCE); } diff --git a/src/hotspot/share/oops/objArrayKlass.hpp b/src/hotspot/share/oops/objArrayKlass.hpp index 934eedcbf6a6..6a3f938bd4a9 100644 --- a/src/hotspot/share/oops/objArrayKlass.hpp +++ b/src/hotspot/share/oops/objArrayKlass.hpp @@ -36,7 +36,7 @@ class ObjArrayKlass : public ArrayKlass { friend class Deoptimization; friend class oopFactory; friend class VMStructs; - friend class ciInlineKlass; + friend class ciValueKlass; public: static const KlassKind Kind = ObjArrayKlassKind; diff --git a/src/hotspot/share/oops/oop.cpp b/src/hotspot/share/oops/oop.cpp index 4a7c7ad688d1..5ae20b4041b2 100644 --- a/src/hotspot/share/oops/oop.cpp +++ b/src/hotspot/share/oops/oop.cpp @@ -118,7 +118,7 @@ void oopDesc::verify(oopDesc* oop_desc) { intptr_t oopDesc::slow_identity_hash(markWord current_mark, Thread* current) { precond(!current_mark.has_hash()); - assert(!is_inline(), "slow_identity_hash should not be called for value objects"); + assert(!is_value(), "slow_identity_hash should not be called for value objects"); // Calculate the new hash const intptr_t new_hash = ObjectSynchronizer::get_next_hash(current, this); diff --git a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp index 349c5f5a518f..f810c07b956b 100644 --- a/src/hotspot/share/oops/oop.hpp +++ b/src/hotspot/share/oops/oop.hpp @@ -117,7 +117,7 @@ class oopDesc { // type test operations (inlined in oop.inline.hpp) inline bool is_instance() const; - inline bool is_inline() const; + inline bool is_value() const; inline bool is_instanceRef() const; inline bool is_stackChunk() const; inline bool is_array() const; @@ -128,7 +128,7 @@ class oopDesc { inline bool is_refined_objArray() const; inline bool is_array_with_oops() const; - inline bool is_inline_type() const; + inline bool is_value_type() const; // type test operations that don't require inclusion of oop.inline.hpp. bool is_instance_noinline() const; diff --git a/src/hotspot/share/oops/oop.inline.hpp b/src/hotspot/share/oops/oop.inline.hpp index 864fbc5e5e72..fbd526b3c966 100644 --- a/src/hotspot/share/oops/oop.inline.hpp +++ b/src/hotspot/share/oops/oop.inline.hpp @@ -210,7 +210,7 @@ size_t oopDesc::size_given_klass(Klass* klass) { } bool oopDesc::is_instance() const { return klass()->is_instance_klass(); } -bool oopDesc::is_inline() const { return klass()->is_inline_klass(); } +bool oopDesc::is_value() const { return klass()->is_value_klass(); } bool oopDesc::is_instanceRef() const { return klass()->is_reference_instance_klass(); } bool oopDesc::is_stackChunk() const { return klass()->is_stack_chunk_instance_klass(); } bool oopDesc::is_array() const { return klass()->is_array_klass(); } @@ -229,7 +229,7 @@ bool oopDesc::is_array_with_oops() const { return is_refArray() || FlatArrayKlass::cast(klass())->contains_oops(); } -bool oopDesc::is_inline_type() const { return mark().is_inline_type(); } +bool oopDesc::is_value_type() const { return mark().is_value_type(); } template T* oopDesc::field_addr(int offset) const { return reinterpret_cast(cast_from_oop(as_oop()) + offset); } diff --git a/src/hotspot/share/oops/oopsHierarchy.hpp b/src/hotspot/share/oops/oopsHierarchy.hpp index 83f2ad866138..d79239c644e4 100644 --- a/src/hotspot/share/oops/oopsHierarchy.hpp +++ b/src/hotspot/share/oops/oopsHierarchy.hpp @@ -42,7 +42,7 @@ typedef void* OopOrNarrowOopStar; typedef class oopDesc* oop; typedef class instanceOopDesc* instanceOop; -typedef class inlineOopDesc* inlineOop; +typedef class valueOopDesc* valueOop; typedef class stackChunkOopDesc* stackChunkOop; typedef class arrayOopDesc* arrayOop; typedef class objArrayOopDesc* objArrayOop; @@ -166,7 +166,7 @@ struct PrimitiveConversions::Translate : public std::true_type { #define DEF_OOP(type) DEF_OOP_IMPL(type##Oop, type##OopDesc, oop) DEF_OOP(instance); -DEF_OOP_BASE(inline, instance); +DEF_OOP_BASE(value, instance); DEF_OOP_BASE(stackChunk, instance); DEF_OOP(array); DEF_OOP_BASE(objArray, array); @@ -206,7 +206,7 @@ class ConstantPool; class Klass; class InstanceKlass; -class InlineKlass; +class ValueKlass; class InstanceMirrorKlass; class InstanceClassLoaderKlass; class InstanceRefKlass; diff --git a/src/hotspot/share/oops/refArrayKlass.cpp b/src/hotspot/share/oops/refArrayKlass.cpp index 268d9c487ae9..7e5a181fd663 100644 --- a/src/hotspot/share/oops/refArrayKlass.cpp +++ b/src/hotspot/share/oops/refArrayKlass.cpp @@ -62,7 +62,7 @@ RefArrayKlass *RefArrayKlass::allocate_klass(ClassLoaderData* loader_data, int n RefArrayKlass* RefArrayKlass::allocate_refArray_klass(ClassLoaderData* loader_data, int n, Klass* element_klass, ArrayProperties props, TRAPS) { - assert(!props.is_null_restricted() || (n == 1 && element_klass->is_inline_klass()), + assert(!props.is_null_restricted() || (n == 1 && element_klass->is_value_klass()), "null-free unsupported"); // Eagerly allocate the direct array supertype. diff --git a/src/hotspot/share/oops/resolvedFieldEntry.cpp b/src/hotspot/share/oops/resolvedFieldEntry.cpp index 2f9fe98daa27..f1f6a7143b1c 100644 --- a/src/hotspot/share/oops/resolvedFieldEntry.cpp +++ b/src/hotspot/share/oops/resolvedFieldEntry.cpp @@ -42,7 +42,7 @@ void ResolvedFieldEntry::fill_in(const fieldDescriptor& info, u1 tos_state, u1 g set_flags(info.access_flags().is_volatile(), info.access_flags().is_final(), info.is_flat(), - info.is_null_free_inline_type(), + info.is_null_free_value_type(), info.has_null_marker()); _field_holder = info.field_holder(); _field_offset = info.offset(); @@ -70,7 +70,7 @@ void ResolvedFieldEntry::print_on(outputStream* st) const { st->print_cr(" - Is Final: %d", is_final()); st->print_cr(" - Is Volatile: %d", is_volatile()); st->print_cr(" - Is Flat: %d", is_flat()); - st->print_cr(" - Is Null Free Inline Type: %d", is_null_free_inline_type()); + st->print_cr(" - Is Null Free Value type: %d", is_null_free_value_type()); st->print_cr(" - Has null marker: %d", has_null_marker()); st->print_cr(" - Get Bytecode: %s", Bytecodes::name((Bytecodes::Code)get_code())); st->print_cr(" - Put Bytecode: %s", Bytecodes::name((Bytecodes::Code)put_code())); diff --git a/src/hotspot/share/oops/resolvedFieldEntry.hpp b/src/hotspot/share/oops/resolvedFieldEntry.hpp index f1dddb403e7c..d3afbb72e230 100644 --- a/src/hotspot/share/oops/resolvedFieldEntry.hpp +++ b/src/hotspot/share/oops/resolvedFieldEntry.hpp @@ -56,7 +56,7 @@ class ResolvedFieldEntry { u2 _field_index; // Index into field information in holder InstanceKlass u2 _cpool_index; // Constant pool index u1 _tos_state; // TOS state - u1 _flags; // Flags: [000|has_null_marker|is_null_free_inline_type|is_flat|is_final|is_volatile] + u1 _flags; // Flags: [000|has_null_marker|is_null_free_value_type|is_flat|is_final|is_volatile] u1 _get_code, _put_code; // Get and Put bytecodes of the field #ifdef _LP64 u4 _padding; @@ -85,7 +85,7 @@ class ResolvedFieldEntry { is_volatile_shift = 0, is_final_shift = 1, // unused is_flat_shift = 2, - is_null_free_inline_type_shift = 3, + is_null_free_value_type_shift = 3, has_null_marker_shift = 4, max_flag_shift = has_null_marker_shift }; @@ -101,7 +101,7 @@ class ResolvedFieldEntry { bool is_volatile () const { return (_flags & (1 << is_volatile_shift)) != 0; } bool is_final() const { return (_flags & (1 << is_final_shift)) != 0; } bool is_flat() const { return (_flags & (1 << is_flat_shift)) != 0; } - bool is_null_free_inline_type() const { return (_flags & (1 << is_null_free_inline_type_shift)) != 0; } + bool is_null_free_value_type() const { return (_flags & (1 << is_null_free_value_type_shift)) != 0; } bool has_null_marker() const { return (_flags & (1 << has_null_marker_shift)) != 0; } bool is_resolved(Bytecodes::Code code) const { switch(code) { @@ -124,19 +124,19 @@ class ResolvedFieldEntry { void set_flags(bool is_volatile_flag, bool is_final_flag, bool is_flat_flag, - bool is_null_free_inline_type_flag, + bool is_null_free_value_type_flag, bool has_null_marker_flag) { int new_flags = ((is_volatile_flag ? 1 : 0) << is_volatile_shift) | ((is_final_flag ? 1 : 0) << is_final_shift) | ((is_flat_flag ? 1 : 0) << is_flat_shift) | - ((is_null_free_inline_type_flag ? 1 : 0) << is_null_free_inline_type_shift) | + ((is_null_free_value_type_flag ? 1 : 0) << is_null_free_value_type_shift) | ((has_null_marker_flag ? 1 : 0) << has_null_marker_shift); _flags = checked_cast(new_flags); assert(is_volatile() == is_volatile_flag, "Must be"); assert(is_final() == is_final_flag, "Must be"); assert(is_flat() == is_flat_flag, "Must be"); - assert(is_null_free_inline_type() == is_null_free_inline_type_flag, "Must be"); + assert(is_null_free_value_type() == is_null_free_value_type_flag, "Must be"); assert(has_null_marker() == has_null_marker_flag, "Must be"); } diff --git a/src/hotspot/share/oops/inlineKlass.cpp b/src/hotspot/share/oops/valueKlass.cpp similarity index 78% rename from src/hotspot/share/oops/inlineKlass.cpp rename to src/hotspot/share/oops/valueKlass.cpp index b37e1ff80f66..df12a90dd533 100644 --- a/src/hotspot/share/oops/inlineKlass.cpp +++ b/src/hotspot/share/oops/valueKlass.cpp @@ -38,7 +38,6 @@ #include "oops/compressedOops.inline.hpp" #include "oops/fieldStreams.inline.hpp" #include "oops/flatArrayKlass.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/layoutKind.hpp" #include "oops/method.hpp" @@ -46,6 +45,7 @@ #include "oops/oop.inline.hpp" #include "oops/oopsHierarchy.hpp" #include "oops/refArrayKlass.hpp" +#include "oops/valueKlass.inline.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" @@ -57,7 +57,7 @@ #include "utilities/copy.hpp" #include "utilities/stringUtils.hpp" -InlineKlass::Members::Members() +ValueKlass::Members::Members() : _extended_sig(nullptr), _return_regs(nullptr), _pack_handler(nullptr), @@ -79,53 +79,53 @@ InlineKlass::Members::Members() _fast_hashcode_shift(0) {} -InlineKlass::InlineKlass() { +ValueKlass::ValueKlass() { assert(CDSConfig::is_dumping_archive() || UseSharedSpaces, "only for CDS"); } // Constructor -InlineKlass::InlineKlass(const ClassFileParser& parser) - : InstanceKlass(parser, InlineKlass::Kind, markWord::inline_type_prototype()) { - assert(is_inline_klass(), "sanity"); - assert(prototype_header().is_inline_type(), "sanity"); +ValueKlass::ValueKlass(const ClassFileParser& parser) + : InstanceKlass(parser, ValueKlass::Kind, markWord::value_type_prototype()) { + assert(is_value_klass(), "sanity"); + assert(prototype_header().is_value_type(), "sanity"); // Set up the offset to the members of this klass - _adr_inline_klass_members = calculate_members_address(); + _adr_value_klass_members = calculate_members_address(); // Placement install the members - new (_adr_inline_klass_members) Members(); + new (_adr_value_klass_members) Members(); // Sanity check construction of the members assert(pack_handler() == nullptr, "pack handler not null"); } -address InlineKlass::calculate_members_address() const { +address ValueKlass::calculate_members_address() const { // The members are placed after all other contents inherited from the InstanceKlass return end_of_instance_klass(); } -oop InlineKlass::null_reset_value() const { +oop ValueKlass::null_reset_value() const { assert(is_initialized() || is_being_initialized() || is_in_error_state(), "null reset value is set at the beginning of initialization"); oop val = java_mirror()->obj_field_acquire(null_reset_value_offset()); assert(val != nullptr, "Sanity check"); return val; } -void InlineKlass::set_null_reset_value(oop val) { +void ValueKlass::set_null_reset_value(oop val) { assert(val != nullptr, "Sanity check"); assert(oopDesc::is_oop(val), "Sanity check"); - assert(val->is_inline_type(), "Sanity check"); + assert(val->is_value_type(), "Sanity check"); assert(val->klass() == this, "sanity check"); java_mirror()->obj_field_put(null_reset_value_offset(), val); } -inlineOop InlineKlass::allocate_instance(TRAPS) { - inlineOop oop = (inlineOop)InstanceKlass::allocate_instance(CHECK_NULL); - assert(oop->mark().is_inline_type(), "Expected inline type"); +valueOop ValueKlass::allocate_instance(TRAPS) { + valueOop oop = (valueOop)InstanceKlass::allocate_instance(CHECK_NULL); + assert(oop->mark().is_value_type(), "Expected value type"); return oop; } -int InlineKlass::nonstatic_oop_count() { +int ValueKlass::nonstatic_oop_count() { int oops = 0; int map_count = nonstatic_oop_map_count(); OopMapBlock* block = start_of_nonstatic_oop_maps(); @@ -139,7 +139,7 @@ int InlineKlass::nonstatic_oop_count() { // Arrays of... -bool InlineKlass::maybe_flat_in_array() { +bool ValueKlass::maybe_flat_in_array() { if (!UseArrayFlattening) { return false; } @@ -154,30 +154,30 @@ bool InlineKlass::maybe_flat_in_array() { return true; } -// Inline type arguments are not passed by reference, instead each -// field of the inline type is passed as an argument. This helper +// Value type arguments are not passed by reference, instead each +// field of the value type is passed as an argument. This helper // function collects the flat field (recursively) // in a list. Included with the field's type is -// the offset of each field in the inline type: i2c and c2i adapters +// the offset of each field in the value type: i2c and c2i adapters // need that to load or store fields. Finally, the list of fields is // sorted in order of increasing offsets: the adapters and the // compiled code need to agree upon the order of fields. // // The list of basic types that is returned starts with a T_METADATA // and ends with an extra T_VOID. T_METADATA/T_VOID pairs are used as -// delimiters. Every entry between the two is a field of the inline -// type. If there's an embedded inline type in the list, it also starts +// delimiters. Every entry between the two is a field of the value +// type. If there's an embedded value type in the list, it also starts // with a T_METADATA and ends with a T_VOID. This is so we can // generate a unique fingerprint for the method's adapters and we can // generate the list of basic types from the interpreter point of view -// (inline types passed as reference: iterate on the list until a +// (value types passed as reference: iterate on the list until a // T_METADATA, drop everything until and including the closing -// T_VOID) or the compiler point of view (each field of the inline +// T_VOID) or the compiler point of view (each field of the value // types is an argument: drop all T_METADATA/T_VOID from the list). // // Value classes could also have fields in abstract super value classes. // Use a HierarchicalFieldStream to get them as well. -int InlineKlass::collect_fields(GrowableArray* sig, int base_off, int null_marker_offset) { +int ValueKlass::collect_fields(GrowableArray* sig, int base_off, int null_marker_offset) { int count = 0; SigEntry::add_entry(sig, T_METADATA, name(), base_off); for (TopDownHierarchicalNonStaticFieldStreamBase fs(this); !fs.done(); fs.next()) { @@ -187,11 +187,11 @@ int InlineKlass::collect_fields(GrowableArray* sig, int base_off, int if (fs.is_flat()) { // Resolve klass of flat field and recursively collect fields int field_null_marker_offset = -1; - if (!fs.is_null_free_inline_type()) { + if (!fs.is_null_free_value_type()) { field_null_marker_offset = base_off + fs.null_marker_offset() - (base_off > 0 ? payload_offset() : 0); } - Klass* vk = field_holder->get_inline_type_field_klass(fs.index()); - count += InlineKlass::cast(vk)->collect_fields(sig, offset, field_null_marker_offset); + Klass* vk = field_holder->get_value_type_field_klass(fs.index()); + count += ValueKlass::cast(vk)->collect_fields(sig, offset, field_null_marker_offset); } else { BasicType bt = Signature::basic_type(fs.signature()); SigEntry::add_entry(sig, bt, fs.name(), offset); @@ -211,27 +211,27 @@ int InlineKlass::collect_fields(GrowableArray* sig, int base_off, int // Support for the scalarized calling convention. // -// For arguments, an inline type can be passed in scalarized form instead of as a single +// For arguments, a value type can be passed in scalarized form instead of as a single // oop: the calling convention uses an optional buffer oop together with a null marker, // followed by the field values, assigned to the normal argument registers and stack slots. // See CompiledEntrySignature::compute_calling_conventions. // -// For returns, an inline type is returned in scalarized form via multiple return registers: -// the first word is a tri-state value (null, tagged InlineKlass*, or oop) and the remaining +// For returns, a value type is returned in scalarized form via multiple return registers: +// the first word is a tri-state value (null, tagged ValueKlass*, or oop) and the remaining // registers carry the field values. -void InlineKlass::initialize_calling_convention(TRAPS) { +void ValueKlass::initialize_calling_convention(TRAPS) { // Because the pack and unpack handler addresses need to be loadable from generated code, - // they are stored at a fixed offset in the klass metadata. Since inline type klasses do + // they are stored at a fixed offset in the klass metadata. Since value type klasses do // not have a vtable, the vtable offset is used to store these addresses. - if (InlineTypeReturnedAsFields || InlineTypePassFieldsAsArgs) { + if (ValueTypeReturnedAsFields || ValueTypePassFieldsAsArgs) { ResourceMark rm; GrowableArray sig_vk; int nb_fields = collect_fields(&sig_vk); - if (*PrintInlineKlassFields != '\0') { + if (*PrintValueKlassFields != '\0') { const char* class_name_str = _name->as_C_string(); - if (StringUtils::class_list_match(PrintInlineKlassFields, class_name_str)) { + if (StringUtils::class_list_match(PrintValueKlassFields, class_name_str)) { ttyLocker ttyl; - tty->print_cr("Fields of InlineKlass: %s", class_name_str); + tty->print_cr("Fields of ValueKlass: %s", class_name_str); for (const SigEntry& entry : sig_vk) { tty->print(" %s: %s+%d", entry._name->as_C_string(), type2name(entry._bt), entry._offset); if (entry._null_marker) { @@ -264,7 +264,7 @@ void InlineKlass::initialize_calling_convention(TRAPS) { return_regs->at_put(i, regs[i]); } - BufferedInlineTypeBlob* buffered_blob = SharedRuntime::generate_buffered_inline_type_adapter(this); + BufferedValueTypeBlob* buffered_blob = SharedRuntime::generate_buffered_value_type_adapter(this); if (buffered_blob == nullptr) { THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "Out of space in CodeCache for adapters"); } @@ -283,7 +283,7 @@ void InlineKlass::initialize_calling_convention(TRAPS) { } } -void InlineKlass::deallocate_contents(ClassLoaderData* loader_data) { +void ValueKlass::deallocate_contents(ClassLoaderData* loader_data) { if (extended_sig() != nullptr) { MetadataFactory::free_array(loader_data, members()._extended_sig); set_extended_sig(nullptr); @@ -296,14 +296,14 @@ void InlineKlass::deallocate_contents(ClassLoaderData* loader_data) { InstanceKlass::deallocate_contents(loader_data); } -void InlineKlass::cleanup(InlineKlass* ik) { - ik->cleanup_blobs(); +void ValueKlass::cleanup(ValueKlass* vk) { + vk->cleanup_blobs(); } -void InlineKlass::cleanup_blobs() { +void ValueKlass::cleanup_blobs() { if (pack_handler() != nullptr) { CodeBlob* buffered_blob = CodeCache::find_blob(pack_handler()); - assert(buffered_blob->is_buffered_inline_type_blob(), "bad blob type"); + assert(buffered_blob->is_buffered_value_type_blob(), "bad blob type"); BufferBlob::free((BufferBlob*)buffered_blob); set_pack_handler(nullptr); set_pack_handler_jobject(nullptr); @@ -311,18 +311,18 @@ void InlineKlass::cleanup_blobs() { } } -// Can this inline type be passed as multiple values? -bool InlineKlass::can_be_passed_as_fields() const { - return InlineTypePassFieldsAsArgs; +// Can this value type be passed as multiple values? +bool ValueKlass::can_be_passed_as_fields() const { + return ValueTypePassFieldsAsArgs; } -// Can this inline type be returned as multiple values? -bool InlineKlass::can_be_returned_as_fields(bool init) const { - return InlineTypeReturnedAsFields && (init || return_regs() != nullptr); +// Can this value type be returned as multiple values? +bool ValueKlass::can_be_returned_as_fields(bool init) const { + return ValueTypeReturnedAsFields && (init || return_regs() != nullptr); } // Create handles for all oop fields returned in registers that are going to be live across a safepoint -void InlineKlass::save_oop_fields(const RegisterMap& reg_map, GrowableArray& handles) const { +void ValueKlass::save_oop_fields(const RegisterMap& reg_map, GrowableArray& handles) const { Thread* thread = Thread::current(); const Array* sig_vk = extended_sig(); const Array* regs = return_regs(); @@ -352,8 +352,8 @@ void InlineKlass::save_oop_fields(const RegisterMap& reg_map, GrowableArray& handles) const { - assert(InlineTypeReturnedAsFields, "Inline types should never be returned as fields"); +void ValueKlass::restore_oop_results(RegisterMap& reg_map, GrowableArray& handles) const { + assert(ValueTypeReturnedAsFields, "Value types should never be returned as fields"); const Array* sig_vk = extended_sig(); const Array* regs = return_regs(); assert(regs != nullptr, "inconsistent"); @@ -382,9 +382,9 @@ void InlineKlass::restore_oop_results(RegisterMap& reg_map, GrowableArraylength(), "missed a field?"); } -// Fields are in registers. Create an instance of the inline type and +// Fields are in registers. Create an instance of the value type and // initialize it with the values of the fields. -oop InlineKlass::realloc_result(const RegisterMap& reg_map, const GrowableArray& handles, TRAPS) { +oop ValueKlass::realloc_result(const RegisterMap& reg_map, const GrowableArray& handles, TRAPS) { oop new_vt = allocate_instance(CHECK_NULL); const Array* sig_vk = extended_sig(); const Array* regs = return_regs(); @@ -458,10 +458,10 @@ oop InlineKlass::realloc_result(const RegisterMap& reg_map, const GrowableArray< return new_vt; } -// Check if we return an inline type in scalarized form, i.e. check if either -// - The return value is a tagged InlineKlass pointer, or -// - The return value is an inline type oop that is also returned in scalarized form -InlineKlass* InlineKlass::returned_inline_klass(const RegisterMap& map, bool* return_oop, Method* method) { +// Check if we return a value type in scalarized form, i.e. check if either +// - The return value is a tagged ValueKlass pointer, or +// - The return value is a value type oop that is also returned in scalarized form +ValueKlass* ValueKlass::returned_value_klass(const RegisterMap& map, bool* return_oop, Method* method) { BasicType bt = T_METADATA; VMRegPair pair; int nb = SharedRuntime::java_return_convention(&bt, &pair, 1); @@ -471,10 +471,10 @@ InlineKlass* InlineKlass::returned_inline_klass(const RegisterMap& map, bool* re guarantee(loc != nullptr, "bad register save location"); intptr_t ptr = *loc; if (is_set_nth_bit(ptr, 0)) { - // Return value is tagged, must be an InlineKlass pointer + // Return value is tagged, must be an ValueKlass pointer clear_nth_bit(ptr, 0); assert(Metaspace::contains((void*)ptr), "should be klass"); - InlineKlass* vk = (InlineKlass*)ptr; + ValueKlass* vk = (ValueKlass*)ptr; assert(vk->can_be_returned_as_fields(), "must be able to return as fields"); if (return_oop != nullptr) { // Not returning an oop @@ -485,10 +485,10 @@ InlineKlass* InlineKlass::returned_inline_klass(const RegisterMap& map, bool* re // Return value is not tagged, must be a valid oop oop o = cast_to_oop(ptr); assert(oopDesc::is_oop_or_null(o), "Bad oop return: " PTR_FORMAT, ptr); - if (return_oop != nullptr && o != nullptr && o->is_inline_type()) { - // Check if inline type is also returned in scalarized form - InlineKlass* vk_val = InlineKlass::cast(o->klass()); - InlineKlass* vk_sig = method->returns_inline_type(); + if (return_oop != nullptr && o != nullptr && o->is_value_type()) { + // Check if value type is also returned in scalarized form + ValueKlass* vk_val = ValueKlass::cast(o->klass()); + ValueKlass* vk_sig = method->returns_value_type(); if (vk_val->can_be_returned_as_fields() && vk_sig != nullptr) { assert(vk_val == vk_sig, "Unexpected return value"); return vk_val; @@ -500,12 +500,12 @@ InlineKlass* InlineKlass::returned_inline_klass(const RegisterMap& map, bool* re // CDS support #if INCLUDE_CDS -void InlineKlass::remove_unshareable_info() { +void ValueKlass::remove_unshareable_info() { InstanceKlass::remove_unshareable_info(); // update it to point to the "buffered" copy of this class. - _adr_inline_klass_members = calculate_members_address(); - ArchivePtrMarker::mark_pointer(&_adr_inline_klass_members); + _adr_value_klass_members = calculate_members_address(); + ArchivePtrMarker::mark_pointer(&_adr_value_klass_members); set_extended_sig(nullptr); set_return_regs(nullptr); @@ -520,7 +520,7 @@ void InlineKlass::remove_unshareable_info() { #define BULLET " - " -void InlineKlass::print_on(outputStream* st) const { +void ValueKlass::print_on(outputStream* st) const { InstanceKlass::print_on(st); members().print_on(st); st->print_cr(BULLET"---- LayoutKinds:"); @@ -543,18 +543,18 @@ void InlineKlass::print_on(outputStream* st) const { // Verification -void InlineKlass::verify_on(outputStream* st) { +void ValueKlass::verify_on(outputStream* st) { InstanceKlass::verify_on(st); - guarantee(prototype_header().is_inline_type(), "Prototype header is not inline type"); + guarantee(prototype_header().is_value_type(), "Prototype header is not value type"); } -void InlineKlass::oop_verify_on(oop obj, outputStream* st) { +void ValueKlass::oop_verify_on(oop obj, outputStream* st) { InstanceKlass::oop_verify_on(obj, st); - guarantee(obj->mark().is_inline_type(), "Header is not inline type"); + guarantee(obj->mark().is_value_type(), "Header is not value type"); } -void InlineKlass::Members::print_on(outputStream* st) const { - st->print_cr(BULLET"---- inline type members:"); +void ValueKlass::Members::print_on(outputStream* st) const { + st->print_cr(BULLET"---- value type members:"); st->print(BULLET"extended signature registers: "); InstanceKlass::print_array_on(st, _extended_sig, [](outputStream* ost, SigEntry pair){ pair.print_on(ost); diff --git a/src/hotspot/share/oops/inlineKlass.hpp b/src/hotspot/share/oops/valueKlass.hpp similarity index 91% rename from src/hotspot/share/oops/inlineKlass.hpp rename to src/hotspot/share/oops/valueKlass.hpp index 97ef09a9d540..b39db26eda96 100644 --- a/src/hotspot/share/oops/inlineKlass.hpp +++ b/src/hotspot/share/oops/valueKlass.hpp @@ -22,13 +22,13 @@ * */ -#ifndef SHARE_VM_OOPS_INLINEKLASS_HPP -#define SHARE_VM_OOPS_INLINEKLASS_HPP +#ifndef SHARE_VM_OOPS_VALUEKLASS_HPP +#define SHARE_VM_OOPS_VALUEKLASS_HPP -#include "oops/inlineOop.hpp" #include "oops/instanceKlass.hpp" #include "oops/layoutKind.hpp" #include "oops/oopsHierarchy.hpp" +#include "oops/valueOop.hpp" #include "oops/valuePayload.hpp" #include "runtime/handles.hpp" #include "utilities/exceptions.hpp" @@ -43,17 +43,17 @@ class Method; class RegisterMap; class SigEntry; -// An InlineKlass is a specialized InstanceKlass for concrete value classes +// A ValueKlass is a specialized InstanceKlass for concrete value classes // (abstract value classes are represented by InstanceKlass) -class InlineKlass: public InstanceKlass { +class ValueKlass: public InstanceKlass { friend class VMStructs; friend class InstanceKlass; public: - static const KlassKind Kind = InlineKlassKind; + static const KlassKind Kind = ValueKlassKind; - // The member fields of the InlineKlass. + // The member fields of the ValueKlass. // // All Klass objects have vtables starting at offset `sizeof(InstanceKlass)`. // @@ -65,7 +65,7 @@ class InlineKlass: public InstanceKlass { // dynamically-sized sections belonging to the InstanceKlass part of the // object. // - // InlineKlass object layout: + // ValueKlass object layout: // +-----------------------+ // | sizeof(InstanceKlass) | // +-----------------------+ <= InstanceKlass:header_size() @@ -73,13 +73,13 @@ class InlineKlass: public InstanceKlass { // +-----------------------+ // | other sections | // +-----------------------+ <= end_of_instance_klass() - // | InlineKlass::Members | + // | ValueKlass::Members | // +-----------------------+ // class Members { - friend class InlineKlass; + friend class ValueKlass; - // Addresses used for inline type calling convention + // Addresses used for value type calling convention Array* _extended_sig; Array* _return_regs; @@ -173,30 +173,30 @@ class InlineKlass: public InstanceKlass { void print_on(outputStream* st) const; }; - InlineKlass(); + ValueKlass(); private: // Constructor - InlineKlass(const ClassFileParser& parser); + ValueKlass(const ClassFileParser& parser); // Calculates where the members are supposed to be placed address calculate_members_address() const; Members& members() { - assert(_adr_inline_klass_members != nullptr, "Should have been initialized"); - return *reinterpret_cast(_adr_inline_klass_members); + assert(_adr_value_klass_members != nullptr, "Should have been initialized"); + return *reinterpret_cast(_adr_value_klass_members); } inline const Members& members() const { - InlineKlass* ik = const_cast(this); - return const_cast(ik->members()); + ValueKlass* vk = const_cast(this); + return const_cast(vk->members()); } public: - bool is_empty_inline_type() const { return _misc_flags.is_empty_inline_type(); } - void set_is_empty_inline_type() { _misc_flags.set_is_empty_inline_type(true); } + bool is_empty_value_type() const { return _misc_flags.is_empty_value_type(); } + void set_is_empty_value_type() { _misc_flags.set_is_empty_value_type(true); } // Members access functions @@ -206,7 +206,7 @@ class InlineKlass: public InstanceKlass { const Array* return_regs() const { return members()._return_regs; } void set_return_regs(Array* return_regs) { members()._return_regs = return_regs; } - // pack and unpack handlers for inline types return + // pack and unpack handlers for value types return address pack_handler() const { return members()._pack_handler; } void set_pack_handler(address pack_handler) { members()._pack_handler = pack_handler; } @@ -314,23 +314,23 @@ class InlineKlass: public InstanceKlass { public: // Type testing - bool is_inline_klass_slow() const override { return true; } + bool is_value_klass_slow() const override { return true; } // Casting from Klass* - static InlineKlass* cast(Klass* k) { - return const_cast(cast(const_cast(k))); + static ValueKlass* cast(Klass* k) { + return const_cast(cast(const_cast(k))); } - static const InlineKlass* cast(const Klass* k) { + static const ValueKlass* cast(const Klass* k) { assert(k != nullptr, "k should not be null"); - assert(k->is_inline_klass(), "cast to InlineKlass"); - return static_cast(k); + assert(k->is_value_klass(), "cast to ValueKlass"); + return static_cast(k); } // Allocates a stand alone value in the Java heap // initialized to default value (cleared memory) - inlineOop allocate_instance(TRAPS); + valueOop allocate_instance(TRAPS); address payload_addr(oop o) const; @@ -359,10 +359,10 @@ class InlineKlass: public InstanceKlass { void save_oop_fields(const RegisterMap& map, GrowableArray& handles) const; void restore_oop_results(RegisterMap& map, GrowableArray& handles) const; oop realloc_result(const RegisterMap& reg_map, const GrowableArray& handles, TRAPS); - static InlineKlass* returned_inline_klass(const RegisterMap& reg_map, bool* return_oop = nullptr, Method* method = nullptr); + static ValueKlass* returned_value_klass(const RegisterMap& reg_map, bool* return_oop = nullptr, Method* method = nullptr); static ByteSize adr_members_offset() { - return InstanceKlass::adr_inline_klass_members_offset(); + return InstanceKlass::adr_value_klass_members_offset(); } // pack and unpack handlers. Need to be loadable from generated code @@ -411,7 +411,7 @@ class InlineKlass: public InstanceKlass { void set_null_reset_value(oop val); void deallocate_contents(ClassLoaderData* loader_data); - static void cleanup(InlineKlass* ik) ; + static void cleanup(ValueKlass* ik) ; void print_on(outputStream* st) const override; @@ -420,4 +420,4 @@ class InlineKlass: public InstanceKlass { void oop_verify_on(oop obj, outputStream* st) override; }; -#endif // SHARE_VM_OOPS_INLINEKLASS_HPP +#endif // SHARE_VM_OOPS_VALUEKLASS_HPP diff --git a/src/hotspot/share/oops/inlineKlass.inline.hpp b/src/hotspot/share/oops/valueKlass.inline.hpp similarity index 86% rename from src/hotspot/share/oops/inlineKlass.inline.hpp rename to src/hotspot/share/oops/valueKlass.inline.hpp index 96882dd2f5cd..c8525a87e3b5 100644 --- a/src/hotspot/share/oops/inlineKlass.inline.hpp +++ b/src/hotspot/share/oops/valueKlass.inline.hpp @@ -21,23 +21,23 @@ * questions. * */ -#ifndef SHARE_VM_OOPS_INLINEKLASS_INLINE_HPP -#define SHARE_VM_OOPS_INLINEKLASS_INLINE_HPP +#ifndef SHARE_VM_OOPS_VALUEKLASS_INLINE_HPP +#define SHARE_VM_OOPS_VALUEKLASS_INLINE_HPP -#include "oops/inlineKlass.hpp" +#include "oops/valueKlass.hpp" #include "oops/valuePayload.inline.hpp" #include "runtime/handles.hpp" #include "utilities/debug.hpp" #include "utilities/devirtualizer.inline.hpp" -inline bool InlineKlass::layout_has_null_marker(LayoutKind lk) const { +inline bool ValueKlass::layout_has_null_marker(LayoutKind lk) const { assert(is_layout_supported(lk), "Must be"); return LayoutKindHelper::is_nullable_flat(lk) || (lk == LayoutKind::BUFFERED && supports_nullable_layouts()); } -inline bool InlineKlass::is_layout_supported(LayoutKind lk) const { +inline bool ValueKlass::is_layout_supported(LayoutKind lk) const { switch(lk) { case LayoutKind::NULL_FREE_NON_ATOMIC_FLAT: return has_null_free_non_atomic_layout(); @@ -59,7 +59,7 @@ inline bool InlineKlass::is_layout_supported(LayoutKind lk) const { } } -inline int InlineKlass::layout_size_in_bytes(LayoutKind kind) const { +inline int ValueKlass::layout_size_in_bytes(LayoutKind kind) const { switch(kind) { case LayoutKind::NULL_FREE_NON_ATOMIC_FLAT: assert(has_null_free_non_atomic_layout(), "Layout not available"); @@ -85,7 +85,7 @@ inline int InlineKlass::layout_size_in_bytes(LayoutKind kind) const { } } -inline int InlineKlass::layout_alignment(LayoutKind kind) const { +inline int ValueKlass::layout_alignment(LayoutKind kind) const { switch(kind) { case LayoutKind::NULL_FREE_NON_ATOMIC_FLAT: assert(has_null_free_non_atomic_layout(), "Layout not available"); @@ -111,12 +111,12 @@ inline int InlineKlass::layout_alignment(LayoutKind kind) const { } } -inline address InlineKlass::payload_addr(oop o) const { +inline address ValueKlass::payload_addr(oop o) const { return cast_from_oop
(o) + payload_offset(); } template -void InlineKlass::oop_iterate_value_payload_f(address payload, Function function) { +void ValueKlass::oop_iterate_value_payload_f(address payload, Function function) { OopMapBlock* map = start_of_nonstatic_oop_maps(); OopMapBlock* const end_map = map + nonstatic_oop_map_count(); @@ -135,14 +135,14 @@ void InlineKlass::oop_iterate_value_payload_f(address payload, Function function } template -void InlineKlass::oop_iterate_value_payload(address payload, OopClosureType* closure) { +void ValueKlass::oop_iterate_value_payload(address payload, OopClosureType* closure) { oop_iterate_value_payload_f(payload, [&](T* p) { Devirtualizer::do_oop(closure, p); }); } template -inline void InlineKlass::oop_iterate_value_payload_bounded(address payload, OopClosureType* closure, uintptr_t lo, uintptr_t hi) { +inline void ValueKlass::oop_iterate_value_payload_bounded(address payload, OopClosureType* closure, uintptr_t lo, uintptr_t hi) { OopMapBlock* map = start_of_nonstatic_oop_maps(); OopMapBlock* const end_map = map + nonstatic_oop_map_count(); @@ -169,4 +169,4 @@ inline void InlineKlass::oop_iterate_value_payload_bounded(address payload, OopC } } -#endif // SHARE_VM_OOPS_INLINEKLASS_INLINE_HPP +#endif // SHARE_VM_OOPS_VALUEKLASS_INLINE_HPP diff --git a/src/hotspot/share/oops/inlineOop.hpp b/src/hotspot/share/oops/valueOop.hpp similarity index 79% rename from src/hotspot/share/oops/inlineOop.hpp rename to src/hotspot/share/oops/valueOop.hpp index d466ec95a837..c76af42e5d99 100644 --- a/src/hotspot/share/oops/inlineOop.hpp +++ b/src/hotspot/share/oops/valueOop.hpp @@ -22,17 +22,17 @@ * */ -#ifndef SHARE_OOPS_INLINEOOP_HPP -#define SHARE_OOPS_INLINEOOP_HPP +#ifndef SHARE_OOPS_VALUEOOP_HPP +#define SHARE_OOPS_VALUEOOP_HPP #include "oops/instanceOop.hpp" -// A buffered object of a java value class InlineKlass. -class inlineOopDesc : public instanceOopDesc { +// A buffered object of a java value. +class valueOopDesc : public instanceOopDesc { }; // See similar requirement for instanceOopDesc. -static_assert(std::is_trivially_default_constructible::value, "required"); +static_assert(std::is_trivially_default_constructible::value, "required"); -#endif // SHARE_OOPS_INLINEOOP_HPP +#endif // SHARE_OOPS_VALUEOOP_HPP diff --git a/src/hotspot/share/oops/valuePayload.hpp b/src/hotspot/share/oops/valuePayload.hpp index f63e1b318b70..1e742729bbee 100644 --- a/src/hotspot/share/oops/valuePayload.hpp +++ b/src/hotspot/share/oops/valuePayload.hpp @@ -25,11 +25,11 @@ #ifndef SHARE_VM_OOPS_VALUEPAYLOAD_HPP #define SHARE_VM_OOPS_VALUEPAYLOAD_HPP -#include "oops/inlineOop.hpp" #include "oops/instanceKlass.hpp" #include "oops/layoutKind.hpp" #include "oops/oopHandle.hpp" #include "oops/oopsHierarchy.hpp" +#include "oops/valueOop.hpp" #include "runtime/handles.hpp" #include "utilities/exceptions.hpp" #include "utilities/globalDefinitions.hpp" @@ -52,7 +52,7 @@ class ValuePayload { }; address _absolute_addr; }; - InlineKlass* _klass; + ValueKlass* _klass; LayoutKind _layout_kind; bool _uses_absolute_addr; @@ -60,10 +60,10 @@ class ValuePayload { inline StorageImpl(); inline StorageImpl(OopOrHandle container, ptrdiff_t offset, - InlineKlass* klass, + ValueKlass* klass, LayoutKind layout_kind); inline StorageImpl(address absolute_addr, - InlineKlass* klass, + ValueKlass* klass, LayoutKind layout_kind); inline ~StorageImpl(); inline StorageImpl(const StorageImpl& other); @@ -78,7 +78,7 @@ class ValuePayload { inline address& absolute_addr(); inline address absolute_addr() const; - inline InlineKlass* klass() const; + inline ValueKlass* klass() const; inline LayoutKind layout_kind() const; @@ -99,12 +99,12 @@ class ValuePayload { // Constructed from parts container and offset inline ValuePayload(oop container, ptrdiff_t offset, - InlineKlass* klass, + ValueKlass* klass, LayoutKind layout_kind); // Constructed from parts absolute_addr inline ValuePayload(address absolute_addr, - InlineKlass* klass, + ValueKlass* klass, LayoutKind layout_kind); inline void set_offset(ptrdiff_t offset); @@ -131,7 +131,7 @@ class ValuePayload { LayoutKind copy_layout_kind) NOT_DEBUG_RETURN; public: - inline InlineKlass* klass() const; + inline ValueKlass* klass() const; inline ptrdiff_t offset() const; inline LayoutKind layout_kind() const; @@ -144,7 +144,7 @@ class ValuePayload { class OopHandle; [[nodiscard]] static inline ValuePayload construct_from_parts(address absolute_addr, - InlineKlass* klass, + ValueKlass* klass, LayoutKind layout_kind); }; @@ -152,9 +152,9 @@ class BufferedValuePayload : public ValuePayload { friend class FlatValuePayload; private: - inline BufferedValuePayload(inlineOop container, + inline BufferedValuePayload(valueOop container, ptrdiff_t offset, - InlineKlass* klass, + ValueKlass* klass, LayoutKind layout_kind); public: @@ -162,10 +162,10 @@ class BufferedValuePayload : public ValuePayload { BufferedValuePayload(const BufferedValuePayload&) = default; BufferedValuePayload& operator=(const BufferedValuePayload&) = default; - explicit inline BufferedValuePayload(inlineOop buffer); - inline BufferedValuePayload(inlineOop buffer, InlineKlass* klass); + explicit inline BufferedValuePayload(valueOop buffer); + inline BufferedValuePayload(valueOop buffer, ValueKlass* klass); - inline inlineOop container() const; + inline valueOop container() const; inline void copy_to(const BufferedValuePayload& dst); @@ -180,11 +180,11 @@ class FlatValuePayload : public ValuePayload { protected: inline FlatValuePayload(oop container, ptrdiff_t offset, - InlineKlass* klass, + ValueKlass* klass, LayoutKind layout_kind); private: - inline inlineOop allocate_instance(TRAPS); + inline valueOop allocate_instance(TRAPS); public: FlatValuePayload() = default; @@ -196,13 +196,13 @@ class FlatValuePayload : public ValuePayload { inline void copy_to(const FlatValuePayload& dst); - [[nodiscard]] inline inlineOop read(TRAPS); - inline void write_without_nullability_check(inlineOop obj); - inline void write(inlineOop obj, TRAPS); + [[nodiscard]] inline valueOop read(TRAPS); + inline void write_without_nullability_check(valueOop obj); + inline void write(valueOop obj, TRAPS); [[nodiscard]] static inline FlatValuePayload construct_from_parts(oop container, ptrdiff_t offset, - InlineKlass* klass, + ValueKlass* klass, LayoutKind layout_kind); class Handle; @@ -216,12 +216,12 @@ class FlatFieldPayload : public FlatValuePayload { private: inline FlatFieldPayload(instanceOop container, ptrdiff_t offset, - InlineKlass* klass, + ValueKlass* klass, LayoutKind layout_kind); inline FlatFieldPayload(instanceOop container, ptrdiff_t offset, - InlineLayoutInfo* inline_layout_info); + ValueFieldLayoutInfo* layout_info); inline void assert_post_construction_invariants(instanceOop container, ResolvedFieldEntry* resolved_field_entry) const NOT_DEBUG_RETURN; @@ -255,7 +255,7 @@ class FlatArrayPayload : public FlatValuePayload { inline FlatArrayPayload(flatArrayOop container, ptrdiff_t offset, - InlineKlass* klass, + ValueKlass* klass, LayoutKind layout_kind, jint layout_helper, int element_size); @@ -306,7 +306,7 @@ class ValuePayload::Handle { Handle(const Handle&) = default; Handle& operator=(const Handle&) = default; - inline InlineKlass* klass() const; + inline ValueKlass* klass() const; inline ptrdiff_t offset() const; inline LayoutKind layout_kind() const; }; @@ -329,7 +329,7 @@ class ValuePayload::OopHandle { inline void release(OopStorage* storage); - inline InlineKlass* klass() const; + inline ValueKlass* klass() const; inline ptrdiff_t offset() const; inline LayoutKind layout_kind() const; }; @@ -340,7 +340,7 @@ class BufferedValuePayload::Handle : public ValuePayload::Handle { inline BufferedValuePayload operator()() const; - inline inlineOop container() const; + inline valueOop container() const; }; class BufferedValuePayload::OopHandle : public ValuePayload::OopHandle { @@ -349,7 +349,7 @@ class BufferedValuePayload::OopHandle : public ValuePayload::OopHandle { inline BufferedValuePayload operator()() const; - inline inlineOop container() const; + inline valueOop container() const; }; class FlatValuePayload::Handle : public ValuePayload::Handle { diff --git a/src/hotspot/share/oops/valuePayload.inline.hpp b/src/hotspot/share/oops/valuePayload.inline.hpp index 82d728e1a45e..4a1f567c945c 100644 --- a/src/hotspot/share/oops/valuePayload.inline.hpp +++ b/src/hotspot/share/oops/valuePayload.inline.hpp @@ -30,11 +30,11 @@ #include "cppstdlib/type_traits.hpp" #include "oops/flatArrayKlass.inline.hpp" #include "oops/flatArrayOop.inline.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/layoutKind.hpp" #include "oops/oopHandle.inline.hpp" #include "oops/oopsHierarchy.hpp" #include "oops/resolvedFieldEntry.hpp" +#include "oops/valueKlass.inline.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaThread.inline.hpp" @@ -53,7 +53,7 @@ inline ValuePayload::StorageImpl::StorageImpl() template inline ValuePayload::StorageImpl::StorageImpl(OopOrHandle container, ptrdiff_t offset, - InlineKlass* klass, + ValueKlass* klass, LayoutKind layout_kind) : _container(container), _offset(offset), @@ -63,7 +63,7 @@ inline ValuePayload::StorageImpl::StorageImpl(OopOrHandle container template inline ValuePayload::StorageImpl::StorageImpl(address absolute_addr, - InlineKlass* klass, + ValueKlass* klass, LayoutKind layout_kind) : _absolute_addr(absolute_addr), _klass(klass), @@ -149,7 +149,7 @@ inline address ValuePayload::StorageImpl::absolute_addr() const { } template -inline InlineKlass* ValuePayload::StorageImpl::klass() const { +inline ValueKlass* ValuePayload::StorageImpl::klass() const { return _klass; } @@ -165,14 +165,14 @@ inline bool ValuePayload::StorageImpl::uses_absolute_addr() const { inline ValuePayload::ValuePayload(oop container, ptrdiff_t offset, - InlineKlass* klass, + ValueKlass* klass, LayoutKind layout_kind) : _storage{container, offset, klass, layout_kind} { assert_post_construction_invariants(); } inline ValuePayload::ValuePayload(address absolute_addr, - InlineKlass* klass, + ValueKlass* klass, LayoutKind layout_kind) : _storage{absolute_addr, klass, layout_kind} { assert_post_construction_invariants(); @@ -187,7 +187,7 @@ inline void ValuePayload::copy(const ValuePayload& src, LayoutKind copy_layout_kind) { assert_pre_copy_invariants(src, dst, copy_layout_kind); - InlineKlass* const klass = src.klass(); + ValueKlass* const klass = src.klass(); switch (copy_layout_kind) { case LayoutKind::NULLABLE_ATOMIC_FLAT: @@ -201,7 +201,7 @@ inline void ValuePayload::copy(const ValuePayload& src, case LayoutKind::BUFFERED: case LayoutKind::NULL_FREE_ATOMIC_FLAT: case LayoutKind::NULL_FREE_NON_ATOMIC_FLAT: { - if (!klass->is_empty_inline_type()) { + if (!klass->is_empty_value_type()) { HeapAccess<>::value_copy(src, dst); } } break; @@ -257,7 +257,7 @@ inline void ValuePayload::print_on(outputStream* st) const { } } { - InlineKlass* const klass = _storage.klass(); + ValueKlass* const klass = _storage.klass(); st->print_cr("--- klass ---"); StreamIndentor si(st); st->print_cr("_klass: " PTR_FORMAT, p2i(klass)); @@ -289,29 +289,29 @@ inline void ValuePayload::assert_is_flat_field(const InstanceKlass* klass, int o fieldDescriptor field_descriptor; postcond(klass->find_flat_field_containing_offset(offset, &field_descriptor)); - const InlineLayoutInfo inline_layout_info = field_descriptor.field_holder()->inline_layout_info(field_descriptor.index()); + const ValueFieldLayoutInfo value_field_layout_info = field_descriptor.field_holder()->value_field_layout_info(field_descriptor.index()); - OnVMError on_assertion_failure_inline_layout_info([&](outputStream* st) { + OnVMError on_assertion_failure_value_field_layout_info([&](outputStream* st) { st->print_cr("=== assert_is_flat_field(" PTR_FORMAT ", %d) failure ===", p2i(klass), offset); StreamIndentor si(st); st->print("field_descriptor: "); field_descriptor.print_on(st); st->cr(); - st->print("inline_layout_info: "); - inline_layout_info.print_on(st); + st->print("value_field_layout_info: "); + value_field_layout_info.print_on(st); st->cr(); }); - if (inline_layout_info.klass() == this->klass()) { + if (value_field_layout_info.klass() == this->klass()) { // Found the field in klass postcond(offset == field_descriptor.offset()); - postcond(inline_layout_info.kind() == layout_kind()); + postcond(value_field_layout_info.kind() == layout_kind()); postcond(field_descriptor.layout_kind() == layout_kind()); postcond(field_descriptor.is_flat()); } else { // Nested flat field postcond(offset >= field_descriptor.offset()); - const InlineKlass* const field_klass = inline_layout_info.klass(); + const ValueKlass* const field_klass = value_field_layout_info.klass(); const int payload_offset = field_klass->payload_offset(); assert_is_flat_field(field_klass, offset - field_descriptor.offset() + payload_offset); } @@ -346,7 +346,7 @@ inline void ValuePayload::assert_post_construction_invariants() const { postcond(container_flat_array_klass->layout_kind() == layout_kind()); } else { // Accessing nested flat field - const InlineKlass* const element_klass = container_flat_array_klass->element_klass(); + const ValueKlass* const element_klass = container_flat_array_klass->element_klass(); const int element_offset = (checked_cast(this->offset()) - checked_cast(flatArrayOopDesc::base_offset_in_bytes())) % @@ -385,8 +385,8 @@ inline void ValuePayload::assert_pre_copy_invariants(const ValuePayload& src, } }); - const InlineKlass* const src_klass = src.klass(); - const InlineKlass* const dst_klass = dst.klass(); + const ValueKlass* const src_klass = src.klass(); + const ValueKlass* const dst_klass = dst.klass(); precond(src_klass == dst_klass); @@ -422,7 +422,7 @@ inline void ValuePayload::assert_pre_copy_invariants(const ValuePayload& src, #endif // ASSERT -inline InlineKlass* ValuePayload::klass() const { +inline ValueKlass* ValuePayload::klass() const { return _storage.klass(); } @@ -450,26 +450,26 @@ inline bool ValuePayload::is_payload_null() const { } inline ValuePayload ValuePayload::construct_from_parts(address absolute_addr, - InlineKlass* klass, + ValueKlass* klass, LayoutKind layout_kind) { return ValuePayload(absolute_addr, klass, layout_kind); } -inline BufferedValuePayload::BufferedValuePayload(inlineOop container, +inline BufferedValuePayload::BufferedValuePayload(valueOop container, ptrdiff_t offset, - InlineKlass* klass, + ValueKlass* klass, LayoutKind layout_kind) : ValuePayload(container, offset, klass, layout_kind) {} -inline BufferedValuePayload::BufferedValuePayload(inlineOop buffer) - : BufferedValuePayload(buffer, InlineKlass::cast(buffer->klass())) {} +inline BufferedValuePayload::BufferedValuePayload(valueOop buffer) + : BufferedValuePayload(buffer, ValueKlass::cast(buffer->klass())) {} -inline BufferedValuePayload::BufferedValuePayload(inlineOop buffer, - InlineKlass* klass) +inline BufferedValuePayload::BufferedValuePayload(valueOop buffer, + ValueKlass* klass) : ValuePayload(buffer, klass->payload_offset(), klass, LayoutKind::BUFFERED) {} -inline inlineOop BufferedValuePayload::container() const { - return inlineOop(ValuePayload::container()); +inline valueOop BufferedValuePayload::container() const { + return valueOop(ValuePayload::container()); } inline void BufferedValuePayload::copy_to(const BufferedValuePayload& dst) { @@ -478,15 +478,15 @@ inline void BufferedValuePayload::copy_to(const BufferedValuePayload& dst) { inline FlatValuePayload::FlatValuePayload(oop container, ptrdiff_t offset, - InlineKlass* klass, + ValueKlass* klass, LayoutKind layout_kind) : ValuePayload(container, offset, klass, layout_kind) {} -inline inlineOop FlatValuePayload::allocate_instance(TRAPS) { +inline valueOop FlatValuePayload::allocate_instance(TRAPS) { // Preserve the container oop across the instance allocation. oop& container = this->container(); ::Handle container_handle(THREAD, container); - inlineOop res = klass()->allocate_instance(THREAD); + valueOop res = klass()->allocate_instance(THREAD); container = container_handle(); return res; } @@ -530,7 +530,7 @@ inline void FlatValuePayload::copy_to(const FlatValuePayload& dst) { copy(*this, dst, layout_kind()); } -inline inlineOop FlatValuePayload::read(TRAPS) { +inline valueOop FlatValuePayload::read(TRAPS) { switch (layout_kind()) { case LayoutKind::NULLABLE_ATOMIC_FLAT: case LayoutKind::NULLABLE_NON_ATOMIC_FLAT: { @@ -540,7 +540,7 @@ inline inlineOop FlatValuePayload::read(TRAPS) { } // Fallthrough case LayoutKind::NULL_FREE_ATOMIC_FLAT: case LayoutKind::NULL_FREE_NON_ATOMIC_FLAT: { - inlineOop res = allocate_instance(CHECK_NULL); + valueOop res = allocate_instance(CHECK_NULL); BufferedValuePayload dst(res, klass()); if (!copy_to(dst)) { // copy_to may fail if the payload has been updated with a null value @@ -558,7 +558,7 @@ inline inlineOop FlatValuePayload::read(TRAPS) { } } -inline void FlatValuePayload::write_without_nullability_check(inlineOop obj) { +inline void FlatValuePayload::write_without_nullability_check(valueOop obj) { if (obj == nullptr) { assert(has_null_marker(), "Payload must support null values"); HeapAccess<>::value_store_null(*this); @@ -569,7 +569,7 @@ inline void FlatValuePayload::write_without_nullability_check(inlineOop obj) { } } -inline void FlatValuePayload::write(inlineOop obj, TRAPS) { +inline void FlatValuePayload::write(valueOop obj, TRAPS) { if (obj == nullptr && !has_null_marker()) { // This payload does not have a null marker and cannot represent a null // value. @@ -580,21 +580,21 @@ inline void FlatValuePayload::write(inlineOop obj, TRAPS) { inline FlatValuePayload FlatValuePayload::construct_from_parts(oop container, ptrdiff_t offset, - InlineKlass* klass, + ValueKlass* klass, LayoutKind layout_kind) { return FlatValuePayload(container, offset, klass, layout_kind); } inline FlatFieldPayload::FlatFieldPayload(instanceOop container, ptrdiff_t offset, - InlineKlass* klass, + ValueKlass* klass, LayoutKind layout_kind) : FlatValuePayload(container, offset, klass, layout_kind) {} inline FlatFieldPayload::FlatFieldPayload(instanceOop container, ptrdiff_t offset, - InlineLayoutInfo* inline_layout_info) - : FlatValuePayload(container, offset, inline_layout_info->klass(), inline_layout_info->kind()) {} + ValueFieldLayoutInfo* layout_info) + : FlatValuePayload(container, offset, layout_info->klass(), layout_info->kind()) {} #ifdef ASSERT @@ -630,7 +630,7 @@ inline FlatFieldPayload::FlatFieldPayload(instanceOop container, fieldDescriptor* field_descriptor) : FlatFieldPayload(container, field_descriptor->offset(), - field_descriptor->field_holder()->inline_layout_info_adr(field_descriptor->index())) { + field_descriptor->field_holder()->value_field_layout_info_adr(field_descriptor->index())) { assert_post_construction_invariants(container, field_descriptor); } @@ -638,7 +638,7 @@ inline FlatFieldPayload::FlatFieldPayload(instanceOop container, ResolvedFieldEntry* resolved_field_entry) : FlatFieldPayload(container, resolved_field_entry->field_offset(), - resolved_field_entry->field_holder()->inline_layout_info_adr(resolved_field_entry->field_index())) { + resolved_field_entry->field_holder()->value_field_layout_info_adr(resolved_field_entry->field_index())) { assert_post_construction_invariants(container, resolved_field_entry); } @@ -648,7 +648,7 @@ inline instanceOop FlatFieldPayload::container() const { inline FlatArrayPayload::FlatArrayPayload(flatArrayOop container, ptrdiff_t offset, - InlineKlass* klass, + ValueKlass* klass, LayoutKind layout_kind, jint layout_helper, int element_size) @@ -740,7 +740,7 @@ inline oop ValuePayload::Handle::container() const { return _storage.container()(); } -inline InlineKlass* ValuePayload::Handle::klass() const { +inline ValueKlass* ValuePayload::Handle::klass() const { return _storage.klass(); } @@ -766,7 +766,7 @@ inline void ValuePayload::OopHandle::release(OopStorage* storage) { return _storage.container().release(storage); } -inline InlineKlass* ValuePayload::OopHandle::klass() const { +inline ValueKlass* ValuePayload::OopHandle::klass() const { return _storage.klass(); } @@ -785,8 +785,8 @@ inline BufferedValuePayload BufferedValuePayload::Handle::operator()() const { return BufferedValuePayload(container(), offset(), klass(), layout_kind()); } -inline inlineOop BufferedValuePayload::Handle::container() const { - return inlineOop(ValuePayload::Handle::container()); +inline valueOop BufferedValuePayload::Handle::container() const { + return valueOop(ValuePayload::Handle::container()); } inline BufferedValuePayload::Handle BufferedValuePayload::make_handle(JavaThread* thread) const { @@ -801,8 +801,8 @@ inline BufferedValuePayload BufferedValuePayload::OopHandle::operator()() const return BufferedValuePayload(container(), offset(), klass(), layout_kind()); } -inline inlineOop BufferedValuePayload::OopHandle::container() const { - return inlineOop(ValuePayload::OopHandle::container()); +inline valueOop BufferedValuePayload::OopHandle::container() const { + return valueOop(ValuePayload::OopHandle::container()); } inline BufferedValuePayload::OopHandle BufferedValuePayload::make_oop_handle(OopStorage* storage) const { diff --git a/src/hotspot/share/opto/addnode.cpp b/src/hotspot/share/opto/addnode.cpp index 31fcc46e0cb4..78467569e2e7 100644 --- a/src/hotspot/share/opto/addnode.cpp +++ b/src/hotspot/share/opto/addnode.cpp @@ -624,28 +624,32 @@ Node* AddINode::Identity(PhaseGVN* phase) { // Supplied function returns the sum of the inputs. Guaranteed never // to be passed a TOP or BOTTOM type, these are filtered out by // pre-check. -const Type *AddINode::add_ring( const Type *t0, const Type *t1 ) const { - const TypeInt *r0 = t0->is_int(); // Handy access - const TypeInt *r1 = t1->is_int(); - int lo = java_add(r0->_lo, r1->_lo); - int hi = java_add(r0->_hi, r1->_hi); - if( !(r0->is_con() && r1->is_con()) ) { - // Not both constants, compute approximate result - if( (r0->_lo & r1->_lo) < 0 && lo >= 0 ) { - lo = min_jint; hi = max_jint; // Underflow on the low side - } - if( (~(r0->_hi | r1->_hi)) < 0 && hi < 0 ) { - lo = min_jint; hi = max_jint; // Overflow on the high side - } - if( lo > hi ) { // Handle overflow - lo = min_jint; hi = max_jint; - } - } else { - // both constants, compute precise result using 'lo' and 'hi' - // Semantics define overflow and underflow for integer addition - // as expected. In particular: 0x80000000 + 0x80000000 --> 0x0 +const Type* AddINode::add_ring(const Type* t0, const Type* t1) const { + const TypeInt* range0 = t0->is_int(); + const TypeInt* range1 = t1->is_int(); + + jlong lo_sum = (jlong)range0->_lo + (jlong)range1->_lo; + jlong hi_sum = (jlong)range0->_hi + (jlong)range1->_hi; + + const jlong jint_wrap_offset = (jlong)max_juint + 1; + + if (hi_sum < min_jint) { + // The entire range underflows. + lo_sum += jint_wrap_offset; + hi_sum += jint_wrap_offset; + } else if (lo_sum > max_jint) { + // The entire range overflows. + lo_sum -= jint_wrap_offset; + hi_sum -= jint_wrap_offset; + } else if (lo_sum < min_jint || hi_sum > max_jint) { + // The range crosses one or both jint boundaries. + lo_sum = min_jint; + hi_sum = max_jint; } - return TypeInt::make( lo, hi, MAX2(r0->_widen,r1->_widen) ); + + return TypeInt::make(checked_cast(lo_sum), + checked_cast(hi_sum), + MAX2(range0->_widen, range1->_widen)); } @@ -865,7 +869,7 @@ const Type *AddPNode::bottom_type() const { txoffset = tx->get_con(); } if (tp->isa_aryptr()) { - // In the case of a flat inline type array, each field has its + // In the case of a flat value type array, each field has its // own slice so we need to extract the field being accessed from // the address computation return tp->is_aryptr()->add_field_offset_and_offset(txoffset); @@ -891,7 +895,7 @@ const Type* AddPNode::Value(PhaseGVN* phase) const { p2offset = p2->get_con(); } if (p1->isa_aryptr()) { - // In the case of a flat inline type array, each field has its + // In the case of a flat value type array, each field has its // own slice so we need to extract the field being accessed from // the address computation return p1->is_aryptr()->add_field_offset_and_offset(p2offset); diff --git a/src/hotspot/share/opto/arraycopynode.cpp b/src/hotspot/share/opto/arraycopynode.cpp index 3bf612bb468f..240750b8416b 100644 --- a/src/hotspot/share/opto/arraycopynode.cpp +++ b/src/hotspot/share/opto/arraycopynode.cpp @@ -29,7 +29,7 @@ #include "gc/shared/gc_globals.hpp" #include "opto/arraycopynode.hpp" #include "opto/graphKit.hpp" -#include "opto/inlinetypenode.hpp" +#include "opto/valuetypenode.hpp" #include "utilities/powerOfTwo.hpp" const TypeFunc* ArrayCopyNode::_arraycopy_type_Type = nullptr; @@ -145,7 +145,7 @@ int ArrayCopyNode::get_count(PhaseGVN *phase) const { // 3 or 4 elements) might lead to the same length input // (e.g. 2 double-words). assert(!ary_src->size()->is_con() || (get_length_if_constant(phase) >= 0) || - (UseArrayFlattening && ary_src->elem()->make_oopptr() != nullptr && ary_src->elem()->make_oopptr()->can_be_inline_type()) || + (UseArrayFlattening && ary_src->elem()->make_oopptr() != nullptr && ary_src->elem()->make_oopptr()->can_be_value_type()) || phase->is_IterGVN() || phase->C->inlining_incrementally() || StressReflectiveCode, "inconsistent"); if (ary_src->size()->is_con()) { return ary_src->size()->get_con(); @@ -326,7 +326,7 @@ bool ArrayCopyNode::prepare_array_copy(PhaseGVN *phase, bool can_reshape, BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); if ((!ary_dest->is_flat() && bs->array_copy_requires_gc_barriers(is_alloc_tightly_coupled(), dest_elem, false, false, BarrierSetC2::Optimization)) || - (ary_dest->is_flat() && ary_src->elem()->inline_klass()->contains_oops() && + (ary_dest->is_flat() && ary_src->elem()->value_klass()->contains_oops() && bs->array_copy_requires_gc_barriers(is_alloc_tightly_coupled(), T_OBJECT, false, false, BarrierSetC2::Optimization))) { // It's an object array copy but we can't emit the card marking that is needed return false; @@ -381,7 +381,7 @@ bool ArrayCopyNode::prepare_array_copy(PhaseGVN *phase, bool can_reshape, disjoint_bases = true; if (ary_src->elem()->make_oopptr() != nullptr && - ary_src->elem()->make_oopptr()->can_be_inline_type()) { + ary_src->elem()->make_oopptr()->can_be_value_type()) { return false; } @@ -392,7 +392,7 @@ bool ArrayCopyNode::prepare_array_copy(PhaseGVN *phase, bool can_reshape, BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); if ((!ary_src->is_flat() && bs->array_copy_requires_gc_barriers(true, elem, true, is_clone_inst(), BarrierSetC2::Optimization)) || - (ary_src->is_flat() && ary_src->elem()->inline_klass()->contains_oops() && + (ary_src->is_flat() && ary_src->elem()->value_klass()->contains_oops() && bs->array_copy_requires_gc_barriers(true, T_OBJECT, true, is_clone_inst(), BarrierSetC2::Optimization))) { // It's an object array copy but we can't emit the card marking that is needed return false; @@ -461,7 +461,7 @@ void ArrayCopyNode::copy(GraphKit& kit, BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); Node* ctl = kit.control(); if (atp_dest->is_flat()) { - ciInlineKlass* vk = atp_src->elem()->inline_klass(); + ciValueKlass* vk = atp_src->elem()->value_klass(); for (int j = 0; j < vk->nof_nonstatic_fields(); j++) { ciField* field = vk->nonstatic_field_at(j); int off_in_vt = field->offset_in_bytes() - vk->payload_offset(); @@ -649,7 +649,7 @@ Node *ArrayCopyNode::Ideal(PhaseGVN *phase, bool can_reshape) { const Type* dest_type = phase->type(dest); if (src_type->isa_aryptr() && dest_type->isa_instptr()) { - // clone used for load of unknown inline type can't be optimized at + // clone used for load of unknown value type can't be optimized at // this point return nullptr; } diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index 76639a5ef817..af832a029581 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -826,6 +826,9 @@ product(bool, IncrementalInlineForceCleanup, false, DIAGNOSTIC, \ "do cleanup after every iteration of incremental inlining") \ \ + product(bool, IncrementalInlineVector, true, DIAGNOSTIC, \ + "Inline fallback implementation of failed vector intrinsics") \ + \ product(intx, LiveNodeCountInliningCutoff, 40000, \ "max number of live nodes in a method") \ range(0, max_juint / 8) \ diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index 9196d91b47b1..4cacba4eaee9 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -847,6 +847,10 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_Preconditions_checkIndex: case vmIntrinsics::_Preconditions_checkLongIndex: case vmIntrinsics::_getObjectSize: + case vmIntrinsics::_addInt128TLo: + case vmIntrinsics::_addInt128THi: + case vmIntrinsics::_subInt128TLo: + case vmIntrinsics::_subInt128THi: break; case vmIntrinsics::_VectorCompressExpand: case vmIntrinsics::_VectorUnaryOp: diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index 8d9f8d8f32d7..ff46314e7fa1 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -36,11 +36,11 @@ #include "opto/callnode.hpp" #include "opto/castnode.hpp" #include "opto/cfgnode.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/parse.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" #include "opto/subnode.hpp" +#include "opto/valuetypenode.hpp" #include "runtime/os.inline.hpp" #include "runtime/sharedRuntime.hpp" #include "utilities/debug.hpp" @@ -71,8 +71,8 @@ void CallGenerator::mark_projs_not_dead_loop_safe(Node* ret) const { CallNode* call = call_node(); if (ret->is_Proj() && ret->in(0) == call) { ret->mark_not_dead_loop_safe(); - } else if (ret->isa_InlineType()) { - InlineTypeNode* vt = ret->as_InlineType(); + } else if (ret->isa_ValueType()) { + ValueTypeNode* vt = ret->as_ValueType(); Node* oop = vt->get_oop(); if (oop->is_Proj() && oop->in(0) == call) { oop->mark_not_dead_loop_safe(); @@ -161,9 +161,9 @@ class DirectCallGenerator : public CallGenerator { _call_node(nullptr), _separate_io_proj(separate_io_proj) { - if (InlineTypeReturnedAsFields && method->is_method_handle_intrinsic()) { + if (ValueTypeReturnedAsFields && method->is_method_handle_intrinsic()) { // If that call has not been optimized by the time optimizations are over, - // we'll need to add a call to create an inline type instance from the klass + // we'll need to add a call to create a value type instance from the klass // returned by the call (see PhaseMacroExpand::expand_mh_intrinsic_return). // Separating memory and I/O projections for exceptions is required to // perform that graph transformation. @@ -492,6 +492,31 @@ CallGenerator* CallGenerator::for_mh_late_inline(ciMethod* caller, ciMethod* cal return cg; } +class LateInlineVectorCallGenerator : public LateInlineCallGenerator { + private: + CallGenerator* _fallback_cg; + + public: + LateInlineVectorCallGenerator(ciMethod* method, CallGenerator* intrinsic_cg, CallGenerator* fallback_cg) : + LateInlineCallGenerator(method, intrinsic_cg), _fallback_cg(fallback_cg) { + assert(_fallback_cg != nullptr && _fallback_cg->is_parse(), ""); + } + + virtual bool is_vector_late_inline() const { return true; } + + virtual JVMState* generate(JVMState* jvms) { + JVMState* new_jvms = LateInlineCallGenerator::generate(jvms); + CallGenerator* fallback = CallGenerator::for_late_inline(method(), _fallback_cg)->with_call_node(call_node()); + Compile::current()->add_vector_late_inline(fallback); + return new_jvms; + } +}; + +CallGenerator* CallGenerator::for_vector_late_inline(ciMethod* m, CallGenerator* intrinsic_cg, CallGenerator* fallback_cg) { + return new LateInlineVectorCallGenerator(m, intrinsic_cg, fallback_cg); +} + + // Allow inlining decisions to be delayed class LateInlineVirtualCallGenerator : public VirtualCallGenerator { private: @@ -743,12 +768,12 @@ void CallGenerator::do_late_inline_helper() { int arg_num = 0; for (uint i1 = 0; i1 < nargs; i1++) { const Type* t = domain_sig->field_at(TypeFunc::Parms + i1); - if (t->is_inlinetypeptr() && !method()->mismatch() && method()->is_scalarized_arg(arg_num)) { - // Inline type arguments are not passed by reference: we get an argument per - // field of the inline type. Build InlineTypeNodes from the inline type arguments. + if (t->is_valueklassptr() && !method()->mismatch() && method()->is_scalarized_arg(arg_num)) { + // Value type arguments are not passed by reference: we get an argument per + // field of the value type. Build ValueTypeNodes from the value type arguments. GraphKit arg_kit(jvms, &gvn); - Node* vt = InlineTypeNode::make_from_multi(&arg_kit, call, t->inline_klass(), j, /* in= */ true, /* null_free= */ !t->maybe_null()); - // GraphKit::access_load_at() may be called from InlineTypeNode::make_from_multi() and it may change the map + Node* vt = ValueTypeNode::make_from_multi(&arg_kit, call, t->value_klass(), j, /* in= */ true, /* null_free= */ !t->maybe_null()); + // GraphKit::access_load_at() may be called from ValueTypeNode::make_from_multi() and it may change the map // that arg_kit uses. map = arg_kit.map(); map->set_control(arg_kit.control()); @@ -769,20 +794,20 @@ void CallGenerator::do_late_inline_helper() { return; } - // Check if we are late inlining a method handle call that returns an inline type as fields. + // Check if we are late inlining a method handle call that returns a value type as fields. Node* buffer_oop = nullptr; ciMethod* inline_method = inline_cg()->method(); ciType* return_type = inline_method->return_type(); - // Allocate a buffer for the inline type returned as fields because the caller expects an oop return. + // Allocate a buffer for the value type returned as fields because the caller expects an oop return. // Moving this after the call would require distinct JVM states: a next-BCI state with the result for // deoptimization at an allocation safepoint and an invoke-BCI state for exceptions like OOME. The // pre-call state can safely execute the call if allocation deoptimizes. - bool needs_return_buffer = !call->tf()->returns_inline_type_as_fields() && - return_type->is_inlinetype() && - return_type->as_inline_klass()->can_be_returned_as_fields(); + bool needs_return_buffer = !call->tf()->returns_value_type_as_fields() && + return_type->is_value_klass() && + return_type->as_value_klass()->can_be_returned_as_fields(); // A non-null scalarized return would require a buffer. Since allocating that buffer could // initialize the value class, speculate that the result is null and deoptimize otherwise. - bool assert_null_return = needs_return_buffer && !return_type->as_inline_klass()->is_initialized(); + bool assert_null_return = needs_return_buffer && !return_type->as_value_klass()->is_initialized(); assert(!needs_return_buffer || is_mh_late_inline(), "Unexpected return type"); if (needs_return_buffer && !assert_null_return) { @@ -791,7 +816,7 @@ void CallGenerator::do_late_inline_helper() { PreserveReexecuteState preexecs(&arg_kit); arg_kit.jvms()->set_should_reexecute(true); arg_kit.inc_sp(nargs); - Node* klass_node = arg_kit.makecon(TypeKlassPtr::make(return_type->as_inline_klass())); + Node* klass_node = arg_kit.makecon(TypeKlassPtr::make(return_type->as_value_klass())); buffer_oop = arg_kit.new_instance(klass_node, nullptr, nullptr, /* deoptimize_on_exception */ true); } jvms = arg_kit.transfer_exceptions_into_jvms(); @@ -842,10 +867,10 @@ void CallGenerator::do_late_inline_helper() { call->as_CallStaticJava()->is_boxing_method()) { result = kit.must_be_not_null(result, false); } - // Handle inline type returns - InlineTypeNode* vt = result->isa_InlineType(); + // Handle value type returns + ValueTypeNode* vt = result->isa_ValueType(); if (vt != nullptr) { - if (call->tf()->returns_inline_type_as_fields()) { + if (call->tf()->returns_value_type_as_fields()) { vt->replace_call_results(&kit, call, C); } else if (assert_null_return && !vt->is_allocated(&kit.gvn())) { // Deoptimize if the result is non-null. @@ -871,14 +896,14 @@ void CallGenerator::do_late_inline_helper() { Node* null_ctl = kit.top(); kit.null_check_common(vt->get_null_marker(), T_INT, false, &null_ctl); region->init_req(1, null_ctl); - PhiNode* oop = PhiNode::make(region, kit.gvn().zerocon(T_OBJECT), TypeInstPtr::make(TypePtr::BotPTR, vt->type()->inline_klass())); + PhiNode* oop = PhiNode::make(region, kit.gvn().zerocon(T_OBJECT), TypeInstPtr::make(TypePtr::BotPTR, vt->type()->value_klass())); Node* init_mem = kit.reset_memory(); PhiNode* mem = PhiNode::make(region, init_mem, Type::MEMORY, TypePtr::BOTTOM); // Not null, initialize the buffer kit.set_all_memory(init_mem); - Node* payload_ptr = kit.basic_plus_adr(buffer_oop, kit.gvn().type(vt)->inline_klass()->payload_offset()); + Node* payload_ptr = kit.basic_plus_adr(buffer_oop, kit.gvn().type(vt)->value_klass()->payload_offset()); vt->store_flat(&kit, buffer_oop, payload_ptr, false, true, true, IN_HEAP | MO_UNORDERED); // Do not let stores that initialize this buffer be reordered with a subsequent // store that would make this buffer accessible by other threads. @@ -889,11 +914,11 @@ void CallGenerator::do_late_inline_helper() { oop->init_req(2, buffer_oop); mem->init_req(2, kit.merged_memory()); - // Use cloned InlineTypeNode to propagate oop from now on + // Use cloned ValueTypeNode to propagate oop from now on vt = vt->clone_if_required(&kit.gvn(), kit.map()); vt->set_oop(kit.gvn(), kit.gvn().transform(oop)); vt->set_is_buffered(kit.gvn()); - vt = kit.gvn().transform(vt)->as_InlineType(); + vt = kit.gvn().transform(vt)->as_ValueType(); kit.set_control(kit.gvn().transform(region)); kit.set_all_memory(kit.gvn().transform(mem)); @@ -905,12 +930,12 @@ void CallGenerator::do_late_inline_helper() { } DEBUG_ONLY(buffer_oop = nullptr); } else { - assert(!call->tf()->returns_inline_type_as_fields() || !call->as_CallJava()->method()->return_type()->is_loaded(), "Unexpected return value"); + assert(!call->tf()->returns_value_type_as_fields() || !call->as_CallJava()->method()->return_type()->is_loaded(), "Unexpected return value"); } assert(buffer_oop == nullptr, "unused buffer allocation"); // Note: scalarized results are guarded per projection - if (!call->tf()->returns_inline_type_as_fields()) { + if (!call->tf()->returns_value_type_as_fields()) { assert(callprojs->nb_resproj == 1 && callprojs->resproj[0] != nullptr, "single result projection expected"); // Limit result type propagation until next IGVN cleanup. @@ -1184,9 +1209,9 @@ JVMState* PredictedCallGenerator::generate(JVMState* jvms) { Node* n = slow_map->in(i); if (m != n) { #ifdef ASSERT - if (m->is_InlineType() != n->is_InlineType()) { - InlineTypeNode* unique_vt = m->is_InlineType() ? m->as_InlineType() : n->as_InlineType(); - assert(unique_vt->is_allocated(&gvn), "InlineType can be merged with an oop only if it is allocated"); + if (m->is_ValueType() != n->is_ValueType()) { + ValueTypeNode* unique_vt = m->is_ValueType() ? m->as_ValueType() : n->as_ValueType(); + assert(unique_vt->is_allocated(&gvn), "ValueType can be merged with an oop only if it is allocated"); } #endif const Type* t = gvn.type(m)->meet_speculative(gvn.type(n)); diff --git a/src/hotspot/share/opto/callGenerator.hpp b/src/hotspot/share/opto/callGenerator.hpp index 6f4a4069e4e2..c373490f3646 100644 --- a/src/hotspot/share/opto/callGenerator.hpp +++ b/src/hotspot/share/opto/callGenerator.hpp @@ -76,6 +76,7 @@ class CallGenerator : public ArenaObj { // same but for method handle calls virtual bool is_mh_late_inline() const { return false; } virtual bool is_string_late_inline() const { return false; } + virtual bool is_vector_late_inline() const { return false; } virtual bool is_boxing_late_inline() const { return false; } virtual bool is_vector_reboxing_late_inline() const { return false; } virtual bool is_virtual_late_inline() const { return false; } @@ -145,6 +146,7 @@ class CallGenerator : public ArenaObj { static CallGenerator* for_late_inline(ciMethod* m, CallGenerator* inline_cg); static CallGenerator* for_mh_late_inline(ciMethod* caller, ciMethod* callee, bool input_not_const); static CallGenerator* for_string_late_inline(ciMethod* m, CallGenerator* inline_cg); + static CallGenerator* for_vector_late_inline(ciMethod* m, CallGenerator* intrinsic_cg, CallGenerator* fallback_cg); static CallGenerator* for_boxing_late_inline(ciMethod* m, CallGenerator* inline_cg); static CallGenerator* for_vector_reboxing_late_inline(ciMethod* m, CallGenerator* inline_cg); static CallGenerator* for_late_inline_virtual(ciMethod* m, int vtable_index, float expected_uses); diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index 65b5ae1d1de7..528c07350b2c 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -36,7 +36,6 @@ #include "opto/castnode.hpp" #include "opto/convertnode.hpp" #include "opto/escape.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/library_call.hpp" #include "opto/locknode.hpp" #include "opto/machnode.hpp" @@ -49,6 +48,7 @@ #include "opto/rootnode.hpp" #include "opto/runtime.hpp" #include "opto/type.hpp" +#include "opto/valuetypenode.hpp" #include "runtime/arguments.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" @@ -504,7 +504,7 @@ void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st) uint nf = spobj->n_fields(); if (nf > 0) { uint first_ind = spobj->first_index(mcall->jvms()); - if (iklass != nullptr && iklass->is_inlinetype()) { + if (iklass != nullptr && iklass->is_value_klass()) { Node* null_marker = mcall->in(first_ind++); if (!null_marker->is_top()) { st->print(" [null marker"); @@ -768,7 +768,7 @@ const Type* CallNode::Value(PhaseGVN* phase) const { //------------------------------calling_convention----------------------------- void CallNode::calling_convention(BasicType* sig_bt, VMRegPair *parm_regs, uint argcnt) const { - if (InlineTypeReturnedAsFields && _entry_point == SharedRuntime::store_inline_type_fields_to_buf_entry()) { + if (ValueTypeReturnedAsFields && _entry_point == SharedRuntime::store_value_type_fields_to_buf_entry()) { // The call to that stub is a special case: its inputs are // multiple values returned from a call and so it should follow // the return convention. @@ -787,10 +787,10 @@ Node* CallNode::match(const ProjNode* proj, const Matcher* match) { uint con = proj->_con; const TypeTuple* range_cc = _tf->range_cc(); if (con >= TypeFunc::Parms) { - if (_tf->returns_inline_type_as_fields()) { - // The call returns multiple values (inline type fields): we + if (_tf->returns_value_type_as_fields()) { + // The call returns multiple values (value type fields): we // create one projection per returned value. - assert(con <= TypeFunc::Parms+1 || InlineTypeReturnedAsFields, "only for multi value return"); + assert(con <= TypeFunc::Parms+1 || ValueTypeReturnedAsFields, "only for multi value return"); uint ideal_reg = range_cc->field_at(con)->ideal_reg(); const RegMask* mask = match->return_values_mask(_tf); return new MachProjNode(this, con, mask[con-TypeFunc::Parms], ideal_reg); @@ -1278,7 +1278,7 @@ int CallStaticJavaNode::extract_uncommon_trap_request(const Node* call) { // Split if can cause the flat array branch of an array load with unknown type (see // Parse::array_load) to end in an uncommon trap. In that case, the call to -// 'load_unknown_inline' is useless. Replace it with an uncommon trap with the same JVMState. +// 'load_unknown_value' is useless. Replace it with an uncommon trap with the same JVMState. bool CallStaticJavaNode::remove_unknown_flat_array_load(PhaseIterGVN* igvn, Node* ctl, Node* mem, Node* unc_arg) { if (ctl == nullptr || ctl->is_top() || mem == nullptr || mem->is_top() || !mem->is_MergeMem()) { return false; @@ -1313,7 +1313,7 @@ bool CallStaticJavaNode::remove_unknown_flat_array_load(PhaseIterGVN* igvn, Node if (call->is_Proj() || call->is_Catch() || call->is_MemBar()) { call = call->in(0); } else if (call->Opcode() == Op_CallStaticJava && !call->in(0)->is_top() && - call->as_Call()->entry_point() == OptoRuntime::load_unknown_inline_Java()) { + call->as_Call()->entry_point() == OptoRuntime::load_unknown_value_Java()) { // If there is no explicit flat array accesses in the compilation unit, there would be no // membar here if (call->in(0)->is_Proj() && call->in(0)->in(0)->is_MemBar()) { @@ -1352,7 +1352,7 @@ bool CallStaticJavaNode::remove_unknown_flat_array_load(PhaseIterGVN* igvn, Node } else if (m1->is_MemBar()) { m1 = m1->in(TypeFunc::Memory); } else if (m1->Opcode() == Op_CallStaticJava && - m1->as_Call()->entry_point() == OptoRuntime::load_unknown_inline_Java()) { + m1->as_Call()->entry_point() == OptoRuntime::load_unknown_value_Java()) { if (m1 != call) { if (call_mem->outcnt() == 0) { igvn->remove_dead_node(call_mem, PhaseIterGVN::NodeOrigin::Speculative); @@ -1411,11 +1411,11 @@ bool CallStaticJavaNode::remove_unknown_flat_array_load(PhaseIterGVN* igvn, Node Node* CallStaticJavaNode::replace_identity_hash_code(PhaseIterGVN* igvn) { Node* arg = in(TypeFunc::Parms); intptr_t klass_hash; - if (!InlineTypeNode::can_emit_identity_hash_code(*igvn, arg, klass_hash)) { + if (!ValueTypeNode::can_emit_identity_hash_code(*igvn, arg, klass_hash)) { // We can't expand, but now, maybe we can also tell the fast path won't work const Type* arg_type = igvn->type(arg); - if (UseHashcodeFastPath && igvn->type(arg)->is_inlinetypeptr()) { - ciInlineKlass* vk = arg_type->inline_klass(); + if (UseHashcodeFastPath && igvn->type(arg)->is_valueklassptr()) { + ciValueKlass* vk = arg_type->value_klass(); bool fast_path_wont_work = false; fast_path_wont_work = fast_path_wont_work || vk->number_of_oop_entries_in_acmp_map() > 0; fast_path_wont_work = fast_path_wont_work || vk->number_of_nonoop_entries_in_acmp_map() > 1; @@ -1440,7 +1440,7 @@ Node* CallStaticJavaNode::replace_identity_hash_code(PhaseIterGVN* igvn) { igvn->set_delay_transform(true); GraphKit kit(this, *igvn); - Node* replace = InlineTypeNode::emit_identity_hash_code(&kit, arg, klass_hash); + Node* replace = ValueTypeNode::emit_identity_hash_code(&kit, arg, klass_hash); igvn->set_delay_transform(false); assert(replace != nullptr, "must succeed"); @@ -1478,7 +1478,7 @@ Node* CallStaticJavaNode::replace_identity_hash_code(PhaseIterGVN* igvn) { Node* CallStaticJavaNode::replace_is_substitutable(PhaseIterGVN* igvn) { Node* left = in(TypeFunc::Parms); Node* right = in(TypeFunc::Parms + 1); - if (!InlineTypeNode::can_emit_substitutability_check(igvn, left, right)) { + if (!ValueTypeNode::can_emit_substitutability_check(igvn, left, right)) { return nullptr; } @@ -1487,7 +1487,7 @@ Node* CallStaticJavaNode::replace_is_substitutable(PhaseIterGVN* igvn) { igvn->set_delay_transform(true); GraphKit kit(this, *igvn); - Node* replace = InlineTypeNode::emit_substitutability_check(&kit, left, right); + Node* replace = ValueTypeNode::emit_substitutability_check(&kit, left, right); igvn->set_delay_transform(false); assert(replace != nullptr, "must succeed"); @@ -1802,13 +1802,13 @@ Node *SafePointNode::Ideal(PhaseGVN *phase, bool can_reshape) { if (remove_dead_region(phase, can_reshape)) { return this; } - // Scalarize inline types in safepoint debug info. + // Scalarize value types in safepoint debug info. // Delay this until all inlining is over to avoid getting inconsistent debug info. if (phase->C->scalarize_in_safepoints() && can_reshape && jvms() != nullptr) { for (uint i = jvms()->debug_start(); i < jvms()->debug_end(); i++) { Node* n = in(i)->uncast(); - if (n->is_InlineType()) { - if (!n->as_InlineType()->make_scalar_in_safepoints(phase->is_IterGVN(), true, this)) { + if (n->is_ValueType()) { + if (!n->as_ValueType()->make_scalar_in_safepoints(phase->is_IterGVN(), true, this)) { return nullptr; } } @@ -2102,7 +2102,7 @@ AllocateNode::AllocateNode(Compile* C, const TypeFunc *atype, Node *ctrl, Node *mem, Node *abio, Node *size, Node *klass_node, Node* initial_test, - InlineTypeNode* inline_type_node) + ValueTypeNode* value_type_node) : CallNode(atype, nullptr, TypeRawPtr::BOTTOM) { init_class_id(Class_Allocate); @@ -2122,7 +2122,7 @@ AllocateNode::AllocateNode(Compile* C, const TypeFunc *atype, init_req( InitialTest , initial_test); init_req( ALength , topnode); init_req( ValidLengthTest , topnode); - init_req( InlineType , inline_type_node); + init_req( ValueType , value_type_node); // DefaultValue defaults to nullptr // RawDefaultValue defaults to nullptr C->add_macro_node(this); @@ -2547,7 +2547,7 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) { // modify the graph, the value returned from this function is the // one computed above. const Type* obj_type = phase->type(obj_node()); - if (can_reshape && EliminateLocks && !is_non_esc_obj() && !obj_type->is_inlinetypeptr()) { + if (can_reshape && EliminateLocks && !is_non_esc_obj() && !obj_type->is_valueklassptr()) { // // If we are locking an non-escaped object, the lock/unlock is unnecessary // @@ -2746,7 +2746,7 @@ Node *UnlockNode::Ideal(PhaseGVN *phase, bool can_reshape) { // one computed above. // Escape state is defined after Parse phase. const Type* obj_type = phase->type(obj_node()); - if (can_reshape && EliminateLocks && !is_non_esc_obj() && !obj_type->is_inlinetypeptr()) { + if (can_reshape && EliminateLocks && !is_non_esc_obj() && !obj_type->is_valueklassptr()) { // // If we are unlocking an non-escaped object, the lock/unlock is unnecessary. // diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index 229108614f36..80e6cc1e3688 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -822,7 +822,7 @@ class CallNode : public SafePointNode { // Does this node returns pointer? bool returns_pointer() const { const TypeTuple* r = tf()->range_sig(); - return (!tf()->returns_inline_type_as_fields() && + return (!tf()->returns_value_type_as_fields() && r->cnt() > TypeFunc::Parms && r->field_at(TypeFunc::Parms)->isa_ptr()); } @@ -916,12 +916,12 @@ class CallStaticJavaNode : public CallJavaNode { C->add_macro_node(this); } const TypeTuple *r = tf->range_sig(); - if (InlineTypeReturnedAsFields && + if (ValueTypeReturnedAsFields && method != nullptr && method->is_method_handle_intrinsic() && r->cnt() > TypeFunc::Parms && r->field_at(TypeFunc::Parms)->isa_oopptr() && - r->field_at(TypeFunc::Parms)->is_oopptr()->can_be_inline_type()) { + r->field_at(TypeFunc::Parms)->is_oopptr()->can_be_value_type()) { // Make sure this call is processed by PhaseMacroExpand::expand_mh_intrinsic_return init_flags(Flag_is_macro); C->add_macro_node(this); @@ -1120,8 +1120,8 @@ class AllocateNode : public CallNode { InitialTest, // slow-path test (may be constant) ALength, // array length (or TOP if none) ValidLengthTest, - InlineType, // InlineTypeNode if this is an inline type allocation - InitValue, // Init value for null-free inline type arrays + ValueType, // ValueTypeNode if this is a value type allocation + InitValue, // Init value for null-free value type arrays RawInitValue, // Same as above but as raw machine word ParmLimit }; @@ -1133,7 +1133,7 @@ class AllocateNode : public CallNode { fields[InitialTest] = TypeInt::BOOL; fields[ALength] = t; // length (can be a bad length) fields[ValidLengthTest] = TypeInt::BOOL; - fields[InlineType] = Type::BOTTOM; + fields[ValueType] = Type::BOTTOM; fields[InitValue] = TypeInstPtr::NOTNULL; fields[RawInitValue] = TypeX_X; @@ -1157,7 +1157,7 @@ class AllocateNode : public CallNode { virtual uint size_of() const; // Size is bigger AllocateNode(Compile* C, const TypeFunc *atype, Node *ctrl, Node *mem, Node *abio, Node *size, Node *klass_node, Node *initial_test, - InlineTypeNode* inline_type_node = nullptr); + ValueTypeNode* value_type_node = nullptr); // Expansion modifies the JVMState, so we need to deep clone it virtual bool needs_deep_clone_jvms(Compile* C) { return true; } virtual int Opcode() const; diff --git a/src/hotspot/share/opto/castnode.cpp b/src/hotspot/share/opto/castnode.cpp index 472780bb96dd..f2d22f8a2f6b 100644 --- a/src/hotspot/share/opto/castnode.cpp +++ b/src/hotspot/share/opto/castnode.cpp @@ -28,13 +28,13 @@ #include "opto/cfgnode.hpp" #include "opto/connode.hpp" #include "opto/graphKit.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/loopnode.hpp" #include "opto/matcher.hpp" #include "opto/phaseX.hpp" #include "opto/rootnode.hpp" #include "opto/subnode.hpp" #include "opto/type.hpp" +#include "opto/valuetypenode.hpp" #include "utilities/checkedCast.hpp" const ConstraintCastNode::DependencyType ConstraintCastNode::DependencyType::FloatingNarrowing(true, true, "floating narrowing dependency"); // not pinned, narrows type @@ -115,9 +115,9 @@ Node *ConstraintCastNode::Ideal(PhaseGVN *phase, bool can_reshape) { return this; } - // Push cast through InlineTypeNode - if (in(1)->is_InlineType()) { - return ideal_cast_of_inline_type_node(phase); + // Push cast through ValueTypeNode + if (in(1)->is_ValueType()) { + return ideal_cast_of_value_type_node(phase); } if (in(1) != nullptr && phase->type(in(1)) != Type::TOP) { @@ -227,8 +227,8 @@ Node* ConstraintCastNode::pin_node_under_control_impl() const { return make_cast_for_type(in(0), in(1), bottom_type(), _dependency.with_pinned_dependency(), _extra_types); } -Node* ConstraintCastNode::ideal_cast_of_inline_type_node(PhaseGVN* phase) { - InlineTypeNode* vt = in(1)->as_InlineType(); +Node* ConstraintCastNode::ideal_cast_of_value_type_node(PhaseGVN* phase) { + ValueTypeNode* vt = in(1)->as_ValueType(); if (type()->isa_rawptr() != nullptr) { return nullptr; } @@ -251,7 +251,7 @@ Node* ConstraintCastNode::ideal_cast_of_inline_type_node(PhaseGVN* phase) { // The only possible case left is that the cast is a cast to not-null assert(join == vt->type()->filter(TypePtr::NOTNULL), "must be"); - InlineTypeNode* res = vt->clone()->as_InlineType(); + ValueTypeNode* res = vt->clone()->as_ValueType(); res->set_null_marker(*phase); // Push the cast to the oop input if possible @@ -479,7 +479,7 @@ Node* CastLLNode::Ideal(PhaseGVN* phase, bool can_reshape) { //------------------------------Identity--------------------------------------- // If input is already higher or equal to cast type, then this is an identity. Node* CheckCastPPNode::Identity(PhaseGVN* phase) { - if (in(1)->is_InlineType() && _type->isa_instptr() && phase->type(in(1))->inline_klass()->is_subtype_of(_type->is_instptr()->instance_klass())) { + if (in(1)->is_ValueType() && _type->isa_instptr() && phase->type(in(1))->value_klass()->is_subtype_of(_type->is_instptr()->instance_klass())) { return in(1); } return ConstraintCastNode::Identity(phase); diff --git a/src/hotspot/share/opto/castnode.hpp b/src/hotspot/share/opto/castnode.hpp index 29b609d6ddda..8998112f0aed 100644 --- a/src/hotspot/share/opto/castnode.hpp +++ b/src/hotspot/share/opto/castnode.hpp @@ -195,7 +195,7 @@ class ConstraintCastNode: public TypeNode { private: virtual Node* pin_node_under_control_impl() const; - Node* ideal_cast_of_inline_type_node(PhaseGVN* phase); + Node* ideal_cast_of_value_type_node(PhaseGVN* phase); }; //------------------------------CastIINode------------------------------------- diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index 21761001099b..76d80855cacc 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -32,17 +32,18 @@ #include "opto/cfgnode.hpp" #include "opto/connode.hpp" #include "opto/convertnode.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/loopnode.hpp" #include "opto/machnode.hpp" #include "opto/movenode.hpp" #include "opto/mulnode.hpp" #include "opto/narrowptrnode.hpp" +#include "opto/node.hpp" #include "opto/phaseX.hpp" #include "opto/regalloc.hpp" #include "opto/regmask.hpp" #include "opto/runtime.hpp" #include "opto/subnode.hpp" +#include "opto/valuetypenode.hpp" #include "opto/vectornode.hpp" #include "utilities/vmError.hpp" @@ -2134,6 +2135,34 @@ bool PhiNode::is_unsafe_data_reference(Node *in) const { return false; // The phi is not reachable from its inputs } +// A Phi may only have other Phis as its transitive outputs, it is dead then. We may not be able to +// remove it normally because a Phi can be a transitive output of itself. +bool PhiNode::is_dead_phi() { + // Early return before we create the worklist + for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) { + if (!fast_out(i)->is_Phi()) { + return false; + } + } + + ResourceMark rm; + Unique_Node_List worklist; + worklist.push(this); + for (uint wl_idx = 0; wl_idx < worklist.size(); wl_idx++) { + Node* n = worklist.at(wl_idx); + for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { + Node* out = n->fast_out(i); + if (out->is_Phi()) { + worklist.push(out); + } else { + return false; + } + } + } + + return true; +} + // Is this Phi's region or some inputs to the region enqueued for IGVN // and so could cause the region to be optimized out? bool PhiNode::wait_for_region_igvn(PhaseGVN* phase) { @@ -2848,9 +2877,9 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { } #endif - Node* inline_type = try_push_inline_types_down(phase, can_reshape); - if (inline_type != this) { - return inline_type; + Node* value_type = try_push_value_types_down(phase, can_reshape); + if (value_type != this) { + return value_type; } // Try to convert a Phi with two duplicated convert nodes into a phi of the pre-conversion type and the convert node @@ -2915,28 +2944,28 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { return progress; // Return any progress } -// If an InlineType node references itself through a Phi (oop input): +// If an ValueType node references itself through a Phi (oop input): // // /------ | -// InlineType | +// ValueType | // \ / | // Phi | // ^____________| // -// and is pushed down through the Phi, the result is a new InlineType node that can be pushed down through the Phi +// and is pushed down through the Phi, the result is a new ValueType node that can be pushed down through the Phi // etc. // -// To solve that problem, the code below finds InlineType nodes that are reachable from another InlineType node by -// following the inline type node's oop inputs through Phis and casts such as, for instance: -// (InlineType (Cast (Phi (InlineType oop +// To solve that problem, the code below finds ValueType nodes that are reachable from another ValueType node by +// following the value type node's oop inputs through Phis and casts such as, for instance: +// (ValueType (Cast (Phi (ValueType oop // and replaces it with: -// (InlineType (Cast (Phi oop -// which requires cloning every Phi and cast nodes in the subgraph between the root InlineType and the leaf -// InlineType node in this example. -class PushInlineTypeDown { +// (ValueType (Cast (Phi oop +// which requires cloning every Phi and cast nodes in the subgraph between the root ValueType and the leaf +// ValueType node in this example. +class PushValueTypeDown { private: - // Find the inlineType nodes that can be reached from this Phi without going through another InlineType (those that - // must not reference another inline type node from their oop input through Phis and cast nodes) + // Find the ValueType nodes that can be reached from this Phi without going through another ValueType (those that + // must not reference another value type node from their oop input through Phis and cast nodes) void collect_nodes_from_phi() { _nodes_from_phi.push(_root_phi); for (uint i = 0; i < _nodes_from_phi.size(); ++i) { @@ -2957,16 +2986,16 @@ class PushInlineTypeDown { } } - void collect_nodes_from_inline_types() { - // Only keep InlineType nodes + void collect_nodes_from_value_types() { + // Only keep ValueType nodes for (int i = _nodes_from_phi.size() - 1; i >= 0; i--) { Node* n = _nodes_from_phi.at(i); - if (!n->is_InlineType()) { + if (!n->is_ValueType()) { _nodes_from_phi.remove(i); } } DEBUG_ONLY(_init_nodes = _nodes_from_phi.size()); - // Find the InlineType nodes reachable from the current set of inline type nodes. + // Find the ValueType nodes reachable from the current set of value type nodes. for (uint i = 0; i < _nodes_from_phi.size(); ++i) { Node* n = _nodes_from_phi.at(i); if (n->is_Phi()) { @@ -2981,8 +3010,8 @@ class PushInlineTypeDown { if (in != nullptr) { _nodes_from_phi.push(in); } - } else if (n->is_InlineType()) { - Node* buf = n->as_InlineType()->get_oop(); + } else if (n->is_ValueType()) { + Node* buf = n->as_ValueType()->get_oop(); if (buf != nullptr) { _nodes_from_phi.push(buf); _subgraph_to_clone.push(n); @@ -2992,9 +3021,9 @@ class PushInlineTypeDown { } void collect_nodes_to_clone() { - collect_nodes_from_inline_types(); + collect_nodes_from_value_types(); - // Find the subgraph that must be cloned by following uses from inline types. + // Find the subgraph that must be cloned by following uses from value types. for (uint i = 0; i < _subgraph_to_clone.size(); ++i) { Node* n = _subgraph_to_clone.at(i); for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { @@ -3010,8 +3039,8 @@ class PushInlineTypeDown { for (uint i = 0; i < _subgraph_to_clone.size(); ++i) { Node* n = _subgraph_to_clone.at(i); assert(_clones[n->_idx] == nullptr, "shouldn't be cloned yet"); - if (n->is_InlineType()) { - _clones.map(n->_idx, n->as_InlineType()->get_oop()); + if (n->is_ValueType()) { + _clones.map(n->_idx, n->as_ValueType()->get_oop()); } else { Node* clone = n->clone(); _phase->is_IterGVN()->register_new_node_with_optimizer(clone); @@ -3052,12 +3081,12 @@ class PushInlineTypeDown { Node* in_clone = get_clone(in); assert(in_clone != nullptr, "must be cloned"); n_clone->set_req(1, in_clone); - } else if (n->is_InlineType()) { - Node* in = n->as_InlineType()->get_oop(); + } else if (n->is_ValueType()) { + Node* in = n->as_ValueType()->get_oop(); Node* in_clone = get_clone(in); if (in_clone != nullptr) { _phase->is_IterGVN()->rehash_node_delayed(n); - n->as_InlineType()->set_oop(*_phase, in_clone); + n->as_ValueType()->set_oop(*_phase, in_clone); } } } @@ -3079,8 +3108,8 @@ class PushInlineTypeDown { before_phis++; } else if (n->is_ConstraintCast()) { before_casts++; - } else if (n->is_InlineType()) { - Node* buf = n->as_InlineType()->get_oop(); + } else if (n->is_ValueType()) { + Node* buf = n->as_ValueType()->get_oop(); if (buf != nullptr && i >= _init_nodes) { vts_to_skip++; } @@ -3107,7 +3136,7 @@ class PushInlineTypeDown { } for (int i = after.size() - 1; i >= 0; i--) { Node* n = after.at(i); - if (!n->is_InlineType()) { + if (!n->is_ValueType()) { after.remove(i); } } @@ -3130,9 +3159,9 @@ class PushInlineTypeDown { if (in != nullptr) { after.push(in); } - } else if (n->is_InlineType()) { + } else if (n->is_ValueType()) { assert(i < init_nodes, ""); - Node* buf = n->as_InlineType()->get_oop(); + Node* buf = n->as_ValueType()->get_oop(); if (buf != nullptr) { after.push(buf); } @@ -3145,10 +3174,10 @@ class PushInlineTypeDown { #endif Node* do_transform(PhiNode* phi) { - assert(_inline_klass != nullptr, "must be"); - InlineTypeNode* vt = InlineTypeNode::make_null(*_phase, _inline_klass, /* transform = */ false)->clone_with_phis( + assert(_value_klass != nullptr, "must be"); + ValueTypeNode* vt = ValueTypeNode::make_null(*_phase, _value_klass, /* transform = */ false)->clone_with_phis( _phase, phi->in(0), nullptr, !phi->type()->maybe_null(), true); - // Record that vt was created to replace phi to be able to use the inline type node when reaching the phi again + // Record that vt was created to replace phi to be able to use the value type node when reaching the phi again // through data loops. _clones.map(phi->_idx, vt); Node_List casts; @@ -3163,7 +3192,7 @@ class PushInlineTypeDown { n = n->in(1); } if (_phase->type(n)->is_zero_type()) { - n = InlineTypeNode::make_null(*_phase, _inline_klass); + n = ValueTypeNode::make_null(*_phase, _value_klass); } else if (n->is_Phi()) { assert(_can_reshape, "can only handle phis during IGVN"); Node* clone = get_clone(n); @@ -3174,11 +3203,11 @@ class PushInlineTypeDown { } } while (casts.size() != 0) { - // Push the cast(s) through the InlineTypeNode + // Push the cast(s) through the ValueTypeNode Node *cast = casts.pop()->clone(); - cast->set_req_X(1, n->as_InlineType()->get_oop(), _phase); + cast->set_req_X(1, n->as_ValueType()->get_oop(), _phase); n = n->clone(); - n->as_InlineType()->set_oop(*_phase, _phase->transform(cast)); + n->as_ValueType()->set_oop(*_phase, _phase->transform(cast)); n = _phase->transform(n); if (n->is_top()) { if (casts.size() > 0) { @@ -3189,9 +3218,9 @@ class PushInlineTypeDown { } } bool transform = !_can_reshape && (i == (phi->req() - 1)); // Transform phis on last merge - assert(n->is_top() || n->is_InlineType(), "Only InlineType or top at this point."); - if (n->is_InlineType()) { - vt->merge_with(_phase, n->as_InlineType(), i, transform); + assert(n->is_top() || n->is_ValueType(), "Only ValueType or top at this point."); + if (n->is_ValueType()) { + vt->merge_with(_phase, n->as_ValueType(), i, transform); } // else nothing to do: phis above vt created by clone_with_phis are initialized to top already. } return vt; @@ -3201,7 +3230,7 @@ class PushInlineTypeDown { PhiNode* _root_phi; PhaseGVN* _phase; bool _can_reshape; - ciInlineKlass* _inline_klass; + ciValueKlass* _value_klass; Unique_Node_List _nodes_from_phi; Unique_Node_List _subgraph_to_clone; Node_List _clones; @@ -3209,8 +3238,8 @@ class PushInlineTypeDown { public: - PushInlineTypeDown(PhiNode *root_phi, PhaseGVN *phase, bool can_reshape) - : _root_phi(root_phi), _phase(phase), _can_reshape(can_reshape), _inline_klass(nullptr) { + PushValueTypeDown(PhiNode *root_phi, PhaseGVN *phase, bool can_reshape) + : _root_phi(root_phi), _phase(phase), _can_reshape(can_reshape), _value_klass(nullptr) { collect_nodes_from_phi(); } @@ -3237,10 +3266,10 @@ class PushInlineTypeDown { continue; } const Type* type = _phase->type(n); - if (n->is_InlineType()) { - if (_inline_klass == nullptr) { - _inline_klass = type->inline_klass(); - } else if (_inline_klass != type->inline_klass()) { + if (n->is_ValueType()) { + if (_value_klass == nullptr) { + _value_klass = type->value_klass(); + } else if (_value_klass != type->value_klass()) { return false; } continue; @@ -3250,12 +3279,12 @@ class PushInlineTypeDown { } } - if (_inline_klass == nullptr) { + if (_value_klass == nullptr) { return false; } // Check if cast nodes can be pushed through - const Type* t = Type::get_const_type(_inline_klass); + const Type* t = Type::get_const_type(_value_klass); for (uint next = 0; next < _nodes_from_phi.size(); next++) { Node* n = _nodes_from_phi.at(next); if (n->is_ConstraintCast()) { @@ -3280,31 +3309,31 @@ class PushInlineTypeDown { }; -// Check recursively if inputs are either an inline type, constant null +// Check recursively if inputs are either a value type, constant null // or another Phi (including self references through data loops). If so, -// push the inline types down through the phis to enable folding of loads. -Node* PhiNode::try_push_inline_types_down(PhaseGVN* phase, const bool can_reshape) { - if (!can_be_inline_type()) { +// push the value types down through the phis to enable folding of loads. +Node* PhiNode::try_push_value_types_down(PhaseGVN* phase, const bool can_reshape) { + if (!can_be_value_type()) { return this; } ResourceMark rm; - PushInlineTypeDown push_inline_type_down(this, phase, can_reshape); - if (push_inline_type_down.can_do_it()) { - return push_inline_type_down.do_it(); + PushValueTypeDown push_value_type_down(this, phase, can_reshape); + if (push_value_type_down.can_do_it()) { + return push_value_type_down.do_it(); } return this; } #ifdef ASSERT -bool PhiNode::can_push_inline_types_down(PhaseGVN* phase) { - if (!can_be_inline_type()) { +bool PhiNode::can_push_value_types_down(PhaseGVN* phase) { + if (!can_be_value_type()) { return false; } ResourceMark rm; - PushInlineTypeDown push_inline_type_down(this, phase, false); - return push_inline_type_down.can_do_it(); + PushValueTypeDown push_value_type_down(this, phase, false); + return push_value_type_down.can_do_it(); } #endif // ASSERT @@ -3698,7 +3727,7 @@ Node* CreateExNode::Identity(PhaseGVN* phase) { // If the CatchProj is optimized away, then we just carry the // exception oop through. - // CheckCastPPNode::Ideal() for inline types reuses the exception + // CheckCastPPNode::Ideal() for value types reuses the exception // paths of a call to perform an allocation: we can see a Phi here. if (in(1)->is_Phi()) { return this; diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index 012fd3735bab..8a920a865746 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -239,6 +239,7 @@ class PhiNode : public TypeNode { LoopSafety simple_data_loop_check(Node *in) const; // Is it unsafe data loop? It becomes a dead loop if this phi node removed. bool is_unsafe_data_reference(Node *in) const; + bool is_dead_phi(); int is_diamond_phi() const; bool try_clean_memory_phi(PhaseIterGVN* igvn); virtual int Opcode() const; @@ -259,12 +260,12 @@ class PhiNode : public TypeNode { type()->higher_equal(tp); } - bool can_be_inline_type() const { - return Arguments::is_valhalla_enabled() && _type->isa_instptr() && _type->is_instptr()->can_be_inline_type(); + bool can_be_value_type() const { + return Arguments::is_valhalla_enabled() && _type->isa_instptr() && _type->is_instptr()->can_be_value_type(); } - Node* try_push_inline_types_down(PhaseGVN* phase, bool can_reshape); - DEBUG_ONLY(bool can_push_inline_types_down(PhaseGVN* phase);) + Node* try_push_value_types_down(PhaseGVN* phase, bool can_reshape); + DEBUG_ONLY(bool can_push_value_types_down(PhaseGVN* phase);) virtual const Type* Value(PhaseGVN* phase) const; virtual Node* Identity(PhaseGVN* phase); diff --git a/src/hotspot/share/opto/classes.cpp b/src/hotspot/share/opto/classes.cpp index 891381cc38e4..5843531d9e1a 100644 --- a/src/hotspot/share/opto/classes.cpp +++ b/src/hotspot/share/opto/classes.cpp @@ -31,7 +31,7 @@ #include "opto/convertnode.hpp" #include "opto/countbitsnode.hpp" #include "opto/divnode.hpp" -#include "opto/inlinetypenode.hpp" +#include "opto/int128tnode.hpp" #include "opto/intrinsicnode.hpp" #include "opto/locknode.hpp" #include "opto/loopnode.hpp" @@ -48,6 +48,7 @@ #include "opto/rootnode.hpp" #include "opto/subnode.hpp" #include "opto/subtypenode.hpp" +#include "opto/valuetypenode.hpp" #include "opto/vectornode.hpp" #include "utilities/macros.hpp" #if INCLUDE_SHENANDOAHGC diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp index 2ae993e535dd..12a7021e39f3 100644 --- a/src/hotspot/share/opto/classes.hpp +++ b/src/hotspot/share/opto/classes.hpp @@ -34,6 +34,7 @@ macro(AbsL) macro(AddD) macro(AddF) macro(AddI) +macro(AddI128T) macro(AddL) macro(AddP) macro(AddHF) @@ -368,6 +369,7 @@ macro(SubHF) macro(SubD) macro(SubF) macro(SubI) +macro(SubI128T) macro(SubL) macro(TailCall) macro(TailJump) @@ -381,7 +383,7 @@ macro(URShiftI) macro(URShiftL) macro(XorI) macro(XorL) -macro(InlineType) +macro(ValueType) macro(LoadFlat) macro(StoreFlat) macro(Vector) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 8d8e4111f922..56aac0457be3 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -25,8 +25,8 @@ #include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" #include "ci/ciFlatArray.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciReplay.hpp" +#include "ci/ciValueKlass.hpp" #include "classfile/javaClasses.hpp" #include "code/aotCodeCache.hpp" #include "code/exceptionHandlerTable.hpp" @@ -63,7 +63,6 @@ #include "opto/divnode.hpp" #include "opto/escape.hpp" #include "opto/idealGraphPrinter.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/locknode.hpp" #include "opto/loopnode.hpp" #include "opto/machnode.hpp" @@ -86,6 +85,7 @@ #include "opto/runtime.hpp" #include "opto/stringopts.hpp" #include "opto/type.hpp" +#include "opto/valuetypenode.hpp" #include "opto/vector.hpp" #include "opto/vectornode.hpp" #include "runtime/arguments.hpp" @@ -417,8 +417,8 @@ void Compile::remove_useless_node(Node* dead) { if (dead->for_post_loop_opts_igvn()) { remove_from_post_loop_opts_igvn(dead); } - if (dead->is_InlineType()) { - remove_inline_type(dead); + if (dead->is_ValueType()) { + remove_value_type(dead); } if (dead->is_LoadFlat() || dead->is_StoreFlat()) { remove_flat_access(dead); @@ -430,6 +430,7 @@ void Compile::remove_useless_node(Node* dead) { remove_useless_late_inlines( &_late_inlines, dead); remove_useless_late_inlines( &_string_late_inlines, dead); remove_useless_late_inlines( &_boxing_late_inlines, dead); + remove_useless_late_inlines( &_vector_late_inlines, dead); remove_useless_late_inlines(&_vector_reboxing_late_inlines, dead); if (dead->is_CallStaticJava()) { @@ -459,7 +460,7 @@ void Compile::disconnect_useless_nodes(Unique_Node_List& useful, Unique_Node_Lis n->raw_del_out(j); --j; --max; - if (child->is_data_proj_of_pure_function(n)) { + if (n->should_process_when_disconnect_output(child)) { worklist.push(n); } } @@ -480,7 +481,7 @@ void Compile::disconnect_useless_nodes(Unique_Node_List& useful, Unique_Node_Lis remove_useless_nodes(_expensive_nodes, useful); // remove useless expensive nodes remove_useless_nodes(_reachability_fences, useful); // remove useless node recorded for post loop opts IGVN pass remove_useless_nodes(_for_post_loop_igvn, useful); // remove useless node recorded for post loop opts IGVN pass - remove_useless_nodes(_inline_type_nodes, useful); // remove useless inline type nodes + remove_useless_nodes(_value_type_nodes, useful); // remove useless value type nodes remove_useless_nodes(_flat_access_nodes, useful); // remove useless flat access nodes #ifdef ASSERT if (_modified_nodes != nullptr) { @@ -500,6 +501,7 @@ void Compile::disconnect_useless_nodes(Unique_Node_List& useful, Unique_Node_Lis remove_useless_late_inlines( &_late_inlines, useful); remove_useless_late_inlines( &_string_late_inlines, useful); remove_useless_late_inlines( &_boxing_late_inlines, useful); + remove_useless_late_inlines( &_vector_late_inlines, useful); remove_useless_late_inlines(&_vector_reboxing_late_inlines, useful); DEBUG_ONLY(verify_graph_edges(true /*check for no_dead_code*/, root_and_safepoints);) } @@ -675,7 +677,7 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci, _strength_reduction(false), _do_cleanup(false), _has_reserved_stack_access(target->has_reserved_stack_access()), - _has_circular_inline_type(false), + _has_circular_value_type(false), #ifndef PRODUCT _igv_idx(0), _trace_opto_output(directive->TraceOptoOutputOption), @@ -694,7 +696,7 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci, _expensive_nodes(comp_arena(), 8, 0, nullptr), _reachability_fences(comp_arena(), 8, 0, nullptr), _for_post_loop_igvn(comp_arena(), 8, 0, nullptr), - _inline_type_nodes (comp_arena(), 8, 0, nullptr), + _value_type_nodes (comp_arena(), 8, 0, nullptr), _flat_access_nodes(comp_arena(), 8, 0, nullptr), _for_merge_stores_igvn(comp_arena(), 8, 0, nullptr), _unstable_if_traps(comp_arena(), 8, 0, nullptr), @@ -718,6 +720,7 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci, _string_late_inlines(comp_arena(), 2, 0, nullptr), _boxing_late_inlines(comp_arena(), 2, 0, nullptr), _vector_reboxing_late_inlines(comp_arena(), 2, 0, nullptr), + _vector_late_inlines(comp_arena(), 2, 0, nullptr), _late_inlines_pos(0), _has_mh_late_inlines(false), _oom(false), @@ -984,7 +987,7 @@ Compile::Compile(ciEnv* ci_env, _inlining_progress(false), _inlining_incrementally(false), _has_reserved_stack_access(false), - _has_circular_inline_type(false), + _has_circular_value_type(false), #ifndef PRODUCT _igv_idx(0), _trace_opto_output(directive->TraceOptoOutputOption), @@ -1776,7 +1779,7 @@ Compile::AliasType* Compile::find_alias_type(const TypePtr* adr_type, bool no_cr int field_offset = flat->is_aryptr()->field_offset().get(); if (flat->is_flat() && field_offset != Type::OffsetBot) { - ciInlineKlass* vk = elemtype->inline_klass(); + ciValueKlass* vk = elemtype->value_klass(); field_offset += vk->payload_offset(); field = vk->get_field_by_offset(field_offset, false); } @@ -1816,9 +1819,9 @@ Compile::AliasType* Compile::find_alias_type(const TypePtr* adr_type, bool no_cr // static field ciInstanceKlass* k = tinst->const_oop()->as_instance()->java_lang_Class_klass()->as_instance_klass(); field = k->get_field_by_offset(tinst->offset(), true); - } else if (tinst->is_inlinetypeptr()) { - // Inline type field - ciInlineKlass* vk = tinst->inline_klass(); + } else if (tinst->is_valueklassptr()) { + // Value type field + ciValueKlass* vk = tinst->value_klass(); field = vk->get_field_by_offset(tinst->offset(), false); } else { ciInstanceKlass *k = tinst->instance_klass(); @@ -1975,19 +1978,19 @@ void Compile::process_for_post_loop_opts_igvn(PhaseIterGVN& igvn) { } } -void Compile::add_inline_type(Node* n) { - assert(n->is_InlineType(), "unexpected node"); - _inline_type_nodes.push(n); +void Compile::add_value_type(Node* n) { + assert(n->is_ValueType(), "unexpected node"); + _value_type_nodes.push(n); } -void Compile::remove_inline_type(Node* n) { - assert(n->is_InlineType(), "unexpected node"); - if (_inline_type_nodes.contains(n)) { - _inline_type_nodes.remove(n); +void Compile::remove_value_type(Node* n) { + assert(n->is_ValueType(), "unexpected node"); + if (_value_type_nodes.contains(n)) { + _value_type_nodes.remove(n); } } -// Does the return value keep otherwise useless inline type allocations alive? +// Does the return value keep otherwise useless value type allocations alive? static bool return_val_keeps_allocations_alive(Node* ret_val) { ResourceMark rm; Unique_Node_List wq; @@ -1998,7 +2001,7 @@ static bool return_val_keeps_allocations_alive(Node* ret_val) { if (n->outcnt() > 1) { // Some other use for the allocation return false; - } else if (n->is_InlineType()) { + } else if (n->is_ValueType()) { wq.push(n->in(1)); } else if (n->is_Phi()) { for (uint j = 1; j < n->req(); j++) { @@ -2026,7 +2029,7 @@ bool Compile::clear_argument_if_only_used_as_buffer_at_calls(Node* result_cast, Node* u = n->fast_out(j); if (u->is_Phi()) { wq.push(u); - } else if (u->is_InlineType() && u->as_InlineType()->get_oop() == n) { + } else if (u->is_ValueType() && u->as_ValueType()->get_oop() == n) { wq.push(u); } else if (u->is_CallJava()) { CallJavaNode* call = u->as_CallJava(); @@ -2075,9 +2078,9 @@ bool Compile::clear_argument_if_only_used_as_buffer_at_calls(Node* result_cast, return true; } -void Compile::process_inline_types(PhaseIterGVN &igvn, bool remove) { +void Compile::process_value_types(PhaseIterGVN &igvn, bool remove) { // Make sure that the return value does not keep an otherwise unused allocation alive - if (tf()->returns_inline_type_as_fields()) { + if (tf()->returns_value_type_as_fields()) { Node* ret = nullptr; for (uint i = 1; i < root()->req(); i++) { Node* in = root()->in(i); @@ -2090,7 +2093,7 @@ void Compile::process_inline_types(PhaseIterGVN &igvn, bool remove) { Node* ret_val = ret->in(TypeFunc::Parms); if (igvn.type(ret_val)->isa_oopptr() && return_val_keeps_allocations_alive(ret_val)) { - igvn.replace_input_of(ret, TypeFunc::Parms, InlineTypeNode::tagged_klass(igvn.type(ret_val)->inline_klass(), igvn)); + igvn.replace_input_of(ret, TypeFunc::Parms, ValueTypeNode::tagged_klass(igvn.type(ret_val)->value_klass(), igvn)); assert(ret_val->outcnt() == 0, "should be dead now"); igvn.remove_dead_node(ret_val, PhaseIterGVN::NodeOrigin::Graph); } @@ -2105,23 +2108,23 @@ void Compile::process_inline_types(PhaseIterGVN &igvn, bool remove) { Node* result_cast = allocate->result_cast(); if (result_cast != nullptr) { const Type* result_type = igvn.type(result_cast); - if (result_type->is_inlinetypeptr()) { + if (result_type->is_valueklassptr()) { clear_argument_if_only_used_as_buffer_at_calls(result_cast, igvn); } } } } - if (_inline_type_nodes.length() == 0) { + if (_value_type_nodes.length() == 0) { // keep the graph canonical igvn.optimize(); return; } - // Scalarize inline types in safepoint debug info. + // Scalarize value types in safepoint debug info. // Delay this until all inlining is over to avoid getting inconsistent debug info. set_scalarize_in_safepoints(true); - for (int i = _inline_type_nodes.length()-1; i >= 0; i--) { - InlineTypeNode* vt = _inline_type_nodes.at(i)->as_InlineType(); + for (int i = _value_type_nodes.length()-1; i >= 0; i--) { + ValueTypeNode* vt = _value_type_nodes.at(i)->as_ValueType(); if (!vt->make_scalar_in_safepoints(&igvn)) { record_failure("out of nodes during scalarization"); return; @@ -2129,9 +2132,9 @@ void Compile::process_inline_types(PhaseIterGVN &igvn, bool remove) { igvn.record_for_igvn(vt); } if (remove) { - // Remove inline type nodes by replacing them with their oop input - while (_inline_type_nodes.length() > 0) { - InlineTypeNode* vt = _inline_type_nodes.pop()->as_InlineType(); + // Remove value type nodes by replacing them with their oop input + while (_value_type_nodes.length() > 0) { + ValueTypeNode* vt = _value_type_nodes.pop()->as_ValueType(); if (vt->outcnt() == 0) { igvn.remove_dead_node(vt, PhaseIterGVN::NodeOrigin::Graph); continue; @@ -2140,7 +2143,7 @@ void Compile::process_inline_types(PhaseIterGVN &igvn, bool remove) { DEBUG_ONLY(bool must_be_buffered = false); Node* u = vt->out(i); // Check if any users are blackholes. If so, rewrite them to use either the - // allocated buffer, or individual components, instead of the inline type node + // allocated buffer, or individual components, instead of the value type node // that goes away. if (u->is_Blackhole()) { BlackholeNode* bh = u->as_Blackhole(); @@ -2165,9 +2168,9 @@ void Compile::process_inline_types(PhaseIterGVN &igvn, bool remove) { igvn.record_for_igvn(bh); } #ifdef ASSERT - // Verify that inline type is buffered when replacing by oop - else if (u->is_InlineType()) { - // InlineType uses don't need buffering because they are about to be replaced as well + // Verify that value type is buffered when replacing by oop + else if (u->is_ValueType()) { + // ValueType uses don't need buffering because they are about to be replaced as well } else { must_be_buffered = true; } @@ -2408,7 +2411,7 @@ void Compile::adjust_flat_array_access_aliases(PhaseIterGVN& igvn) { assert(klass_type->klass_is_exact(), "must be an exact klass"); ciArrayKlass* klass = klass_type->exact_klass()->as_array_klass(); assert(klass->is_flat_array_klass(), "must be a flat array"); - ciInlineKlass* elem_klass = klass->element_klass()->as_inline_klass(); + ciValueKlass* elem_klass = klass->element_klass()->as_value_klass(); const TypeAryPtr* oop_type = klass_type->as_exact_instance_type()->is_aryptr(); assert(oop_type->klass_is_exact(), "must be an exact klass"); @@ -2860,6 +2863,25 @@ void Compile::shuffle_late_inlines() { shuffle_array(*C, _late_inlines); } +void Compile::process_vector_late_inlines() { + for (int i = 0; i < _vector_late_inlines.length(); i++) { + CallGenerator* cg = _vector_late_inlines.at(i); + + // When a vector intrinsic fails, set_generator(cg) caches the + // LateInlineVectorCallGenerator on the call node to allow retries + // if IGVN optimizes the call node's inputs. If the call node is not + // on the IGVN worklist when cleanup runs, CallStaticJavaNode::Ideal + // does not fire and the cached generator persists. Once _late_inlines + // drains and we commit to the fallback here, clear the stale generator + // to prevent a subsequent IGVN pass from re-registering the intrinsic + // attempt into _late_inlines alongside the fallback, which would create + // duplicate call_node entries. + cg->call_node()->as_CallJava()->set_generator(nullptr); + add_late_inline(cg); + } + _vector_late_inlines.clear(); +} + // Perform incremental inlining until bound on number of live nodes is reached void Compile::inline_incrementally(PhaseIterGVN& igvn) { TracePhase tp(_t_incrInline); @@ -2917,6 +2939,10 @@ void Compile::inline_incrementally(PhaseIterGVN& igvn) { print_method(PHASE_INCREMENTAL_INLINE_STEP, 3); if (failing()) return; + + if (_late_inlines.length() == 0) { + process_vector_late_inlines(); + } } igvn_worklist()->ensure_empty(); // should be done with igvn @@ -3108,8 +3134,8 @@ void Compile::Optimize() { // safepoints remove_root_to_sfpts_edges(igvn); - // Process inline type nodes now that all inlining is over - process_inline_types(igvn); + // Process value type nodes now that all inlining is over + process_value_types(igvn); if (failing()) { return; } @@ -3296,9 +3322,9 @@ void Compile::Optimize() { } assert(_late_inlines.length() == 0, "late inline queue must be drained"); - // Process inline types before macro expansion. Otherwise, we will not be able to + // Process value types before macro expansion. Otherwise, we will not be able to // remove unused allocations because it cannot match the expanded allocation. - process_inline_types(igvn); + process_value_types(igvn); if (failing()) { return; } @@ -3332,9 +3358,9 @@ void Compile::Optimize() { print_method(PHASE_AFTER_MACRO_EXPANSION, 2); } - // Process inline type nodes again and remove them. From here + // Process value type nodes again and remove them. From here // on we don't need to keep track of field values anymore. - process_inline_types(igvn, /* remove= */ true); + process_value_types(igvn, /* remove= */ true); if (failing()) { return; } @@ -4678,9 +4704,9 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f break; } #ifdef ASSERT - case Op_InlineType: { + case Op_ValueType: { n->dump(-1); - assert(false, "inline type node was not removed"); + assert(false, "value type node was not removed"); break; } case Op_ConNKlass: { @@ -5139,7 +5165,7 @@ void Compile::verify_bidirectional_edges(Unique_Node_List& visited, const Unique } else if (in == nullptr) { assert(i == 0 || i >= n->req() || n->is_Region() || n->is_Phi() || n->is_ArrayCopy() || - (n->is_Allocate() && i >= AllocateNode::InlineType) || + (n->is_Allocate() && i >= AllocateNode::ValueType) || (n->is_Unlock() && i == (n->req() - 1)) || (n->is_MemBar() && i == 5), // the precedence edge to a membar can be removed during macro node expansion "only region, phi, arraycopy, allocate, unlock or membar nodes have null data edges"); @@ -5294,10 +5320,10 @@ Compile::SubTypeCheckResult Compile::static_subtype_check(const TypeKlassPtr* su int ignored; superelem = superk->is_aryklassptr()->base_element_type(ignored); - // Do not fold the subtype check to an array klass pointer comparison for null-able inline type arrays + // Do not fold the subtype check to an array klass pointer comparison for null-able value type arrays // because null-free [LMyValue <: null-able [LMyValue but the klasses are different. Perform a full test. if (!superk->is_aryklassptr()->is_null_free() && superk->is_aryklassptr()->elem()->isa_instklassptr() && - superk->is_aryklassptr()->elem()->is_instklassptr()->instance_klass()->is_inlinetype()) { + superk->is_aryklassptr()->elem()->is_instklassptr()->instance_klass()->is_value_klass()) { return SSC_full_test; } } @@ -5399,6 +5425,9 @@ void Compile::log_inline_id(CallGenerator* cg) { } void Compile::log_inline_failure(const char* msg) { + if (inline_printer()->is_suspended()) { + return; + } if (C->log() != nullptr) { C->log()->inline_fail(msg); } diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index f931deaad344..f8542a142332 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -100,7 +100,7 @@ class TypeVect; class Type_Array; class Unique_Node_List; class UnstableIfTrap; -class InlineTypeNode; +class ValueTypeNode; class nmethod; class Node_Stack; struct Final_Reshape_Counts; @@ -348,7 +348,7 @@ class Compile : public Phase { bool _has_stringbuilder; // True StringBuffers or StringBuilders are allocated bool _has_boxed_value; // True if a boxed object is allocated bool _has_reserved_stack_access; // True if the method or an inlined method is annotated with ReservedStackAccess - bool _has_circular_inline_type; // True if method loads an inline type with a circular, non-flat field + bool _has_circular_value_type; // True if method loads a value type with a circular, non-flat field bool _needs_nm_slot; // True if an extra stack slot is needed to hold the null marker at scalarized returns uint _max_vector_size; // Maximum size of generated vectors bool _clear_upper_avx; // Clear upper bits of ymm registers using vzeroupper @@ -379,7 +379,7 @@ class Compile : public Phase { int _loop_opts_cnt; // loop opts round bool _has_flat_accesses; // Any known flat array accesses? bool _flat_accesses_share_alias; // Initially all flat array share a single slice - bool _scalarize_in_safepoints; // Scalarize inline types in safepoint debug info + bool _scalarize_in_safepoints; // Scalarize value types in safepoint debug info // Compilation environment. Arena _comp_arena; // Arena with lifetime equivalent to Compile @@ -398,7 +398,7 @@ class Compile : public Phase { GrowableArray _expensive_nodes; // List of nodes that are expensive to compute and that we'd better not let the GVN freely common GrowableArray _reachability_fences; // List of reachability fences GrowableArray _for_post_loop_igvn; // List of nodes for IGVN after loop opts are over - GrowableArray _inline_type_nodes; // List of InlineType nodes + GrowableArray _value_type_nodes; // List of ValueType nodes GrowableArray _flat_access_nodes; // List of LoadFlat and StoreFlat nodes GrowableArray _for_merge_stores_igvn; // List of nodes for IGVN merge stores GrowableArray _unstable_if_traps; // List of ifnodes after IGVN @@ -493,6 +493,7 @@ class Compile : public Phase { GrowableArray _boxing_late_inlines; // same but for boxing operations GrowableArray _vector_reboxing_late_inlines; // same but for vector reboxing operations + GrowableArray _vector_late_inlines; // inline fallback implementation for failed intrinsics int _late_inlines_pos; // Where in the queue should the next late inlining candidate go (emulate depth first inlining) bool _has_mh_late_inlines; // Can there still be a method handle late inlining pending? @@ -521,6 +522,12 @@ class Compile : public Phase { InlinePrinter _inline_printer; public: + + void add_vector_late_inline(CallGenerator* cg) { + _vector_late_inlines.push(cg); + } + void process_vector_late_inlines(); + void* barrier_set_state() const { return _barrier_set_state; } InlinePrinter* inline_printer() { return &_inline_printer; } @@ -639,8 +646,8 @@ class Compile : public Phase { void set_has_boxed_value(bool z) { _has_boxed_value = z; } bool has_reserved_stack_access() const { return _has_reserved_stack_access; } void set_has_reserved_stack_access(bool z) { _has_reserved_stack_access = z; } - bool has_circular_inline_type() const { return _has_circular_inline_type; } - void set_has_circular_inline_type(bool z) { _has_circular_inline_type = z; } + bool has_circular_value_type() const { return _has_circular_value_type; } + void set_has_circular_value_type(bool z) { _has_circular_value_type = z; } uint max_vector_size() const { return _max_vector_size; } void set_max_vector_size(uint s) { _max_vector_size = s; } bool clear_upper_avx() const { return _clear_upper_avx; } @@ -681,7 +688,7 @@ class Compile : public Phase { bool scalarize_in_safepoints() const { return _scalarize_in_safepoints; } void set_scalarize_in_safepoints(bool z) { _scalarize_in_safepoints = z; } - // Support for scalarized inline type calling convention + // Support for scalarized value type calling convention bool has_scalarized_args() const { return _method != nullptr && _method->has_scalarized_args(); } bool needs_stack_repair() const { return _method != nullptr && _method->needs_stack_repair(); } bool needs_nm_slot() const { return _needs_nm_slot; } @@ -830,13 +837,13 @@ class Compile : public Phase { void remove_from_post_loop_opts_igvn(Node* n); void process_for_post_loop_opts_igvn(PhaseIterGVN& igvn); - // Keep track of inline type nodes for later processing - void add_inline_type(Node* n); - void remove_inline_type(Node* n); + // Keep track of value type nodes for later processing + void add_value_type(Node* n); + void remove_value_type(Node* n); bool clear_argument_if_only_used_as_buffer_at_calls(Node* result_cast, PhaseIterGVN& igvn); - void process_inline_types(PhaseIterGVN &igvn, bool remove = false); + void process_value_types(PhaseIterGVN &igvn, bool remove = false); void add_flat_access(Node* n); void remove_flat_access(Node* n); diff --git a/src/hotspot/share/opto/convertnode.cpp b/src/hotspot/share/opto/convertnode.cpp index cb710864c722..0ba49e5299d7 100644 --- a/src/hotspot/share/opto/convertnode.cpp +++ b/src/hotspot/share/opto/convertnode.cpp @@ -27,12 +27,12 @@ #include "opto/connode.hpp" #include "opto/convertnode.hpp" #include "opto/divnode.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/matcher.hpp" #include "opto/movenode.hpp" #include "opto/mulnode.hpp" #include "opto/phaseX.hpp" #include "opto/subnode.hpp" +#include "opto/valuetypenode.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/checkedCast.hpp" @@ -67,10 +67,10 @@ const Type* Conv2BNode::Value(PhaseGVN* phase) const { } Node* Conv2BNode::Ideal(PhaseGVN* phase, bool can_reshape) { - if (in(1)->is_InlineType()) { - // Null checking a scalarized but nullable inline type. Check the null marker + if (in(1)->is_ValueType()) { + // Null checking a scalarized but nullable value type. Check the null marker // input instead of the oop input to avoid keeping buffer allocations alive. - set_req_X(1, in(1)->as_InlineType()->get_null_marker(), phase); + set_req_X(1, in(1)->as_ValueType()->get_null_marker(), phase); return this; } if (!Matcher::match_rule_supported(Op_Conv2B)) { diff --git a/src/hotspot/share/opto/doCall.cpp b/src/hotspot/share/opto/doCall.cpp index 4dc5404e5989..732a2f2fe2fc 100644 --- a/src/hotspot/share/opto/doCall.cpp +++ b/src/hotspot/share/opto/doCall.cpp @@ -40,12 +40,12 @@ #include "opto/castnode.hpp" #include "opto/cfgnode.hpp" #include "opto/graphKit.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/mulnode.hpp" #include "opto/parse.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" #include "opto/subnode.hpp" +#include "opto/valuetypenode.hpp" #include "prims/methodHandles.hpp" #include "runtime/sharedRuntime.hpp" #include "utilities/macros.hpp" @@ -170,6 +170,21 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool cg_intrinsic = cg; cg = nullptr; } else if (IncrementalInline && should_delay_vector_inlining(callee, jvms)) { + if (IncrementalInlineVector && allow_inline) { + // Try to incrementally inline fallback implementation if intrinsification attempt fails. + CallGenerator* fallback_cg; + { + InlinePrinterSuspendScope guard(C->inline_printer()); + fallback_cg = call_generator(callee, vtable_index, call_does_dispatch, jvms, + true /*allow_inline*/, prof_factor, + speculative_receiver_type, false /*allow_intrinsics*/); + } + if (fallback_cg != nullptr && fallback_cg->is_parse()) { + return CallGenerator::for_vector_late_inline(callee, cg, fallback_cg); + } + // Fallback not inlineable by regular heuristics; fall through. + } + // Don't try to inline fallback implementation. return CallGenerator::for_late_inline(callee, cg); } else { return cg; @@ -835,22 +850,22 @@ void Parse::do_call() { if (!rtype->is_void()) { Node* retnode = peek(); const Type* rettype = gvn().type(retnode); - if (!cg->method()->return_value_is_larval() && !retnode->is_InlineType() && rettype->is_inlinetypeptr()) { - retnode = InlineTypeNode::make_from_oop(this, retnode, rettype->inline_klass()); + if (!cg->method()->return_value_is_larval() && !retnode->is_ValueType() && rettype->is_valueklassptr()) { + retnode = ValueTypeNode::make_from_oop(this, retnode, rettype->value_klass()); dec_sp(1); push(retnode); } } if (cg->method()->receiver_maybe_larval() && receiver != nullptr && - !receiver->is_InlineType() && gvn().type(receiver)->is_inlinetypeptr()) { - InlineTypeNode* non_larval = InlineTypeNode::make_from_oop(this, receiver, gvn().type(receiver)->inline_klass()); + !receiver->is_ValueType() && gvn().type(receiver)->is_valueklassptr()) { + ValueTypeNode* non_larval = ValueTypeNode::make_from_oop(this, receiver, gvn().type(receiver)->value_klass()); // Relinquish the oop input, we will delay the allocation to the point it is needed, see the - // comments in InlineTypeNode::Ideal for more details + // comments in ValueTypeNode::Ideal for more details non_larval = non_larval->clone_if_required(&gvn(), nullptr); non_larval->set_oop(gvn(), null()); non_larval->set_is_buffered(gvn(), false); - non_larval = gvn().transform(non_larval)->as_InlineType(); + non_larval = gvn().transform(non_larval)->as_ValueType(); map()->replace_edge(receiver, non_larval); } } diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 5938d6e73b9a..cab3f70057b2 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -37,13 +37,13 @@ #include "opto/cfgnode.hpp" #include "opto/compile.hpp" #include "opto/escape.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/locknode.hpp" #include "opto/macro.hpp" #include "opto/movenode.hpp" #include "opto/narrowptrnode.hpp" #include "opto/phaseX.hpp" #include "opto/rootnode.hpp" +#include "opto/valuetypenode.hpp" #include "utilities/macros.hpp" ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn, int invocation) : @@ -1349,8 +1349,8 @@ bool ConnectionGraph::reduce_phi_on_safepoints_helper(Node* ophi, Node* cast, No Unique_Node_List value_worklist; #ifdef ASSERT const Type* res_type = alloc->result_cast()->bottom_type(); - if (res_type->is_inlinetypeptr() && !Compile::current()->has_circular_inline_type()) { - assert(!ophi->as_Phi()->can_push_inline_types_down(_igvn), "missed earlier scalarization opportunity"); + if (res_type->is_valueklassptr() && !Compile::current()->has_circular_value_type()) { + assert(!ophi->as_Phi()->can_push_value_types_down(_igvn), "missed earlier scalarization opportunity"); } #endif SafePointScalarObjectNode* sobj = mexp.create_scalarized_object_description(alloc, sfpt, &value_worklist); @@ -1369,12 +1369,12 @@ bool ConnectionGraph::reduce_phi_on_safepoints_helper(Node* ophi, Node* cast, No // Register the scalarized object as a candidate for reallocation smerge->add_req(sobj); - // Scalarize inline types that were added to the safepoint. + // Scalarize value types that were added to the safepoint. // Don't allow linking a constant oop (if available) for flat array elements // because Deoptimization::reassign_flat_array_elements needs field values. const bool allow_oop = !merge_t->is_flat(); for (uint j = 0; j < value_worklist.size(); ++j) { - InlineTypeNode* vt = value_worklist.at(j)->as_InlineType(); + ValueTypeNode* vt = value_worklist.at(j)->as_ValueType(); if (!vt->make_scalar_in_safepoints(_igvn, allow_oop)) { sfpt->restore_non_debug_edges(non_debug_edges_worklist); return false; @@ -1628,7 +1628,7 @@ void ConnectionGraph::add_proj(Node* n, Unique_Node_List* delayed_worklist) { add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(0), delayed_worklist); } else if (n->as_Proj()->_con >= TypeFunc::Parms && n->in(0)->is_Call() && n->bottom_type()->isa_ptr()) { CallNode* call = n->in(0)->as_Call(); - assert(call->tf()->returns_inline_type_as_fields(), ""); + assert(call->tf()->returns_value_type_as_fields(), ""); if (n->as_Proj()->_con == TypeFunc::Parms || !returns_an_argument(call)) { // either: // - not an argument returned @@ -1675,7 +1675,7 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de (n->is_CallStaticJava() && n->as_CallStaticJava()->is_boxing_method())) { add_call_node(n->as_Call()); - } else if (n->as_Call()->tf()->returns_inline_type_as_fields()) { + } else if (n->as_Call()->tf()->returns_value_type_as_fields()) { bool returns_oop = false; for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax && !returns_oop; i++) { ProjNode* pn = n->fast_out(i)->as_Proj(); @@ -1718,7 +1718,7 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de map_ideal_node(n, phantom_obj); break; } - case Op_InlineType: + case Op_ValueType: case Op_CastPP: case Op_CheckCastPP: case Op_EncodeP: @@ -1894,7 +1894,7 @@ void ConnectionGraph::add_final_edges(Node *n) { add_base(n_ptn->as_Field(), ptn_base); break; } - case Op_InlineType: + case Op_ValueType: case Op_CastPP: case Op_CheckCastPP: case Op_EncodeP: @@ -1949,8 +1949,8 @@ void ConnectionGraph::add_final_edges(Node *n) { } case Op_StoreFlat: { // StoreFlat globally escapes its stored flattened fields - InlineTypeNode* value = n->as_StoreFlat()->value(); - ciInlineKlass* vk = _igvn->type(value)->inline_klass(); + ValueTypeNode* value = n->as_StoreFlat()->value(); + ciValueKlass* vk = _igvn->type(value)->value_klass(); for (int i = 0; i < vk->nof_nonstatic_fields(); i++) { ciField* field = vk->nonstatic_field_at(i); if (field->type()->is_primitive_type()) { @@ -2075,7 +2075,7 @@ void ConnectionGraph::add_to_congraph_unsafe_access(Node* n, uint opcode, Unique } #endif } else { - // Ignore copy the displaced header to the BoxNode (OSR compilation). + // Ignore initialization of the BoxLock (OSR compilation). if (adr->is_BoxLock()) { return; } @@ -2285,7 +2285,7 @@ bool ConnectionGraph::returns_an_argument(CallNode* call) { if (scalarized_arg && !compatible_return(call->as_CallJava(), i)) { return false; } - if (call->tf()->returns_inline_type_as_fields() != scalarized_arg) { + if (call->tf()->returns_value_type_as_fields() != scalarized_arg) { return false; } ret_arg = true; @@ -2299,7 +2299,7 @@ bool ConnectionGraph::returns_an_argument(CallNode* call) { } void ConnectionGraph::add_call_node(CallNode* call) { - assert(call->returns_pointer() || call->tf()->returns_inline_type_as_fields(), "only for call which returns pointer"); + assert(call->returns_pointer() || call->tf()->returns_value_type_as_fields(), "only for call which returns pointer"); uint call_idx = call->_idx; if (call->is_Allocate()) { Node* k = call->in(AllocateNode::KlassNode); @@ -2376,8 +2376,8 @@ void ConnectionGraph::add_call_node(CallNode* call) { if (meth == nullptr) { const char* name = call->as_CallStaticJava()->_name; assert(call->as_CallStaticJava()->is_call_to_multianewarray_stub() || - strncmp(name, "load_unknown_inline", 19) == 0 || - strncmp(name, "store_inline_type_fields_to_buf", 31) == 0, "TODO: add failed case check"); + strncmp(name, "load_unknown_value", 18) == 0 || + strncmp(name, "store_value_type_fields_to_buf", 30) == 0, "TODO: add failed case check"); // Returns a newly allocated non-escaped object. add_java_object(call, PointsToNode::NoEscape); set_not_scalar_replaceable(ptnode_adr(call_idx) NOT_PRODUCT(COMMA "is result of multinewarray")); @@ -2412,7 +2412,7 @@ void ConnectionGraph::add_call_node(CallNode* call) { // For scalarized argument/return: process_call_arguments() adds an edge between a call projection for a field // and the argument input to the call for that field. An edge is added between the projection for the returned // buffer and the call. - if (returns_an_argument(call) && !call->tf()->returns_inline_type_as_fields()) { + if (returns_an_argument(call) && !call->tf()->returns_value_type_as_fields()) { // returns non scalarized argument add_local_var(call, PointsToNode::ArgEscape); } else { @@ -2492,7 +2492,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call) { (aat->isa_aryptr() && (aat->isa_aryptr()->elem() == Type::BOTTOM || aat->isa_aryptr()->elem()->make_oopptr() != nullptr)) || (aat->isa_aryptr() && aat->isa_aryptr()->elem() != nullptr && aat->isa_aryptr()->is_flat() && - aat->isa_aryptr()->elem()->inline_klass()->contains_oops())); + aat->isa_aryptr()->elem()->value_klass()->contains_oops())); if (i == TypeFunc::Parms) { src_has_oops = arg_has_oops; } @@ -2559,9 +2559,9 @@ void ConnectionGraph::process_call_arguments(CallNode *call) { strcmp(call->as_CallLeaf()->_name, "montgomery_multiply") == 0 || strcmp(call->as_CallLeaf()->_name, "montgomery_square") == 0 || strcmp(call->as_CallLeaf()->_name, "vectorizedMismatch") == 0 || - strcmp(call->as_CallLeaf()->_name, "load_unknown_inline") == 0 || - strcmp(call->as_CallLeaf()->_name, "store_unknown_inline") == 0 || - strcmp(call->as_CallLeaf()->_name, "store_inline_type_fields_to_buf") == 0 || + strcmp(call->as_CallLeaf()->_name, "load_unknown_value") == 0 || + strcmp(call->as_CallLeaf()->_name, "store_unknown_value") == 0 || + strcmp(call->as_CallLeaf()->_name, "store_value_type_fields_to_buf") == 0 || strcmp(call->as_CallLeaf()->_name, "bigIntegerRightShiftWorker") == 0 || strcmp(call->as_CallLeaf()->_name, "bigIntegerLeftShiftWorker") == 0 || strcmp(call->as_CallLeaf()->_name, "vectorizedMismatch") == 0 || @@ -3111,7 +3111,7 @@ int ConnectionGraph::find_init_values_phantom(JavaObjectNode* pta) { // "known" unless they are initialized by arraycopy/clone. if (alloc->is_Allocate() && !pta->arraycopy_dst()) { if (alloc->as_Allocate()->in(AllocateNode::InitValue) != nullptr) { - // Null-free inline type arrays are initialized with an init value instead of null + // Null-free value type arrays are initialized with an init value instead of null init_val = ptnode_adr(alloc->as_Allocate()->in(AllocateNode::InitValue)->_idx); assert(init_val != nullptr, "init value should be registered"); } else { @@ -3124,8 +3124,8 @@ int ConnectionGraph::find_init_values_phantom(JavaObjectNode* pta) { if (alloc->is_CallStaticJava() && alloc->as_CallStaticJava()->method() == nullptr) { const char* name = alloc->as_CallStaticJava()->_name; assert(alloc->as_CallStaticJava()->is_call_to_multianewarray_stub() || - strncmp(name, "load_unknown_inline", 19) == 0 || - strncmp(name, "store_inline_type_fields_to_buf", 31) == 0, "sanity"); + strncmp(name, "load_unknown_value", 18) == 0 || + strncmp(name, "store_value_type_fields_to_buf", 30) == 0, "sanity"); } #endif // Non-escaped allocation returned from Java or runtime call have unknown values in fields. @@ -3602,7 +3602,7 @@ void ConnectionGraph::optimize_ideal_graph(GrowableArray& ptr_cmp_worklis AbstractLockNode* alock = n->as_AbstractLock(); if (!alock->is_non_esc_obj()) { const Type* obj_type = igvn->type(alock->obj_node()); - if (can_eliminate_lock(alock) && !obj_type->is_inlinetypeptr()) { + if (can_eliminate_lock(alock) && !obj_type->is_valueklassptr()) { assert(!alock->is_eliminated() || alock->is_coarsened(), "sanity"); // The lock could be marked eliminated by lock coarsening // code during first IGVN before EA. Replace coarsened flag @@ -3644,8 +3644,8 @@ void ConnectionGraph::optimize_ideal_graph(GrowableArray& ptr_cmp_worklis Node* storestore = storestore_worklist.at(i); Node* alloc = storestore->in(MemBarNode::Precedent)->in(0); if (alloc->is_Allocate() && not_global_escape(alloc)) { - if (alloc->in(AllocateNode::InlineType) != nullptr) { - // Non-escaping inline type buffer allocations don't require a membar + if (alloc->in(AllocateNode::ValueType) != nullptr) { + // Non-escaping value type buffer allocations don't require a membar storestore->as_MemBar()->remove(_igvn); } else { MemBarNode* mb = MemBarNode::make(C, Op_MemBarCPUOrder, Compile::AliasIdxBot); @@ -3874,7 +3874,7 @@ bool ConnectionGraph::is_oop_field(Node* n, int offset, bool* unsafe) { } else { const Type* elemtype = adr_type->is_aryptr()->elem(); if (adr_type->is_aryptr()->is_flat() && field_offset != Type::OffsetBot) { - ciInlineKlass* vk = elemtype->inline_klass(); + ciValueKlass* vk = elemtype->value_klass(); field_offset += vk->payload_offset(); ciField* field = vk->get_field_by_offset(field_offset, false); if (field != nullptr) { @@ -4272,7 +4272,7 @@ bool ConnectionGraph::split_AddP(Node *addp, Node *base) { intptr_t offs = (int)igvn->find_intptr_t_con(addp->in(AddPNode::Offset), Type::OffsetBot); assert(offs != Type::OffsetBot, "offset must be a constant"); if (base_t->isa_aryptr() != nullptr) { - // In the case of a flat inline type array, each field has its + // In the case of a flat value type array, each field has its // own slice so we need to extract the field being accessed from // the address computation t = base_t->isa_aryptr()->add_field_offset_and_offset(offs)->is_oopptr(); @@ -4306,7 +4306,7 @@ bool ConnectionGraph::split_AddP(Node *addp, Node *base) { } const TypePtr* tinst = base_t->add_offset(t->offset()); if (tinst->isa_aryptr() && t->isa_aryptr()) { - // In the case of a flat inline type array, each field has its + // In the case of a flat value type array, each field has its // own slice so we need to keep track of the field being accessed. tinst = tinst->is_aryptr()->with_field_offset(t->is_aryptr()->field_offset().get()); // Keep array properties (not flat/null-free) @@ -4998,7 +4998,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, const TypePtr* adr_type = proj->adr_type(); const TypePtr* new_adr_type = tinst->with_offset(adr_type->offset()); if (adr_type->isa_aryptr()) { - // In the case of a flat inline type array, each field has its own slice so we need a + // In the case of a flat value type array, each field has its own slice so we need a // NarrowMemProj for each field of the flat array elements new_adr_type = new_adr_type->is_aryptr()->with_field_offset(adr_type->is_aryptr()->field_offset().get()); } @@ -5188,8 +5188,8 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, memnode_worklist.push(use); } } else if (use->Opcode() == Op_Return) { - // Allocation is referenced by field of returned inline type - assert(_compile->tf()->returns_inline_type_as_fields(), "EA: unexpected reference by ReturnNode"); + // Allocation is referenced by field of returned value type + assert(_compile->tf()->returns_value_type_as_fields(), "EA: unexpected reference by ReturnNode"); } else { uint op = use->Opcode(); if ((op == Op_StrCompressedCopy || op == Op_StrInflatedCopy) && @@ -5199,7 +5199,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, } else if (!(op == Op_CmpP || op == Op_Conv2B || op == Op_CastP2X || op == Op_FastLock || use->is_memory_access_intrinsic() || - op == Op_SubTypeCheck || op == Op_InlineType || op == Op_FlatArrayCheck || + op == Op_SubTypeCheck || op == Op_ValueType || op == Op_FlatArrayCheck || op == Op_ReinterpretS2HF || op == Op_ReachabilityFence)) { n->dump(); @@ -5283,14 +5283,8 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, if (visited.test_set(n->_idx)) { continue; } - if (n->is_Phi()) { - if ((uint) _compile->get_alias_index(n->adr_type()) < new_index_start) { - // Push memory phis on the orig_phis worklist to update - // during Phase 4 if needed. - orig_phis.push(n); - } - } else if (n->is_ClearArray()) { - // we don't need to do anything, but the users must be pushed + if (n->is_Phi() || n->is_ClearArray()) { + // we don't need to do anything, but the users must be pushed } else if (n->is_MemBar()) { // MemBar nodes if (!n->is_Initialize()) { // memory projections for Initialize pushed below (so we get to all their uses) // we don't need to do anything, but the users must be pushed @@ -5315,7 +5309,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, n = n->find_out_with(Op_SCMemProj); assert(n != nullptr && n->Opcode() == Op_SCMemProj, "memory projection required"); } else if (n->is_CallLeaf() && n->as_CallLeaf()->_name != nullptr && - strcmp(n->as_CallLeaf()->_name, "store_unknown_inline") == 0) { + strcmp(n->as_CallLeaf()->_name, "store_unknown_value") == 0) { n = n->as_CallLeaf()->proj_out(TypeFunc::Memory); } else if (n->is_Proj()) { assert(n->in(0)->is_Initialize(), "we only push memory projections for Initialize"); @@ -5378,8 +5372,8 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, memnode_worklist.push(use); } } else if (use->is_CallLeaf() && use->as_CallLeaf()->_name != nullptr && - strcmp(use->as_CallLeaf()->_name, "store_unknown_inline") == 0) { - // store_unknown_inline overwrites destination array + strcmp(use->as_CallLeaf()->_name, "store_unknown_value") == 0) { + // store_unknown_value overwrites destination array memnode_worklist.push(use); } else { uint op = use->Opcode(); diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 0e8ef7d98ba7..5aca684ba841 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -24,10 +24,10 @@ #include "asm/register.hpp" #include "ci/ciFlatArrayKlass.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciMethod.hpp" #include "ci/ciObjArray.hpp" #include "ci/ciUtilities.hpp" +#include "ci/ciValueKlass.hpp" #include "classfile/javaClasses.hpp" #include "classfile/javaStackTraceClasses.hpp" #include "compiler/compileLog.hpp" @@ -42,7 +42,6 @@ #include "opto/convertnode.hpp" #include "opto/graphKit.hpp" #include "opto/idealKit.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/intrinsicnode.hpp" #include "opto/locknode.hpp" #include "opto/machnode.hpp" @@ -57,6 +56,7 @@ #include "opto/runtime.hpp" #include "opto/subtypenode.hpp" #include "opto/type.hpp" +#include "opto/valuetypenode.hpp" #include "runtime/arguments.hpp" #include "runtime/deoptimization.hpp" #include "runtime/sharedRuntime.hpp" @@ -1371,10 +1371,10 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, if (stopped()) return top(); NOT_PRODUCT(explicit_null_checks_inserted++); - if (value->is_InlineType()) { - // Null checking a scalarized but nullable inline type. Check the null marker + if (value->is_ValueType()) { + // Null checking a scalarized but nullable value type. Check the null marker // input instead of the oop input to avoid keeping buffer allocations alive. - null_check_common(value->as_InlineType()->get_null_marker(), T_INT, assert_null, null_control, speculative, true); + null_check_common(value->as_ValueType()->get_null_marker(), T_INT, assert_null, null_control, speculative, true); if (stopped()) { return top(); } @@ -1761,7 +1761,7 @@ Node* GraphKit::access_store_at(Node* obj, BasicType bt, DecoratorSet decorators, bool safe_for_replace, - const InlineTypeNode* vt) { + const ValueTypeNode* vt) { // Transformation of a value which could be null pointer (CastPP #null) // could be delayed during Parse (for example, in adjust_map_after_if()). // Execute transformation here to avoid barrier generation in such case. @@ -1774,12 +1774,12 @@ Node* GraphKit::access_store_at(Node* obj, } assert(val != nullptr, "not dead path"); - if (val->is_InlineType()) { - // Store to non-flat field. Buffer the inline type and make sure + if (val->is_ValueType()) { + // Store to non-flat field. Buffer the value type and make sure // the store is re-executed if the allocation triggers deoptimization. PreserveReexecuteState preexecs(this); jvms()->set_should_reexecute(true); - val = val->as_InlineType()->buffer(this, safe_for_replace); + val = val->as_ValueType()->buffer(this, safe_for_replace); } C2AccessValuePtr addr(adr, adr_type); @@ -1933,7 +1933,7 @@ Node* GraphKit::array_element_address(Node* ary, Node* idx, BasicType elembt, if (arytype->is_flat() && arytype->klass_is_exact()) { // We can only determine the flat array layout statically if the klass is exact. Otherwise, we could have different // value classes at runtime with a potentially different layout. The caller needs to fall back to call - // load/store_unknown_inline_Type() at runtime. We could return a sentinel node for the non-exact case but that + // load/store_unknown_value_Type() at runtime. We could return a sentinel node for the non-exact case but that // might mess with other GVN transformations in between. Thus, we just continue in the else branch normally, even // though we don't need the address node in this case and throw it away again. shift = arytype->flat_log_elem_size(); @@ -1957,7 +1957,7 @@ Node* GraphKit::array_element_address(Node* ary, Node* idx, BasicType elembt, return basic_plus_adr(ary, base, scale); } -Node* GraphKit::cast_to_flat_array(Node* array, ciInlineKlass* elem_vk) { +Node* GraphKit::cast_to_flat_array(Node* array, ciValueKlass* elem_vk) { assert(elem_vk->maybe_flat_in_array(), "no flat array for %s", elem_vk->name()->as_utf8()); if (!elem_vk->has_null_free_atomic_layout() && !elem_vk->has_nullable_atomic_layout()) { return cast_to_flat_array_exact(array, elem_vk, true, false); @@ -1979,7 +1979,7 @@ Node* GraphKit::cast_to_flat_array(Node* array, ciInlineKlass* elem_vk) { return _gvn.transform(new CheckCastPPNode(control(), array, arytype, ConstraintCastNode::DependencyType::NonFloatingNarrowing)); } -Node* GraphKit::cast_to_flat_array_exact(Node* array, ciInlineKlass* elem_vk, bool is_null_free, bool is_atomic) { +Node* GraphKit::cast_to_flat_array_exact(Node* array, ciValueKlass* elem_vk, bool is_null_free, bool is_atomic) { assert(is_null_free || is_atomic, "nullable arrays must be atomic"); ciArrayKlass* array_klass = ciObjArrayKlass::make(elem_vk, true, is_null_free, is_atomic); const TypeAryPtr* arytype = TypeOopPtr::make_from_klass(array_klass)->isa_aryptr(); @@ -2008,7 +2008,7 @@ Node* GraphKit::load_array_element(Node* ary, Node* idx, const TypeAryPtr* aryty void GraphKit::set_arguments_for_java_call(CallJavaNode* call) { PreserveReexecuteState preexecs(this); if (Arguments::is_valhalla_enabled()) { - // Make sure the call is "re-executed", if buffering of inline type arguments triggers deoptimization. + // Make sure the call is "re-executed", if buffering of value type arguments triggers deoptimization. // At this point, the call hasn't been executed yet, so we will only ever execute the call once. jvms()->set_should_reexecute(true); int arg_size = method()->get_declared_signature_at_bci(bci())->arg_size_for_bc(java_bc()); @@ -2022,12 +2022,12 @@ void GraphKit::set_arguments_for_java_call(CallJavaNode* call) { uint arg_idx = i - TypeFunc::Parms; Node* arg = argument(arg_idx); const Type* t = domain->field_at(i); - if (t->is_inlinetypeptr() && !call->method()->mismatch() && call->method()->is_scalarized_arg(arg_num)) { - // We don't pass inline type arguments by reference but instead pass each field of the inline type - if (!arg->is_InlineType()) { + if (t->is_valueklassptr() && !call->method()->mismatch() && call->method()->is_scalarized_arg(arg_num)) { + // We don't pass value type arguments by reference but instead pass each field of the value type + if (!arg->is_ValueType()) { // There are 2 cases in which the argument has not been scalarized if (_gvn.type(arg)->is_zero_type()) { - arg = InlineTypeNode::make_null(_gvn, t->inline_klass()); + arg = ValueTypeNode::make_null(_gvn, t->value_klass()); } else { // During parsing, a method is called with an abstract (or j.l.Object) receiver, the // receiver is a non-scalarized oop. CHA or IGVN might then prove that the receiver @@ -2035,12 +2035,12 @@ void GraphKit::set_arguments_for_java_call(CallJavaNode* call) { // a direct call with a scalarized receiver instead. assert(arg_idx == 0 && !call->method()->is_static(), "must be the receiver"); assert(call->is_optimized_virtual(), "must be during devirtualization of calls"); - arg = InlineTypeNode::make_from_oop(this, arg, t->inline_klass()); + arg = ValueTypeNode::make_from_oop(this, arg, t->value_klass()); } } - InlineTypeNode* vt = arg->as_InlineType(); + ValueTypeNode* vt = arg->as_ValueType(); vt->pass_fields(this, call, idx, true, !t->maybe_null(), true); - // If an inline type argument is passed as fields, attach the Method* to the call site + // If a value type argument is passed as fields, attach the Method* to the call site // to be able to access the extended signature later via attached_method_before_pc(). // For example, see CompiledMethod::preserve_callee_argument_oops(). call->set_override_symbolic_info(true); @@ -2049,9 +2049,9 @@ void GraphKit::set_arguments_for_java_call(CallJavaNode* call) { C->dependencies()->assert_mismatch_calling_convention(call->method()); arg_num++; continue; - } else if (arg->is_InlineType()) { - // Pass inline type argument via oop to callee - arg = arg->as_InlineType()->buffer(this, true); + } else if (arg->is_ValueType()) { + // Pass value type argument via oop to callee + arg = arg->as_ValueType()->buffer(this, true); } if (t != Type::HALF) { arg_num++; @@ -2111,12 +2111,12 @@ Node* GraphKit::set_results_for_java_call(CallJavaNode* call, bool separate_io_p Node* ret; if (call->method() == nullptr || call->method()->return_type()->basic_type() == T_VOID) { ret = top(); - } else if (call->tf()->returns_inline_type_as_fields()) { - // Return of multiple values (inline type fields): we create a - // InlineType node, each field is a projection from the call. - ciInlineKlass* vk = call->method()->return_type()->as_inline_klass(); + } else if (call->tf()->returns_value_type_as_fields()) { + // Return of multiple values (value type fields): we create a + // ValueType node, each field is a projection from the call. + ciValueKlass* vk = call->method()->return_type()->as_value_klass(); uint base_input = TypeFunc::Parms; - ret = InlineTypeNode::make_from_multi(this, call, vk, base_input, false, false); + ret = ValueTypeNode::make_from_multi(this, call, vk, base_input, false, false); // If we run out of registers to store the null marker, we need to reserve an extra // slot to store it on the stack. Unfortunately, we only know if stack slot is needed // when matching the call (see Matcher::return_values_mask), so we are conservative here. @@ -2124,7 +2124,7 @@ Node* GraphKit::set_results_for_java_call(CallJavaNode* call, bool separate_io_p } else { ret = _gvn.transform(new ProjNode(call, TypeFunc::Parms)); ciType* t = call->method()->return_type(); - if (!t->is_loaded() && InlineTypeReturnedAsFields) { + if (!t->is_loaded() && ValueTypeReturnedAsFields) { // The return type is unloaded but the callee might later be C2 compiled and then return // in scalarized form when the return type is loaded. Handle this similar to what we do in // PhaseMacroExpand::expand_mh_intrinsic_return by calling into the runtime to buffer. @@ -2134,7 +2134,7 @@ Node* GraphKit::set_results_for_java_call(CallJavaNode* call, bool separate_io_p ideal.declarations_done(); // Change return type of call to scalarized return const TypeFunc* tf = call->_tf; - const TypeTuple* domain = OptoRuntime::store_inline_type_fields_Type()->domain_cc(); + const TypeTuple* domain = OptoRuntime::store_value_type_fields_Type()->domain_cc(); const TypeFunc* new_tf = TypeFunc::make(tf->domain_sig(), tf->domain_cc(), tf->range_sig(), domain, true); call->_tf = new_tf; _gvn.set_type(call, call->Value(&_gvn)); @@ -2149,8 +2149,8 @@ Node* GraphKit::set_results_for_java_call(CallJavaNode* call, bool separate_io_p sync_kit(ideal); Node* store_to_buf_call = make_runtime_call(RC_NO_LEAF | RC_NO_IO, - OptoRuntime::store_inline_type_fields_Type(), - SharedRuntime::store_inline_type_fields_to_buf_entry(), + OptoRuntime::store_value_type_fields_Type(), + SharedRuntime::store_value_type_fields_to_buf_entry(), nullptr, TypePtr::BOTTOM, ret); // We don't know how many values are returned. This assumes the @@ -2181,12 +2181,12 @@ Node* GraphKit::set_results_for_java_call(CallJavaNode* call, bool separate_io_p } sync_kit(ideal); ret = _gvn.transform(ideal.value(res)); - } else if (!call->method()->return_value_is_larval() && _gvn.type(ret)->is_inlinetypeptr()) { + } else if (!call->method()->return_value_is_larval() && _gvn.type(ret)->is_valueklassptr()) { // In Parse::do_call we call make_from_oop on the final result of the call, but this could be the // result of merging several call paths. If one of them is made of an actual call node that - // returns an oop, we need to call make_from_oop here as well because we want InlineType - // nodes on every path to avoid merging an unallocated InlineType node path with an oop path. - ret = InlineTypeNode::make_from_oop(this, ret, _gvn.type(ret)->inline_klass()); + // returns an oop, we need to call make_from_oop here as well because we want ValueType + // nodes on every path to avoid merging an unallocated ValueType node path with an oop path. + ret = ValueTypeNode::make_from_oop(this, ret, _gvn.type(ret)->value_klass()); } } @@ -2316,14 +2316,14 @@ void GraphKit::replace_call(CallNode* call, Node* result, bool do_replaced_nodes // Replace the result with the new result if it exists and is used if (callprojs->resproj[0] != nullptr && result != nullptr) { - // If the inlined code is dead, the result projections for an inline type returned as + // If the inlined code is dead, the result projections for a value type returned as // fields have not been replaced. They will go away once the call is replaced by TOP below. - assert(callprojs->nb_resproj == 1 || (call->tf()->returns_inline_type_as_fields() && stopped()) || - (C->strength_reduction() && InlineTypeReturnedAsFields && !call->as_CallJava()->method()->return_type()->is_loaded()), + assert(callprojs->nb_resproj == 1 || (call->tf()->returns_value_type_as_fields() && stopped()) || + (C->strength_reduction() && ValueTypeReturnedAsFields && !call->as_CallJava()->method()->return_type()->is_loaded()), "unexpected number of results"); // If we are doing strength reduction and the return type is not loaded we - // need to rewire all projections since store_inline_type_fields_to_buf is already present - if (C->strength_reduction() && InlineTypeReturnedAsFields && !call->as_CallJava()->method()->return_type()->is_loaded()) { + // need to rewire all projections since store_value_type_fields_to_buf is already present + if (C->strength_reduction() && ValueTypeReturnedAsFields && !call->as_CallJava()->method()->return_type()->is_loaded()) { CallNode* new_call = result->in(0)->as_Call(); assert(new_call->proj_out_or_null(TypeFunc::Parms) == result, "the first data projection should be result"); for (uint i = 0; i < callprojs->nb_resproj; i++) { @@ -3269,8 +3269,8 @@ Node* Phase::gen_subtype_check(Node* subklass, Node* superklass, Node** ctrl, No Node* GraphKit::gen_subtype_check(Node* obj_or_subklass, Node* superklass) { const Type* sub_t = _gvn.type(obj_or_subklass); - if (sub_t->make_oopptr() != nullptr && sub_t->make_oopptr()->is_inlinetypeptr()) { - sub_t = TypeKlassPtr::make(sub_t->inline_klass()); + if (sub_t->make_oopptr() != nullptr && sub_t->make_oopptr()->is_valueklassptr()) { + sub_t = TypeKlassPtr::make(sub_t->value_klass()); obj_or_subklass = makecon(sub_t); } bool expand_subtype_check = C->post_loop_opts_phase(); // macro node expansion is over @@ -3300,8 +3300,8 @@ Node* GraphKit::type_check_receiver(Node* receiver, ciKlass* klass, assert(!klass->is_interface(), "no exact type check on interfaces"); Node* fail = top(); const Type* rec_t = _gvn.type(receiver); - if (rec_t->is_inlinetypeptr()) { - if (klass->equals(rec_t->inline_klass())) { + if (rec_t->is_valueklassptr()) { + if (klass->equals(rec_t->value_klass())) { (*casted_receiver) = receiver; // Always passes } else { (*casted_receiver) = top(); // Always fails @@ -3328,9 +3328,9 @@ Node* GraphKit::type_check_receiver(Node* receiver, ciKlass* klass, // recv_xtype, since now we know what the type will be. Node* cast = new CheckCastPPNode(control(), receiver, recv_xtype); Node* res = _gvn.transform(cast); - if (recv_xtype->is_inlinetypeptr()) { + if (recv_xtype->is_valueklassptr()) { assert(!gvn().type(res)->maybe_null(), "receiver should never be null"); - res = InlineTypeNode::make_from_oop(this, res, recv_xtype->inline_klass()); + res = ValueTypeNode::make_from_oop(this, res, recv_xtype->value_klass()); } (*casted_receiver) = res; assert(!(*casted_receiver)->is_top(), "that path should be unreachable"); @@ -3366,8 +3366,8 @@ Node* GraphKit::subtype_check_receiver(Node* receiver, ciKlass* klass, const TypeOopPtr* recv_type = tklass->as_subtype_instance_type(); if (receiver_type != nullptr && !receiver_type->higher_equal(recv_type)) { // ignore redundant casts Node* cast = _gvn.transform(new CheckCastPPNode(control(), receiver, recv_type)); - if (recv_type->is_inlinetypeptr()) { - cast = InlineTypeNode::make_from_oop(this, cast, recv_type->inline_klass()); + if (recv_type->is_valueklassptr()) { + cast = ValueTypeNode::make_from_oop(this, cast, recv_type->value_klass()); } (*casted_receiver) = cast; } @@ -3695,7 +3695,7 @@ Node* GraphKit::gen_checkcast(Node* obj, Node* superklass, Node** failure_contro const TypeKlassPtr* improved_klass_ptr_type = klass_ptr_type->try_improve(); const TypeOopPtr* toop = improved_klass_ptr_type->as_subtype_instance_type(); bool safe_for_replace = (failure_control == nullptr); - assert(!null_free || toop->can_be_inline_type(), "must be an inline type pointer"); + assert(!null_free || toop->can_be_value_type(), "must be a value type pointer"); // Fast cutout: Check the case that the cast is vacuously true. // This detects the common cases where the test will short-circuit @@ -3707,8 +3707,8 @@ Node* GraphKit::gen_checkcast(Node* obj, Node* superklass, Node** failure_contro const TypeKlassPtr* kptr = nullptr; if (obj_type->isa_oop_ptr()) { kptr = obj_type->is_oopptr()->as_klass_type(); - } else if (obj->is_InlineType()) { - ciInlineKlass* vk = obj_type->inline_klass(); + } else if (obj->is_ValueType()) { + ciValueKlass* vk = obj_type->value_klass(); kptr = TypeInstKlassPtr::make(TypePtr::NotNull, vk, Type::Offset(0)); } @@ -3783,8 +3783,8 @@ Node* GraphKit::gen_checkcast(Node* obj, Node* superklass, Node** failure_contro // If not_null_obj is dead, only null-path is taken if (stopped()) { // Doing instance-of on a null? set_control(null_ctl); - if (toop->is_inlinetypeptr()) { - return InlineTypeNode::make_null(_gvn, toop->inline_klass()); + if (toop->is_valueklassptr()) { + return ValueTypeNode::make_null(_gvn, toop->value_klass()); } return null(); } @@ -3853,9 +3853,9 @@ Node* GraphKit::gen_checkcast(Node* obj, Node* superklass, Node** failure_contro set_control( _gvn.transform(region) ); record_for_igvn(region); - bool not_inline = !toop->can_be_inline_type(); - bool not_flat_in_array = !UseArrayFlattening || not_inline || (toop->is_inlinetypeptr() && !toop->inline_klass()->maybe_flat_in_array()); - if (Arguments::is_valhalla_enabled() && (not_inline || not_flat_in_array)) { + bool not_value = !toop->can_be_value_type(); + bool not_flat_in_array = !UseArrayFlattening || not_value || (toop->is_valueklassptr() && !toop->value_klass()->maybe_flat_in_array()); + if (Arguments::is_valhalla_enabled() && (not_value || not_flat_in_array)) { // Check if obj has been loaded from an array. Keep obj unchanged for final // map replacement below. Node* array_obj = obj->isa_DecodeN() ? obj->in(1) : obj; @@ -3878,8 +3878,8 @@ Node* GraphKit::gen_checkcast(Node* obj, Node* superklass, Node** failure_contro if (array != nullptr) { const TypeAryPtr* ary_t = _gvn.type(array)->isa_aryptr(); if (ary_t != nullptr) { - if (!ary_t->is_not_null_free() && !ary_t->is_null_free() && not_inline) { - // Casting array element to a non-inline-type, mark array as not null-free. + if (!ary_t->is_not_null_free() && !ary_t->is_null_free() && not_value) { + // Casting array element to a non-value-type, mark array as not null-free. Node* cast = _gvn.transform(new CheckCastPPNode(control(), array, ary_t->cast_to_not_null_free())); if (new_cast_failure_map != nullptr) { // We want to propagate the improved cast node in the current map. Clone it such that we can still properly @@ -3905,10 +3905,10 @@ Node* GraphKit::gen_checkcast(Node* obj, Node* superklass, Node** failure_contro // A merge of null or Casted-NotNull obj Node* res = _gvn.transform(phi); - if (!stopped() && !res->is_InlineType()) { + if (!stopped() && !res->is_ValueType()) { res = record_profiled_receiver_for_speculation(res); - if (toop->is_inlinetypeptr() && !maybe_larval) { - Node* vt = InlineTypeNode::make_from_oop(this, res, toop->inline_klass()); + if (toop->is_valueklassptr() && !maybe_larval) { + Node* vt = ValueTypeNode::make_from_oop(this, res, toop->value_klass()); res = vt; if (safe_for_replace) { replace_in_map(obj, vt); @@ -3935,8 +3935,8 @@ Node* GraphKit::mark_word_test(Node* obj, uintptr_t mask_val, bool eq) { return _gvn.transform(new BoolNode(cmp, eq ? BoolTest::eq : BoolTest::ne)); } -Node* GraphKit::inline_type_test(Node* obj, bool is_inline) { - return mark_word_test(obj, markWord::inline_type_pattern, is_inline); +Node* GraphKit::value_type_test(Node* obj, bool is_value) { + return mark_word_test(obj, markWord::value_type_pattern, is_value); } Node* GraphKit::flat_array_test(Node* array_or_klass, bool flat) { @@ -3961,7 +3961,7 @@ Node* GraphKit::null_free_array_test(Node* array, bool null_free) { return mark_word_test(array, markWord::null_free_array_bit_in_place, null_free); } -Node* GraphKit::null_free_atomic_array_test(Node* array, ciInlineKlass* vk) { +Node* GraphKit::null_free_atomic_array_test(Node* array, ciValueKlass* vk) { assert(vk->has_null_free_atomic_layout() || vk->has_null_free_non_atomic_layout(), "Can't be null-free and flat"); if (!vk->has_null_free_non_atomic_layout()) { @@ -4008,10 +4008,10 @@ Node* GraphKit::atomic_layout_array_test_and_get_layout_kind(Node* array, Region return layout_kind; } -// Deoptimize if 'ary' is a null-free inline type array and 'val' is null +// Deoptimize if 'ary' is a null-free value type array and 'val' is null // Return `ary` as nullable if `val` is statically known to be null. Beware // it will also replace_in_map `ary` with the casted version. -Node* GraphKit::inline_array_null_guard(Node* ary, Node* val, int nargs) { +Node* GraphKit::value_array_null_guard(Node* ary, Node* val, int nargs) { RegionNode* region = new RegionNode(3); Node* null_ctl = top(); null_check_oop(val, &null_ctl); @@ -4181,7 +4181,7 @@ void GraphKit::shared_unlock(Node* box, Node* obj) { map()->pop_monitor(); // Kill monitor from debug info return; } - assert(!obj->is_InlineType(), "should not unlock on inline type"); + assert(!obj->is_ValueType(), "should not unlock on value type"); // Memory barrier to avoid floating things down past the locked region insert_mem_bar(Op_MemBarReleaseLock); @@ -4365,7 +4365,7 @@ Node* GraphKit::new_instance(Node* klass_node, Node* extra_slow_test, Node* *return_size_val, bool deoptimize_on_exception, - InlineTypeNode* inline_type_node) { + ValueTypeNode* value_type_node) { // Compute size in doublewords // The size is always an integral number of doublewords, represented // as a positive bytewise size stored in the klass's layout_helper. @@ -4423,7 +4423,7 @@ Node* GraphKit::new_instance(Node* klass_node, AllocateNode* alloc = new AllocateNode(C, AllocateNode::alloc_type(Type::TOP), control(), mem, i_o(), size, klass_node, - initial_slow_test, inline_type_node); + initial_slow_test, value_type_node); // This is a precise notnull oop of the klass. // (Actually, it need not be precise if this is a reflective allocation.) @@ -4985,10 +4985,10 @@ Node* GraphKit::make_constant_from_field(ciField* field, Node* obj) { /*is_unsigned_load=*/false); if (con_type != nullptr) { Node* con = makecon(con_type); - if (field->type()->is_inlinetype()) { - con = InlineTypeNode::make_from_oop(this, con, field->type()->as_inline_klass()); - } else if (con_type->is_inlinetypeptr()) { - con = InlineTypeNode::make_from_oop(this, con, con_type->inline_klass()); + if (field->type()->is_value_klass()) { + con = ValueTypeNode::make_from_oop(this, con, field->type()->as_value_klass()); + } else if (con_type->is_valueklassptr()) { + con = ValueTypeNode::make_from_oop(this, con, con_type->value_klass()); } return con; } @@ -5003,8 +5003,8 @@ Node* GraphKit::maybe_narrow_object_type(Node* obj, ciKlass* type, bool maybe_la Node* casted_obj = gvn().transform(new CheckCastPPNode(control(), obj, narrow_obj_type)); obj = casted_obj; } - if (!maybe_larval && sig_type->is_inlinetypeptr()) { - obj = InlineTypeNode::make_from_oop(this, obj, sig_type->inline_klass()); + if (!maybe_larval && sig_type->is_valueklassptr()) { + obj = ValueTypeNode::make_from_oop(this, obj, sig_type->value_klass()); } return obj; } diff --git a/src/hotspot/share/opto/graphKit.hpp b/src/hotspot/share/opto/graphKit.hpp index 3fbef71c8952..7246364bd2cf 100644 --- a/src/hotspot/share/opto/graphKit.hpp +++ b/src/hotspot/share/opto/graphKit.hpp @@ -33,11 +33,11 @@ #include "opto/cfgnode.hpp" #include "opto/compile.hpp" #include "opto/divnode.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/mulnode.hpp" #include "opto/phaseX.hpp" #include "opto/subnode.hpp" #include "opto/type.hpp" +#include "opto/valuetypenode.hpp" #include "runtime/deoptimization.hpp" class BarrierSetC2; @@ -603,7 +603,7 @@ class GraphKit : public Phase { BasicType bt, DecoratorSet decorators, bool safe_for_replace = true, - const InlineTypeNode* vt = nullptr); + const ValueTypeNode* vt = nullptr); Node* access_load_at(Node* obj, // containing obj Node* adr, // actual address to load val at @@ -664,8 +664,8 @@ class GraphKit : public Phase { const TypeInt* sizetype = nullptr, // Optional control dependency (for example, on range check) Node* ctrl = nullptr); - Node* cast_to_flat_array(Node* array, ciInlineKlass* elem_vk); - Node* cast_to_flat_array_exact(Node* array, ciInlineKlass* elem_vk, bool is_null_free, bool is_atomic); + Node* cast_to_flat_array(Node* array, ciValueKlass* elem_vk); + Node* cast_to_flat_array_exact(Node* array, ciValueKlass* elem_vk, bool is_null_free, bool is_atomic); // Return a load of array element at idx. Node* load_array_element(Node* ary, Node* idx, const TypeAryPtr* arytype, bool set_ctrl); @@ -843,14 +843,14 @@ class GraphKit : public Phase { SafePointNode** new_cast_failure_map = nullptr, bool null_free = false, bool maybe_larval = false); - // Inline types + // Value types Node* mark_word_test(Node* obj, uintptr_t mask_val, bool eq); - Node* inline_type_test(Node* obj, bool is_inline = true); + Node* value_type_test(Node* obj, bool is_value = true); Node* flat_array_test(Node* array_or_klass, bool flat = true); Node* null_free_array_test(Node* array, bool null_free = true); - Node* null_free_atomic_array_test(Node* array, ciInlineKlass* vk); + Node* null_free_atomic_array_test(Node* array, ciValueKlass* vk); Node* atomic_layout_array_test_and_get_layout_kind(Node* array, RegionNode* atomic_region); - Node* inline_array_null_guard(Node* ary, Node* val, int nargs); + Node* value_array_null_guard(Node* ary, Node* val, int nargs); Node* gen_subtype_check(Node* obj, Node* superklass); @@ -874,7 +874,7 @@ class GraphKit : public Phase { Node* slow_test = nullptr, Node* *return_size_val = nullptr, bool deoptimize_on_exception = false, - InlineTypeNode* inline_type_node = nullptr); + ValueTypeNode* value_type_node = nullptr); Node* new_array(Node* klass_node, Node* count_val, int nargs, Node* *return_size_val = nullptr, bool deoptimize_on_exception = false, diff --git a/src/hotspot/share/opto/int128tnode.cpp b/src/hotspot/share/opto/int128tnode.cpp new file mode 100644 index 000000000000..8263e56aa52a --- /dev/null +++ b/src/hotspot/share/opto/int128tnode.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "opto/int128tnode.hpp" +#include "opto/machnode.hpp" +#include "opto/matcher.hpp" +#include "opto/node.hpp" +#include "opto/type.hpp" + +Int128TBinaryNode::Int128TBinaryNode(Node* lo1, Node* hi1, Node* lo2, Node* hi2) : MultiNode(5) { + init_flags(Flag_is_macro); + init_req(1, lo1); + init_req(2, hi1); + init_req(3, lo2); + init_req(4, hi2); + Compile* C = Compile::current(); + assert(C->allow_macro_nodes(), "must before macro expansion"); + C->add_macro_node(this); +} + +Node* Int128TBinaryNode::match(const ProjNode* proj, const Matcher* matcher) { + return new MachProjNode(this, proj->_con, *matcher->idealreg2regmask[Op_RegL], Op_RegL); +} diff --git a/src/hotspot/share/opto/int128tnode.hpp b/src/hotspot/share/opto/int128tnode.hpp new file mode 100644 index 000000000000..35b818547e37 --- /dev/null +++ b/src/hotspot/share/opto/int128tnode.hpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_OPTO_INT128TNODE_HPP +#define SHARE_OPTO_INT128TNODE_HPP + +#include "opto/multnode.hpp" + +class Matcher; +class ProjNode; +class Type; + +// An operation producing an int128 consisting of 2 longs, a lo and a hi Projs +class Int128TBinaryNode : public MultiNode { +public: + Int128TBinaryNode(Node* lo1, Node* hi1, Node* lo2, Node* hi2); + + Node* result_lo_or_null() const { return proj_out_or_null(lo_proj_num); } + Node* result_hi_or_null() const { return proj_out_or_null(hi_proj_num); } + Node* lo1() const { return in(1); } + Node* hi1() const { return in(2); } + Node* lo2() const { return in(3); } + Node* hi2() const { return in(4); } + + const Type* bottom_type() const final { return TypeTuple::LONG_PAIR; } + bool is_CFG() const final { return false; } + uint ideal_reg() const final { return NotAMachineReg; } + + Node* match(const ProjNode* proj, const Matcher* m) final; + + static constexpr uint lo_proj_num = 0; + static constexpr uint hi_proj_num = 1; +}; + +class AddI128TNode final : public Int128TBinaryNode { +public: + AddI128TNode(Node* lo1, Node* hi1, Node* lo2, Node* hi2) : Int128TBinaryNode(lo1, hi1, lo2, hi2) {} + + int Opcode() const final; +}; + +class SubI128TNode final : public Int128TBinaryNode { +public: + SubI128TNode(Node* lo1, Node* hi1, Node* lo2, Node* hi2) : Int128TBinaryNode(lo1, hi1, lo2, hi2) {} + + int Opcode() const final; +}; + +#endif // SHARE_OPTO_INT128TNODE_HPP diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 7dc78e959b57..eb22718ed175 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -48,10 +48,11 @@ #include "opto/countbitsnode.hpp" #include "opto/graphKit.hpp" #include "opto/idealKit.hpp" -#include "opto/inlinetypenode.hpp" +#include "opto/int128tnode.hpp" #include "opto/library_call.hpp" #include "opto/mathexactnode.hpp" #include "opto/mulnode.hpp" +#include "opto/multnode.hpp" #include "opto/narrowptrnode.hpp" #include "opto/opaquenode.hpp" #include "opto/opcodes.hpp" @@ -60,6 +61,7 @@ #include "opto/runtime.hpp" #include "opto/subnode.hpp" #include "opto/type.hpp" +#include "opto/valuetypenode.hpp" #include "opto/vectornode.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiThreadState.hpp" @@ -754,6 +756,12 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_maxD_strict: return inline_min_max(intrinsic_id()); + case vmIntrinsics::_addInt128TLo: + case vmIntrinsics::_addInt128THi: + case vmIntrinsics::_subInt128TLo: + case vmIntrinsics::_subInt128THi: + return inline_int128t_addsub(intrinsic_id()); + case vmIntrinsics::_VectorUnaryOp: return inline_vector_nary_operation(1); case vmIntrinsics::_VectorBinaryOp: @@ -2108,6 +2116,29 @@ bool LibraryCallKit::inline_math_unsignedMultiplyHigh() { return true; } +bool LibraryCallKit::inline_int128t_addsub(vmIntrinsicID id) { + Node* lo1 = argument(0); + Node* hi1 = argument(2); + Node* lo2 = argument(4); + Node* hi2 = argument(6); + Node* multi; + if (id == vmIntrinsics::_addInt128TLo || id == vmIntrinsics::_addInt128THi) { + multi = _gvn.transform(new AddI128TNode(lo1, hi1, lo2, hi2)); + } else { + assert(id == vmIntrinsics::_subInt128TLo || id == vmIntrinsics::_subInt128THi, "unexpected input %s", vmIntrinsics::name_at(id)); + multi = _gvn.transform(new SubI128TNode(lo1, hi1, lo2, hi2)); + } + + Node* result; + if (id == vmIntrinsics::_addInt128TLo || id == vmIntrinsics::_subInt128TLo) { + result = _gvn.transform(new ProjNode(multi, Int128TBinaryNode::lo_proj_num)); + } else { + result = _gvn.transform(new ProjNode(multi, Int128TBinaryNode::hi_proj_num)); + } + set_result(result); + return true; +} + inline int LibraryCallKit::classify_unsafe_addr(Node* &base, Node* &offset, BasicType type) { const TypePtr* base_type = TypePtr::NULL_PTR; @@ -2432,12 +2463,12 @@ bool LibraryCallKit::inline_unsafe_access(bool is_store, const BasicType type, c assert(Unsafe_field_offset_to_byte_offset(11) == 11, "fieldOffset must be byte-scaled"); - if (base->is_InlineType()) { - assert(!is_store, "InlineTypeNodes are non-larval value objects"); - InlineTypeNode* vt = base->as_InlineType(); + if (base->is_ValueType()) { + assert(!is_store, "ValueTypeNodes are non-larval value objects"); + ValueTypeNode* vt = base->as_ValueType(); if (offset->is_Con()) { long off = find_long_con(offset, 0); - ciInlineKlass* vk = vt->type()->inline_klass(); + ciValueKlass* vk = vt->type()->value_klass(); if ((long)(int)off != off || !vk->contains_field_offset(off)) { return false; } @@ -2451,8 +2482,8 @@ bool LibraryCallKit::inline_unsafe_access(bool is_store, const BasicType type, c if (bt == type && !field->is_flat()) { Node* value = vt->field_value_by_offset(off, false); const Type* value_type = _gvn.type(value); - if (value_type->is_inlinetypeptr()) { - value = InlineTypeNode::make_from_oop(this, value, value_type->inline_klass()); + if (value_type->is_valueklassptr()) { + value = ValueTypeNode::make_from_oop(this, value, value_type->value_klass()); } set_result(value); return true; @@ -2613,9 +2644,9 @@ bool LibraryCallKit::inline_unsafe_access(bool is_store, const BasicType type, c if (p == nullptr) { // Could not constant fold the load p = access_load_at(heap_base_oop, adr, adr_type, value_type, type, decorators); const TypeOopPtr* ptr = value_type->make_oopptr(); - if (ptr != nullptr && ptr->is_inlinetypeptr()) { - // Load a non-flattened inline type from memory - p = InlineTypeNode::make_from_oop(this, p, ptr->inline_klass()); + if (ptr != nullptr && ptr->is_valueklassptr()) { + // Load a non-flattened value type from memory + p = ValueTypeNode::make_from_oop(this, p, ptr->value_klass()); } } if (type == T_ADDRESS) { @@ -2676,12 +2707,12 @@ bool LibraryCallKit::inline_unsafe_flat_access(bool is_store, AccessKind kind) { return false; } ciType* mirror_type = value_klass_node->const_oop()->as_instance()->java_mirror_type(); - if (mirror_type == nullptr || !mirror_type->is_inlinetype()) { + if (mirror_type == nullptr || !mirror_type->is_value_klass()) { // While mirror_type should not be null, there is no simple argument of that, so let's be safe, and bailout if it happens. - // Otherwise, if mirror_type is not null, but not an inline type, that is dead code. Bailout as well. + // Otherwise, if mirror_type is not null, but not a value type, that is dead code. Bailout as well. return false; } - ciInlineKlass* value_klass = mirror_type->as_inline_klass(); + ciValueKlass* value_klass = mirror_type->as_value_klass(); const TypeInt* layout_type = _gvn.type(argument(4))->isa_int(); if (layout_type == nullptr || !layout_type->is_con()) { @@ -2724,17 +2755,17 @@ bool LibraryCallKit::inline_unsafe_flat_access(bool is_store, AccessKind kind) { offset_con, base_klass->name()->as_utf8(), field->type()->name(), value_klass->name()->as_utf8()); immutable_memory = field->is_strict() && field->is_final(); - if (base->is_InlineType()) { + if (base->is_ValueType()) { assert(!is_store, "Cannot store into a non-larval value object"); - set_result(base->as_InlineType()->field_value_by_offset(offset_con, false)); + set_result(base->as_ValueType()->field_value_by_offset(offset_con, false)); return true; } } } - if (base->is_InlineType()) { + if (base->is_ValueType()) { assert(!is_store, "Cannot store into a non-larval value object"); - base = base->as_InlineType()->buffer(this, true); + base = base->as_ValueType()->buffer(this, true); } ptr = basic_plus_adr(base, ConvL2X(offset)); } else if (base_type->isa_aryptr()) { @@ -2776,16 +2807,16 @@ bool LibraryCallKit::inline_unsafe_flat_access(bool is_store, AccessKind kind) { if (is_store) { Node* value = argument(6); const Type* value_type = _gvn.type(value); - if (!value_type->is_inlinetypeptr()) { + if (!value_type->is_valueklassptr()) { value_type = Type::get_const_type(value_klass)->filter_speculative(value_type); Node* new_value = _gvn.transform(new CheckCastPPNode(control(), value, value_type, ConstraintCastNode::DependencyType::NonFloatingNarrowing)); - new_value = InlineTypeNode::make_from_oop(this, new_value, value_klass); + new_value = ValueTypeNode::make_from_oop(this, new_value, value_klass); replace_in_map(value, new_value); value = new_value; } - assert(value_type == TypePtr::NULL_PTR || value_type->inline_klass() == value_klass, - "value is of type %s while value klass is %s", value_type->inline_klass()->name()->as_utf8(), value_klass->name()->as_utf8()); + assert(value_type == TypePtr::NULL_PTR || value_type->value_klass() == value_klass, + "value is of type %s while value klass is %s", value_type->value_klass()->name()->as_utf8(), value_klass->name()->as_utf8()); if (layout == LayoutKind::REFERENCE) { const TypePtr* ptr_type = (decorators & C2_MISMATCHED) != 0 ? TypeRawPtr::BOTTOM : _gvn.type(ptr)->is_ptr(); access_store_at(base, ptr, ptr_type, value, value_type, T_OBJECT, decorators); @@ -2795,21 +2826,21 @@ bool LibraryCallKit::inline_unsafe_flat_access(bool is_store, AccessKind kind) { if (null_free) { null_check(value); } - value->as_InlineType()->store_flat(this, base, ptr, atomic, immutable_memory, null_free, decorators); + value->as_ValueType()->store_flat(this, base, ptr, atomic, immutable_memory, null_free, decorators); } return true; } else { decorators |= (C2_CONTROL_DEPENDENT_LOAD | C2_UNKNOWN_CONTROL_LOAD); - InlineTypeNode* result; + ValueTypeNode* result; if (layout == LayoutKind::REFERENCE) { const TypePtr* ptr_type = (decorators & C2_MISMATCHED) != 0 ? TypeRawPtr::BOTTOM : _gvn.type(ptr)->is_ptr(); Node* oop = access_load_at(base, ptr, ptr_type, Type::get_const_type(value_klass), T_OBJECT, decorators); - result = InlineTypeNode::make_from_oop(this, oop, value_klass); + result = ValueTypeNode::make_from_oop(this, oop, value_klass); } else { bool atomic = LayoutKindHelper::is_atomic_flat(layout); bool null_free = !LayoutKindHelper::is_nullable_flat(layout); - result = InlineTypeNode::make_from_flat(this, value_klass, base, ptr, atomic, immutable_memory, null_free, decorators); + result = ValueTypeNode::make_from_flat(this, value_klass, base, ptr, atomic, immutable_memory, null_free, decorators); } set_result(result); @@ -3026,17 +3057,17 @@ bool LibraryCallKit::inline_unsafe_load_store(const BasicType type, const LoadSt if (is_reference_type(type)) { decorators |= IN_HEAP | ON_UNKNOWN_OOP_REF; - if (oldval != nullptr && oldval->is_InlineType()) { + if (oldval != nullptr && oldval->is_ValueType()) { // Re-execute the unsafe access if allocation triggers deoptimization. PreserveReexecuteState preexecs(this); jvms()->set_should_reexecute(true); - oldval = oldval->as_InlineType()->buffer(this)->get_oop(); + oldval = oldval->as_ValueType()->buffer(this)->get_oop(); } - if (newval != nullptr && newval->is_InlineType()) { + if (newval != nullptr && newval->is_ValueType()) { // Re-execute the unsafe access if allocation triggers deoptimization. PreserveReexecuteState preexecs(this); jvms()->set_should_reexecute(true); - newval = newval->as_InlineType()->buffer(this)->get_oop(); + newval = newval->as_ValueType()->buffer(this)->get_oop(); } // Transformation of a value which could be null pointer (CastPP #null) @@ -4668,7 +4699,7 @@ bool LibraryCallKit::inline_Class_cast() { set_map(new_cast_failure_map); } set_control(_gvn.transform(region)); - // Set IO and memory because gen_checkcast may override them when buffering inline types + // Set IO and memory because gen_checkcast may override them when buffering value types set_i_o(io); set_all_memory(mem); uncommon_trap(Deoptimization::Reason_intrinsic, @@ -4880,7 +4911,7 @@ bool LibraryCallKit::inline_newArray(bool null_free, bool atomic) { ciInstanceKlass* ik = tp->instance_klass(); if (ik == C->env()->Class_klass()) { ciType* t = tp->java_mirror_type(); - if (t != nullptr && t->is_inlinetype()) { + if (t != nullptr && t->is_value_klass()) { ciArrayKlass* array_klass = ciArrayKlass::make(t, null_free, atomic, true); assert(array_klass->is_elem_null_free() == null_free, "inconsistency"); @@ -4890,15 +4921,15 @@ bool LibraryCallKit::inline_newArray(bool null_free, bool atomic) { return false; } - if (array_klass->is_loaded() && array_klass->element_klass()->as_inline_klass()->is_initialized()) { + if (array_klass->is_loaded() && array_klass->element_klass()->as_value_klass()->is_initialized()) { const TypeAryKlassPtr* array_klass_type = TypeAryKlassPtr::make(array_klass, Type::trust_interfaces); if (null_free) { - if (init_val->is_InlineType()) { - if (array_klass_type->is_flat() && init_val->as_InlineType()->is_all_zero(&gvn(), /* flat */ true)) { + if (init_val->is_ValueType()) { + if (array_klass_type->is_flat() && init_val->as_ValueType()->is_all_zero(&gvn(), /* flat */ true)) { // Zeroing is enough because the init value is the all-zero value init_val = nullptr; } else { - init_val = init_val->as_InlineType()->buffer(this); + init_val = init_val->as_ValueType()->buffer(this); } } if (init_val != nullptr) { @@ -4980,14 +5011,14 @@ bool LibraryCallKit::inline_getArrayProperties(ArrayPropertiesCheck check) { atomic_region->add_req(is_naturally_atomic_ctl); non_atomic_region->add_req(is_not_naturally_atomic_ctl); - Node* is_empty_inline_type_flag = _gvn.transform(new AndINode(array_element_klass_flags, intcon(InstanceKlassFlags::_misc_is_empty_inline_type))); - Node* is_empty_inline_type_cmp = _gvn.transform(new CmpINode(is_empty_inline_type_flag, intcon(0))); - Node* is_empty_inline_type_bol = _gvn.transform(new BoolNode(is_empty_inline_type_cmp, BoolTest::ne)); - IfNode* iff_is_empty_inline_type = create_and_xform_if(is_nullable_ctl, is_empty_inline_type_bol, PROB_FAIR, COUNT_UNKNOWN); - Node* is_empty_inline_type_ctl = _gvn.transform(new IfTrueNode(iff_is_empty_inline_type)); - Node* is_nonempty_inline_type_ctl = _gvn.transform(new IfFalseNode(iff_is_empty_inline_type)); - atomic_region->add_req(is_empty_inline_type_ctl); - non_atomic_region->add_req(is_nonempty_inline_type_ctl); + Node* is_empty_value_type_flag = _gvn.transform(new AndINode(array_element_klass_flags, intcon(InstanceKlassFlags::_misc_is_empty_value_type))); + Node* is_empty_value_type_cmp = _gvn.transform(new CmpINode(is_empty_value_type_flag, intcon(0))); + Node* is_empty_value_type_bol = _gvn.transform(new BoolNode(is_empty_value_type_cmp, BoolTest::ne)); + IfNode* iff_is_empty_value_type = create_and_xform_if(is_nullable_ctl, is_empty_value_type_bol, PROB_FAIR, COUNT_UNKNOWN); + Node* is_empty_value_type_ctl = _gvn.transform(new IfTrueNode(iff_is_empty_value_type)); + Node* is_nonempty_value_type_ctl = _gvn.transform(new IfFalseNode(iff_is_empty_value_type)); + atomic_region->add_req(is_empty_value_type_ctl); + non_atomic_region->add_req(is_nonempty_value_type_ctl); // ...non-atomic, but we tried everything. RegionNode* decision = new RegionNode(3); @@ -5261,7 +5292,7 @@ bool LibraryCallKit::inline_array_copyOf(bool is_copyOfRange) { generate_negative_guard(length, bailout, &length); if (Arguments::is_valhalla_enabled()) { - // Handle inline type arrays + // Handle value type arrays // TODO 8251971 This is too strong generate_fair_guard(flat_array_test(original), bailout); generate_fair_guard(flat_array_test(refined_klass_node), bailout); @@ -5380,9 +5411,9 @@ bool LibraryCallKit::should_bail_out_on_non_ref_arrays(const TypeAryPtr* src_typ const bool dest_maybe_flat = !dest_ary_klass_type->is_not_flat(); // We could have abstract flat value class arrays whose layout we don't know. Bail out. - const bool can_src_be_abstract_flat_value_class_array = src_maybe_flat && !src_type->elem()->is_inlinetypeptr(); + const bool can_src_be_abstract_flat_value_class_array = src_maybe_flat && !src_type->elem()->is_valueklassptr(); const bool can_dest_be_abstract_flat_value_class_array = dest_maybe_flat && - !dest_ary_klass_type->elem()->is_instklassptr()->instance_klass()->is_inlinetype(); + !dest_ary_klass_type->elem()->is_instklassptr()->instance_klass()->is_value_klass(); if (can_src_be_abstract_flat_value_class_array || can_dest_be_abstract_flat_value_class_array) { return true; } @@ -5396,8 +5427,8 @@ bool LibraryCallKit::should_bail_out_on_non_ref_arrays(const TypeAryPtr* src_typ return false; } - const bool can_src_be_flat_with_oops = src_maybe_flat && src_type->elem()->inline_klass()->contains_oops(); - const bool can_dest_be_flat_with_oops = dest_maybe_flat && dest_ary_klass_type->elem()->is_instklassptr()->instance_klass()->as_inline_klass()->contains_oops(); + const bool can_src_be_flat_with_oops = src_maybe_flat && src_type->elem()->value_klass()->contains_oops(); + const bool can_dest_be_flat_with_oops = dest_maybe_flat && dest_ary_klass_type->elem()->is_instklassptr()->instance_klass()->as_value_klass()->contains_oops(); if (can_src_be_flat_with_oops || can_dest_be_flat_with_oops) { return true; } @@ -5545,7 +5576,7 @@ Node* LibraryCallKit::get_hashcode_from_header(Node* header, RegionNode* unset_r * if klass header is not safe to read { goto slow } * k_hash = read_hash_from_klass_header() * if k_hash is empty { goto slow } - * return fast_hashcode_path (see InlineKlass::Members::_fast_hashcode_offset et seqq. for details on how this is computed) + * return fast_hashcode_path (see ValueKlass::Members::_fast_hashcode_offset et seqq. for details on how this is computed) * * slow: * runtime call to hash function (this may be replaced with the expanded form during IGVN. See CallStaticJavaNode::replace_identity_hash_code) @@ -5559,7 +5590,7 @@ bool LibraryCallKit::inline_native_hashcode(bool is_virtual, bool is_static) { _slow_path = 1, // Actually perform the runtime call _cache_path, // Get the hash from the header _null_path, // If object is null, hash is 0. - _inline_fast_path, // Fast path for value objects only (see InlineKlass::Members::_fast_hashcode_offset et seqq.) + _inline_fast_path, // Fast path for value objects only (see ValueKlass::Members::_fast_hashcode_offset et seqq.) PATH_LIMIT, }; @@ -5569,11 +5600,11 @@ bool LibraryCallKit::inline_native_hashcode(bool is_virtual, bool is_static) { PhiNode* result_mem = new PhiNode(result_reg, Type::MEMORY, TypePtr::BOTTOM); Node* obj = argument(0); - if (obj->is_InlineType()) { + if (obj->is_ValueType()) { PreserveReexecuteState preexecs(this); inc_sp(2); jvms()->set_should_reexecute(true); - obj = obj->as_InlineType()->buffer(this); + obj = obj->as_ValueType()->buffer(this); } if (!is_static) { @@ -5601,7 +5632,7 @@ bool LibraryCallKit::inline_native_hashcode(bool is_virtual, bool is_static) { // We only go to the cache case code if we pass a number of guards. The paths which do // not pass are accumulated in the inline_fast_path_region. The compute region tries - // to use the fast path for inline types. That also needs a lot of guards to be met. + // to use the fast path for value types. That also needs a lot of guards to be met. // The paths which do not pass are accumulated in the slow_region, where we do the // runtime call, which is the last resort. RegionNode* inline_fast_path_region = new RegionNode(1); @@ -5634,14 +5665,14 @@ bool LibraryCallKit::inline_native_hashcode(bool is_virtual, bool is_static) { set_control(_gvn.transform(inline_fast_path_region)); IfNode* fast_path_iff = nullptr; if (!stopped()) { - if (UseHashcodeFastPath && is_static && !_gvn.type(obj)->is_inlinetypeptr()) { - Node* is_not_value = inline_type_test(obj, false); + if (UseHashcodeFastPath && is_static && !_gvn.type(obj)->is_valueklassptr()) { + Node* is_not_value = value_type_test(obj, false); generate_fair_guard(is_not_value, slow_region); if (!stopped()) { - // See InlineKlass::Members::_fast_hashcode_offset et seqq. for details on the fast path logic - Node* members_addr = off_heap_plus_addr(obj_klass, in_bytes(InlineKlass::adr_members_offset())); + // See ValueKlass::Members::_fast_hashcode_offset et seqq. for details on the fast path logic + Node* members_addr = off_heap_plus_addr(obj_klass, in_bytes(ValueKlass::adr_members_offset())); Node* members = make_load(control(), members_addr, TypeRawPtr::BOTTOM, T_ADDRESS, MemNode::unordered); - Node* offset_addr = off_heap_plus_addr(members, in_bytes(InlineKlass::fast_hashcode_offset_offset())); + Node* offset_addr = off_heap_plus_addr(members, in_bytes(ValueKlass::fast_hashcode_offset_offset())); Node* offset = make_load(control(), offset_addr, TypeInt::INT, T_INT, MemNode::unordered); Node* bol_no_fast_path = BoolCmpI(offset, BoolTest::lt, zerocon(T_INT)); generate_slow_guard(bol_no_fast_path, slow_region); @@ -5658,7 +5689,7 @@ bool LibraryCallKit::inline_native_hashcode(bool is_virtual, bool is_static) { // 1. the object has no segment, the hash is simply the hash of the class object // 2. the object has one segment of size smaller than 8 (1, 2, 4) // 3. the object has one segment of size 8 (long-sized) - // See inlineKlass.hpp on why and how to tell them apart. + // See valueKlass.hpp on why and how to tell them apart. RegionNode* unmasked_region = new RegionNode(4); Node* unmasked_result = new PhiNode(unmasked_region, TypeInt::INT); @@ -5673,7 +5704,7 @@ bool LibraryCallKit::inline_native_hashcode(bool is_virtual, bool is_static) { Node* obj_payload_addr = basic_plus_adr(obj, ConvI2L(offset)); Node* obj_payload = make_load(control(), obj_payload_addr, TypeLong::LONG, T_LONG, MemNode::unordered, LoadNNode::DependsOnlyOnTest, false, true, true, true); - Node* shift_addr = off_heap_plus_addr(members, in_bytes(InlineKlass::fast_hashcode_shift_offset())); + Node* shift_addr = off_heap_plus_addr(members, in_bytes(ValueKlass::fast_hashcode_shift_offset())); Node* shift = make_load(control(), shift_addr, TypeInt::INT, T_INT, MemNode::unordered); #ifdef VM_LITTLE_ENDIAN // *(obj + offset) >> shift @@ -5789,7 +5820,7 @@ IfNode* LibraryCallKit::hashcode_fast_path_if_from_identity_hash_code_call(Phase if (!offset_addr_add->in(AddPNode::Base)->is_top()) continue; if (offset_addr_add->in(AddPNode::Address)->Opcode() != Op_LoadP) continue; LoadNode* load_members = offset_addr_add->in(AddPNode::Address)->as_Load(); - if (!is_con_offset(offset_addr_add->in(AddPNode::Offset), InlineKlass::fast_hashcode_offset_offset())) continue; + if (!is_con_offset(offset_addr_add->in(AddPNode::Offset), ValueKlass::fast_hashcode_offset_offset())) continue; assert(load_members->in(2) != nullptr, ""); if (!load_members->in(2)->is_AddP()) continue; @@ -5800,7 +5831,7 @@ IfNode* LibraryCallKit::hashcode_fast_path_if_from_identity_hash_code_call(Phase assert(members_addr_add->in(AddPNode::Offset) != nullptr, ""); if (!members_addr_add->in(AddPNode::Base)->is_top()) continue; if (!phase->type(members_addr_add->in(AddPNode::Address))->isa_instklassptr()) continue; - if (!is_con_offset(members_addr_add->in(AddPNode::Offset), InlineKlass::adr_members_offset())) continue; + if (!is_con_offset(members_addr_add->in(AddPNode::Offset), ValueKlass::adr_members_offset())) continue; return iff; } @@ -5813,12 +5844,12 @@ IfNode* LibraryCallKit::hashcode_fast_path_if_from_identity_hash_code_call(Phase // Build special case code for calls to getClass on an object. bool LibraryCallKit::inline_native_getClass() { Node* obj = argument(0); - if (obj->is_InlineType()) { + if (obj->is_ValueType()) { const Type* t = _gvn.type(obj); if (t->maybe_null()) { null_check(obj); } - set_result(makecon(TypeInstPtr::make(t->inline_klass()->java_mirror()))); + set_result(makecon(TypeInstPtr::make(t->value_klass()->java_mirror()))); return true; } obj = null_check_receiver(); @@ -6252,11 +6283,11 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) { if (stopped()) return true; const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr(); - if (obj_type->is_inlinetypeptr()) { - // If the object to clone is an inline type, we can simply return it (i.e. a nop) since inline types have + if (obj_type->is_valueklassptr()) { + // If the object to clone is a value type, we can simply return it (i.e. a nop) since value types have // no identity. But we first need to check whether the value class is actually implementing the Cloneable // interface. If not, we trap. - if (obj_type->inline_klass()->is_cloneable()) { + if (obj_type->value_klass()->is_cloneable()) { set_result(obj); } else { uncommon_trap(Deoptimization::Reason_intrinsic, @@ -6271,7 +6302,7 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) { if (!obj_type->klass_is_exact() && obj_type->speculative_type() != nullptr && obj_type->speculative_type()->is_instance_klass() && - !obj_type->speculative_type()->is_inlinetype()) { + !obj_type->speculative_type()->is_value_klass()) { ciInstanceKlass* spec_ik = obj_type->speculative_type()->as_instance_klass(); if (spec_ik->nof_nonstatic_fields() <= ArrayCopyLoadStoreMaxElem && !spec_ik->has_injected_fields()) { @@ -6316,9 +6347,9 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) { BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); const TypeAryPtr* ary_ptr = obj_type->isa_aryptr(); if (UseArrayFlattening && bs->array_copy_requires_gc_barriers(true, T_OBJECT, true, false, BarrierSetC2::Expansion) && - obj_type->can_be_inline_array() && - (ary_ptr == nullptr || (!ary_ptr->is_not_flat() && (!ary_ptr->is_flat() || ary_ptr->elem()->inline_klass()->contains_oops())))) { - // Flat inline type array may have object field that would require a + obj_type->can_be_value_array() && + (ary_ptr == nullptr || (!ary_ptr->is_not_flat() && (!ary_ptr->is_flat() || ary_ptr->elem()->value_klass()->contains_oops())))) { + // Flat value type array may have object field that would require a // write barrier. Conservatively, go to slow path. generate_fair_guard(flat_array_test(obj), slow_region); } @@ -6519,7 +6550,7 @@ SafePointNode* LibraryCallKit::create_safepoint_with_state_before_array_allocati // Re-create and push the initVal. Node* init_val = alloc->in(AllocateNode::InitValue); if (init_val == nullptr) { - init_val = InlineTypeNode::make_all_zero(_gvn, ary_klass_ptr->elem()->is_instklassptr()->instance_klass()->as_inline_klass()); + init_val = ValueTypeNode::make_all_zero(_gvn, ary_klass_ptr->elem()->is_instklassptr()->instance_klass()->as_value_klass()); } else if (UseCompressedOops) { init_val = _gvn.transform(new DecodeNNode(init_val, init_val->bottom_type()->make_ptr())); } diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index ce9735cc1748..0f185c9fa1a7 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -27,13 +27,14 @@ #include "ci/ciMethod.hpp" #include "classfile/javaClasses.hpp" +#include "classfile/vmIntrinsics.hpp" #include "opto/callGenerator.hpp" #include "opto/castnode.hpp" #include "opto/convertnode.hpp" #include "opto/graphKit.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/intrinsicnode.hpp" #include "opto/movenode.hpp" +#include "opto/valuetypenode.hpp" class LibraryIntrinsic : public InlineCallGenerator { // Extend the set of intrinsics known to the runtime: @@ -116,12 +117,12 @@ class LibraryCallKit : public GraphKit { C->record_method_not_compilable("Can't determine return value."); } BasicType bt = res->bottom_type()->basic_type(); - if (C->inlining_incrementally() && res->is_InlineType()) { + if (C->inlining_incrementally() && res->is_ValueType()) { // The caller expects an oop when incrementally inlining an intrinsic that returns an - // inline type. Make sure the call is re-executed if the allocation triggers a deoptimization. + // value type. Make sure the call is re-executed if the allocation triggers a deoptimization. PreserveReexecuteState preexecs(this); jvms()->set_should_reexecute(true); - res = res->as_InlineType()->buffer(this); + res = res->as_ValueType()->buffer(this); } push_node(bt, res); } @@ -253,6 +254,7 @@ class LibraryCallKit : public GraphKit { bool inline_math_subtractExactI(bool is_decrement); bool inline_math_subtractExactL(bool is_decrement); bool inline_min_max(vmIntrinsics::ID id); + bool inline_int128t_addsub(vmIntrinsics::ID id); bool inline_notify(vmIntrinsics::ID id); // This returns Type::AnyPtr, RawPtr, or OopPtr. int classify_unsafe_addr(Node* &base, Node* &offset, BasicType type); diff --git a/src/hotspot/share/opto/locknode.cpp b/src/hotspot/share/opto/locknode.cpp index ab37ee8326ff..5616343e0c89 100644 --- a/src/hotspot/share/opto/locknode.cpp +++ b/src/hotspot/share/opto/locknode.cpp @@ -195,8 +195,8 @@ const Type* FastLockNode::Value(PhaseGVN* phase) const { if (in1_t == Type::TOP) { return Type::TOP; } - if (in1_t->is_inlinetypeptr()) { - // Locking on inline types always fails + if (in1_t->is_valueklassptr()) { + // Locking on value types always fails return TypeInt::CC_GT; } return TypeInt::CC; @@ -222,8 +222,8 @@ void Parse::do_monitor_enter() { if (stopped()) return; { - // Synchronizing on an inline type is not allowed - BuildCutout unless(this, inline_type_test(obj, /* is_inline = */ false), PROB_MAX); + // Synchronizing on a value type is not allowed + BuildCutout unless(this, value_type_test(obj, /* is_inline = */ false), PROB_MAX); uncommon_trap_exact(Deoptimization::Reason_class_check, Deoptimization::Action_none); } diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index f652b4827dbc..09ea9740ce55 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -4076,11 +4076,6 @@ bool PhaseIdealLoop::intrinsify_fill(IdealLoopTree* lpt) { } Node* from = AddPNode::make_with_base(base, index); _igvn.register_new_node_with_optimizer(from); - // For normal array fills, C2 uses two AddP nodes for array element - // addressing. But for array fills with Unsafe call, there's only one - // AddP node adding an absolute offset, so we do a null check here. - assert(offset != nullptr || C->has_unsafe_access(), - "Only array fills with unsafe have no extra offset"); if (offset != nullptr) { from = AddPNode::make_with_base(base, from, offset); _igvn.register_new_node_with_optimizer(from); diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index d60001ad737d..a71b80b11a40 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -99,7 +99,9 @@ Node *PhaseIdealLoop::get_early_ctrl( Node *n ) { assert( !n->is_Phi() && !n->is_CFG(), "this code only handles data nodes" ); uint i; Node *early; - if (n->in(0) && !n->is_expensive()) { + // During verification we also get early control for expensive nodes here, + // as get_early_ctrl_for_expensive is skipped because it modifies the graph. + if (n->in(0) != nullptr && (!n->is_expensive() || _verify_me != nullptr || _verify_only)) { early = n->in(0); if (!early->is_CFG()) // Might be a non-CFG multi-def early = get_ctrl(early); // So treat input as a straight data input diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index d81ac3b76368..43539fc09f05 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -31,7 +31,6 @@ #include "opto/castnode.hpp" #include "opto/connode.hpp" #include "opto/divnode.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/loopnode.hpp" #include "opto/matcher.hpp" #include "opto/movenode.hpp" @@ -41,6 +40,7 @@ #include "opto/subnode.hpp" #include "opto/subtypenode.hpp" #include "opto/superword.hpp" +#include "opto/valuetypenode.hpp" #include "opto/vectornode.hpp" #include "utilities/checkedCast.hpp" #include "utilities/macros.hpp" @@ -64,9 +64,9 @@ Node* PhaseIdealLoop::split_thru_phi(Node* n, Node* region, int policy) { return nullptr; } - // Inline types should not be split through Phis because they cannot be merged + // Value types should not be split through Phis because they cannot be merged // through Phi nodes but each value input needs to be merged individually. - if (n->is_InlineType()) { + if (n->is_ValueType()) { return nullptr; } @@ -1731,9 +1731,9 @@ void PhaseIdealLoop::split_if_with_blocks_post(Node *n) { try_move_store_after_loop(n); - // Remove multiple allocations of the same inline type - if (n->is_InlineType()) { - n->as_InlineType()->remove_redundant_allocations(this); + // Remove multiple allocations of the same value type + if (n->is_ValueType()) { + n->as_ValueType()->remove_redundant_allocations(this); } } diff --git a/src/hotspot/share/opto/machnode.cpp b/src/hotspot/share/opto/machnode.cpp index 7990cb3a7c83..b7b50ceaf5a3 100644 --- a/src/hotspot/share/opto/machnode.cpp +++ b/src/hotspot/share/opto/machnode.cpp @@ -417,7 +417,7 @@ const class TypePtr *MachNode::adr_type() const { assert(tp->base() != Type::AnyPtr, "not a bare pointer"); if (tp->isa_aryptr()) { - // In the case of a flat inline type array, each field has its + // In the case of a flat value type array, each field has its // own slice so we need to extract the field being accessed from // the address computation if (offset == Type::OffsetBot) { @@ -770,7 +770,7 @@ bool MachCallNode::returns_pointer() const { } bool MachCallNode::returns_scalarized() const { - return tf()->returns_inline_type_as_fields(); + return tf()->returns_value_type_as_fields(); } //------------------------------Registers-------------------------------------- diff --git a/src/hotspot/share/opto/machnode.hpp b/src/hotspot/share/opto/machnode.hpp index ffa6e1ad9dcc..ff56670a8427 100644 --- a/src/hotspot/share/opto/machnode.hpp +++ b/src/hotspot/share/opto/machnode.hpp @@ -512,7 +512,7 @@ class MachConstantNode : public MachNode { }; //------------------------------MachVEPNode----------------------------------- -// Machine Inline Type Entry Point Node +// Machine Value type Entry Point Node class MachVEPNode : public MachIdealNode { public: Label* _verified_entry; @@ -533,7 +533,7 @@ class MachVEPNode : public MachIdealNode { virtual void emit(C2_MacroAssembler *masm, PhaseRegAlloc* ra_) const; #ifndef PRODUCT - virtual const char* Name() const { return "InlineType Entry-Point"; } + virtual const char* Name() const { return "ValueType Entry-Point"; } virtual void format(PhaseRegAlloc*, outputStream* st) const; #endif private: diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 5421e490bc23..9269179bfbe4 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -23,8 +23,8 @@ */ #include "ci/ciFlatArrayKlass.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciInstanceKlass.hpp" +#include "ci/ciValueKlass.hpp" #include "compiler/compileLog.hpp" #include "gc/shared/collectedHeap.inline.hpp" #include "gc/shared/tlab_globals.hpp" @@ -38,12 +38,14 @@ #include "opto/compile.hpp" #include "opto/convertnode.hpp" #include "opto/graphKit.hpp" -#include "opto/inlinetypenode.hpp" +#include "opto/int128tnode.hpp" #include "opto/intrinsicnode.hpp" #include "opto/locknode.hpp" #include "opto/loopnode.hpp" #include "opto/macro.hpp" +#include "opto/matcher.hpp" #include "opto/memnode.hpp" +#include "opto/movenode.hpp" #include "opto/narrowptrnode.hpp" #include "opto/node.hpp" #include "opto/opaquenode.hpp" @@ -55,6 +57,7 @@ #include "opto/subnode.hpp" #include "opto/subtypenode.hpp" #include "opto/type.hpp" +#include "opto/valuetypenode.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/continuation.hpp" #include "runtime/sharedRuntime.hpp" @@ -368,7 +371,7 @@ Node* PhaseMacroExpand::make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* off = _igvn.transform(new AddXNode(_igvn.MakeConX(offset), diff)); adr = _igvn.transform(AddPNode::make_with_base(base, base, off)); - // In the case of a flat inline type array, each field has its + // In the case of a flat value type array, each field has its // own slice so we need to extract the field being accessed from // the address computation adr_type = ((TypeAryPtr*)adr_type)->add_field_offset_and_offset(offset)->add_offset(Type::OffsetBot)->is_aryptr(); @@ -544,15 +547,15 @@ Node* PhaseMacroExpand::value_from_alloc(BasicType ft, const TypeOopPtr* adr_t, init_value = init_value->in(1); } // Cannot look through init_value if it is an oop - if (!init_value->is_InlineType()) { + if (!init_value->is_ValueType()) { return nullptr; } - ciInlineKlass* vk = init_value->bottom_type()->inline_klass(); + ciValueKlass* vk = init_value->bottom_type()->value_klass(); if (ary_t->field_offset().get() == vk->null_marker_offset_in_payload()) { - init_value = init_value->as_InlineType()->get_null_marker(); + init_value = init_value->as_ValueType()->get_null_marker(); } else { - init_value = init_value->as_InlineType()->field_value_by_offset(ary_t->field_offset().get() + vk->payload_offset(), true); + init_value = init_value->as_ValueType()->field_value_by_offset(ary_t->field_offset().get() + vk->payload_offset(), true); } if (ft == T_NARROWOOP) { @@ -683,12 +686,12 @@ Node* PhaseMacroExpand::value_from_mem(Node* origin, Node* ctl, BasicType ft, co return nullptr; } -// Search the last value stored into the inline type's fields (for flat arrays). -Node* PhaseMacroExpand::inline_type_from_mem(ciInlineKlass* vk, const TypeAryPtr* elem_adr_type, int elem_idx, int offset_in_element, bool null_free, AllocateNode* alloc, SafePointNode* sfpt) { +// Search the last value stored into the value type's fields (for flat arrays). +Node* PhaseMacroExpand::value_type_from_mem(ciValueKlass* vk, const TypeAryPtr* elem_adr_type, int elem_idx, int offset_in_element, bool null_free, AllocateNode* alloc, SafePointNode* sfpt) { auto report_failure = [&](int field_offset_in_element, bool is_forced_failure) { #ifndef PRODUCT if (PrintEliminateAllocations) { - ciInlineKlass* elem_klass = elem_adr_type->elem()->inline_klass(); + ciValueKlass* elem_klass = elem_adr_type->elem()->value_klass(); int offset = field_offset_in_element + elem_klass->payload_offset(); ciField* flattened_field = elem_klass->get_field_by_offset(offset, false); assert(flattened_field != nullptr, "must have a field of type %s at offset %d", elem_klass->name()->as_utf8(), offset); @@ -705,8 +708,8 @@ Node* PhaseMacroExpand::inline_type_from_mem(ciInlineKlass* vk, const TypeAryPtr #endif // PRODUCT }; - // Create a new InlineTypeNode and retrieve the field values from memory - InlineTypeNode* vt = InlineTypeNode::make_uninitialized(_igvn, vk, null_free); + // Create a new ValueTypeNode and retrieve the field values from memory + ValueTypeNode* vt = ValueTypeNode::make_uninitialized(_igvn, vk, null_free); transform_later(vt); if (null_free) { vt->set_null_marker(_igvn); @@ -729,9 +732,9 @@ Node* PhaseMacroExpand::inline_type_from_mem(ciInlineKlass* vk, const TypeAryPtr ciType* field_type = field->type(); int field_offset_in_element = offset_in_element + field->offset_in_bytes() - vk->payload_offset(); Node* field_value = nullptr; - assert(!field->is_flat() || field->type()->is_inlinetype(), "must be an inline type"); + assert(!field->is_flat() || field->type()->is_value_klass(), "must be a value type"); if (field->is_flat()) { - field_value = inline_type_from_mem(field_type->as_inline_klass(), elem_adr_type, elem_idx, field_offset_in_element, field->is_null_free(), alloc, sfpt); + field_value = value_type_from_mem(field_type->as_value_klass(), elem_adr_type, elem_idx, field_offset_in_element, field->is_null_free(), alloc, sfpt); } else { const Type* ft = Type::get_const_type(field_type); BasicType bt = type2field[field_type->basic_type()]; @@ -739,7 +742,7 @@ Node* PhaseMacroExpand::inline_type_from_mem(ciInlineKlass* vk, const TypeAryPtr ft = ft->make_narrowoop(); bt = T_NARROWOOP; } - // Each inline type field has its own memory slice + // Each value type field has its own memory slice const TypeAryPtr* field_adr_type = elem_adr_type->with_field_offset(field_offset_in_element); field_value = value_from_mem(sfpt, sfpt->control(), bt, ft, field_adr_type, alloc); bool force_scalarization_failure = StressEliminateAllocations && @@ -751,7 +754,7 @@ Node* PhaseMacroExpand::inline_type_from_mem(ciInlineKlass* vk, const TypeAryPtr assert(UseCompressedOops, "unexpected narrow oop"); if (field_value->is_EncodeP()) { field_value = field_value->in(1); - } else if (!field_value->is_InlineType()) { + } else if (!field_value->is_ValueType()) { field_value = transform_later(new DecodeNNode(field_value, field_value->get_ptr_type())); } } @@ -855,16 +858,16 @@ bool PhaseMacroExpand::can_eliminate_allocation(PhaseIterGVN* igvn, AllocateNode NOT_PRODUCT(fail_eliminate = "null or TOP memory";) can_eliminate = false; } else if (!reduce_merge_precheck) { - assert(!res->is_Phi() || !res->as_Phi()->can_be_inline_type(), "Inline type allocations should not have safepoint uses"); + assert(!res->is_Phi() || !res->as_Phi()->can_be_value_type(), "Value type allocations should not have safepoint uses"); safepoints->push(sfpt); } - } else if (use->is_InlineType() && use->as_InlineType()->get_oop() == res) { + } else if (use->is_ValueType() && use->as_ValueType()->get_oop() == res) { // Look at uses for (DUIterator_Fast kmax, k = use->fast_outs(kmax); k < kmax; k++) { Node* u = use->fast_out(k); - if (u->is_InlineType()) { + if (u->is_ValueType()) { // Use in flat field can be eliminated - InlineTypeNode* vt = u->as_InlineType(); + ValueTypeNode* vt = u->as_ValueType(); for (uint i = 0; i < vt->field_count(); ++i) { if (vt->field_value(i) == use && !vt->field(i)->is_flat()) { can_eliminate = false; // Use in non-flat field @@ -877,10 +880,10 @@ bool PhaseMacroExpand::can_eliminate_allocation(PhaseIterGVN* igvn, AllocateNode } } } else if (use->Opcode() == Op_StoreX && use->in(MemNode::Address) == res) { - // Store to mark word of inline type larval buffer - assert(res_type->is_inlinetypeptr(), "Unexpected store to mark word"); - } else if (res_type->is_inlinetypeptr() && (use->Opcode() == Op_MemBarRelease || use->Opcode() == Op_MemBarStoreStore)) { - // Inline type buffer allocations are followed by a membar + // Store to mark word of value type larval buffer + assert(res_type->is_valueklassptr(), "Unexpected store to mark word"); + } else if (res_type->is_valueklassptr() && (use->Opcode() == Op_MemBarRelease || use->Opcode() == Op_MemBarStoreStore)) { + // Value type buffer allocations are followed by a membar } else if (reduce_merge_precheck && (use->is_Phi() || use->is_EncodeP() || use->Opcode() == Op_MemBarRelease || @@ -1038,20 +1041,20 @@ void PhaseMacroExpand::process_field_value_at_safepoint(const Type* field_type, // to be able scalar replace the allocation. if (field_val->is_EncodeP()) { field_val = field_val->in(1); - } else if (!field_val->is_InlineType()) { + } else if (!field_val->is_ValueType()) { field_val = transform_later(new DecodeNNode(field_val, field_val->get_ptr_type())); } } - // Keep track of inline types to scalarize them later - if (field_val->is_InlineType()) { + // Keep track of value types to scalarize them later + if (field_val->is_ValueType()) { value_worklist->push(field_val); } else if (field_val->is_Phi()) { PhiNode* phi = field_val->as_Phi(); - // Eagerly replace inline type phis now since we could be removing an inline type allocation where we must + // Eagerly replace value type phis now since we could be removing a value type allocation where we must // scalarize all its fields in safepoints. - field_val = phi->try_push_inline_types_down(&_igvn, true); - if (field_val->is_InlineType()) { + field_val = phi->try_push_value_types_down(&_igvn, true); + if (field_val->is_ValueType()) { value_worklist->push(field_val); } } @@ -1079,9 +1082,9 @@ bool PhaseMacroExpand::add_array_elems_to_safepoint(AllocateNode* alloc, const T const TypeAryPtr* elem_adr_type = array_type->with_offset(elem_offset); Node* elem_val; if (array_type->is_flat()) { - ciInlineKlass* elem_klass = elem_type->inline_klass(); + ciValueKlass* elem_klass = elem_type->value_klass(); assert(elem_klass->maybe_flat_in_array(), "must be flat in array"); - elem_val = inline_type_from_mem(elem_klass, elem_adr_type, elem_idx, 0, array_type->is_null_free(), alloc, sfpt); + elem_val = value_type_from_mem(elem_klass, elem_adr_type, elem_idx, 0, array_type->is_null_free(), alloc, sfpt); } else { elem_val = value_from_mem(sfpt, sfpt->control(), basic_elem_type, elem_type, elem_adr_type, alloc); } @@ -1139,7 +1142,7 @@ bool PhaseMacroExpand::add_inst_fields_to_safepoint(ciInstanceKlass* iklass, All for (int i = 0; i < iklass->nof_declared_nonstatic_fields(); i++) { ciField* field = iklass->declared_nonstatic_field_at(i); if (field->is_flat()) { - ciInlineKlass* fvk = field->type()->as_inline_klass(); + ciValueKlass* fvk = field->type()->as_value_klass(); int field_offset_minus_header = offset_minus_header + field->offset_in_bytes() - fvk->payload_offset(); bool success = add_inst_fields_to_safepoint(fvk, alloc, base, field_offset_minus_header, sfpt, value_worklist); if (!success) { @@ -1225,13 +1228,13 @@ SafePointScalarObjectNode* PhaseMacroExpand::create_scalarized_object_descriptio assert(nfields >= 0, "must be an array klass."); } - if (res->bottom_type()->is_inlinetypeptr()) { - // Nullable inline types have a null marker field which is added to the safepoint when scalarizing them (see - // InlineTypeNode::make_scalar_in_safepoint()). When having circular inline types, we stop scalarizing at depth 1 + if (res->bottom_type()->is_valueklassptr()) { + // Nullable value types have a null marker field which is added to the safepoint when scalarizing them (see + // ValueTypeNode::make_scalar_in_safepoint()). When having circular value types, we stop scalarizing at depth 1 // to avoid an endless recursion. Therefore, we do not have a SafePointScalarObjectNode node here, yet. // We are about to create a SafePointScalarObjectNode as if this is a normal object. Add an additional int input // with value 1 which sets the null marker to true to indicate that the object is always non-null. This input is checked - // later in PhaseOutput::filLocArray() for inline types. + // later in PhaseOutput::filLocArray() for value types. sfpt->add_req(_igvn.intcon(1)); } } @@ -1305,12 +1308,12 @@ bool PhaseMacroExpand::scalar_replacement(AllocateNode* alloc, Unique_Node_List& // keep it for rollback safepoints_done.push(sfpt); } - // Scalarize inline types that were added to the safepoint. + // Scalarize value types that were added to the safepoint. // Don't allow linking a constant oop (if available) for flat array elements // because Deoptimization::reassign_flat_array_elements needs field values. bool allow_oop = (res_type != nullptr) && !res_type->is_flat(); for (uint i = 0; i < value_worklist.size(); ++i) { - InlineTypeNode* vt = value_worklist.at(i)->as_InlineType(); + ValueTypeNode* vt = value_worklist.at(i)->as_ValueType(); if (!vt->make_scalar_in_safepoints(&_igvn, allow_oop)) { C->record_failure("out of nodes during scalarization"); return false; @@ -1331,7 +1334,7 @@ static void disconnect_projections(MultiNode* n, PhaseIterGVN& igvn) { } // Process users of eliminated allocation. -void PhaseMacroExpand::process_users_of_allocation(CallNode *alloc, bool inline_alloc) { +void PhaseMacroExpand::process_users_of_allocation(CallNode *alloc, bool value_type_alloc) { Unique_Node_List worklist; Node* res = alloc->result_cast(); if (res != nullptr) { @@ -1351,8 +1354,8 @@ void PhaseMacroExpand::process_users_of_allocation(CallNode *alloc, bool inline_ for (DUIterator_Fast pmax, p = n->fast_outs(pmax); p < pmax; p++) { MemBarNode* mb = n->fast_out(p)->isa_MemBar(); if (mb != nullptr && mb->req() <= MemBarNode::Precedent && mb->in(MemBarNode::Precedent) == n) { - // MemBarVolatiles should have been removed by MemBarNode::Ideal() for non-inline allocations - assert(inline_alloc, "MemBarVolatile should be eliminated for non-escaping object"); + // MemBarVolatiles should have been removed by MemBarNode::Ideal() for non-value type allocations + assert(value_type_alloc, "MemBarVolatile should be eliminated for non-escaping object"); mb->remove(&_igvn); } } @@ -1400,29 +1403,29 @@ void PhaseMacroExpand::process_users_of_allocation(CallNode *alloc, bool inline_ } } _igvn._worklist.push(ac); - } else if (use->is_InlineType()) { - assert(use->as_InlineType()->get_oop() == res, "unexpected inline type ptr use"); + } else if (use->is_ValueType()) { + assert(use->as_ValueType()->get_oop() == res, "unexpected value type ptr use"); // Cut off oop input and remove known instance id from type _igvn.rehash_node_delayed(use); - use->as_InlineType()->set_oop(_igvn, _igvn.zerocon(T_OBJECT)); - use->as_InlineType()->set_is_buffered(_igvn, false); + use->as_ValueType()->set_oop(_igvn, _igvn.zerocon(T_OBJECT)); + use->as_ValueType()->set_is_buffered(_igvn, false); const TypeOopPtr* toop = _igvn.type(use)->is_oopptr()->cast_to_instance_id(TypeOopPtr::InstanceBot); _igvn.set_type(use, toop); - use->as_InlineType()->set_type(toop); + use->as_ValueType()->set_type(toop); // Process users for (DUIterator_Fast kmax, k = use->fast_outs(kmax); k < kmax; k++) { Node* u = use->fast_out(k); - if (!u->is_InlineType() && !u->is_StoreFlat()) { + if (!u->is_ValueType() && !u->is_StoreFlat()) { worklist.push(u); } } } else if (use->Opcode() == Op_StoreX && use->in(MemNode::Address) == res) { - // Store to mark word of inline type larval buffer - assert(inline_alloc, "Unexpected store to mark word"); + // Store to mark word of value type larval buffer + assert(value_type_alloc, "Unexpected store to mark word"); _igvn.replace_node(use, use->in(MemNode::Memory)); } else if (use->Opcode() == Op_MemBarRelease || use->Opcode() == Op_MemBarStoreStore) { - // Inline type buffer allocations are followed by a membar - assert(inline_alloc, "Unexpected MemBarRelease"); + // Value type buffer allocations are followed by a membar + assert(value_type_alloc, "Unexpected MemBarRelease"); use->as_MemBar()->remove(&_igvn); } else if (use->is_ReachabilityFence() && OptimizeReachabilityFences) { use->as_ReachabilityFence()->clear_referent(_igvn); // redundant fence; will be removed during IGVN @@ -1478,8 +1481,8 @@ void PhaseMacroExpand::process_users_of_allocation(CallNode *alloc, bool inline_ init->replace_mem_projs_by(mem, &_igvn); assert(init->outcnt() == 0, "should only have had a control and some memory projections, and we removed them"); } else if (use->Opcode() == Op_MemBarStoreStore) { - // Inline type buffer allocations are followed by a membar - assert(inline_alloc, "Unexpected MemBarStoreStore"); + // Value type buffer allocations are followed by a membar + assert(value_type_alloc, "Unexpected MemBarStoreStore"); use->as_MemBar()->remove(&_igvn); } else { assert(false, "only Initialize or AddP expected"); @@ -1519,11 +1522,11 @@ bool PhaseMacroExpand::eliminate_allocate_node(AllocateNode *alloc) { Node* klass = alloc->in(AllocateNode::KlassNode); const TypeKlassPtr* tklass = _igvn.type(klass)->is_klassptr(); - // Attempt to eliminate inline type buffer allocations + // Attempt to eliminate value type buffer allocations // regardless of usage and escape/replaceable status. - bool inline_alloc = tklass->isa_instklassptr() && - tklass->is_instklassptr()->instance_klass()->is_inlinetype(); - if (!alloc->_is_non_escaping && !inline_alloc) { + bool value_type_alloc = tklass->isa_instklassptr() && + tklass->is_instklassptr()->instance_klass()->is_value_klass(); + if (!alloc->_is_non_escaping && !value_type_alloc) { return false; } // Eliminate boxing allocations which are not used @@ -1532,7 +1535,7 @@ bool PhaseMacroExpand::eliminate_allocate_node(AllocateNode *alloc) { bool boxing_alloc = (res == nullptr) && C->eliminate_boxing() && tklass->isa_instklassptr() && tklass->is_instklassptr()->instance_klass()->is_box_klass(); - if (!alloc->_is_scalar_replaceable && !boxing_alloc && !inline_alloc) { + if (!alloc->_is_scalar_replaceable && !boxing_alloc && !value_type_alloc) { return false; } @@ -1544,7 +1547,7 @@ bool PhaseMacroExpand::eliminate_allocate_node(AllocateNode *alloc) { } if (!alloc->_is_scalar_replaceable) { - assert(res == nullptr || inline_alloc, "sanity"); + assert(res == nullptr || value_type_alloc, "sanity"); // We can only eliminate allocation if all debug info references // are already replaced with SafePointScalarObject because // we can't search for a fields value without instance_id. @@ -1569,7 +1572,7 @@ bool PhaseMacroExpand::eliminate_allocate_node(AllocateNode *alloc) { log->tail("eliminate_allocation"); } - process_users_of_allocation(alloc, inline_alloc); + process_users_of_allocation(alloc, value_type_alloc); #ifndef PRODUCT if (PrintEliminateAllocations) { @@ -2814,13 +2817,13 @@ void PhaseMacroExpand::expand_unlock_node(UnlockNode *unlock) { } } -// An inline type might be returned from the call but we don't know its -// type. Either we get a buffered inline type (and nothing needs to be done) -// or one of the values being returned is the klass of the inline type -// and we need to allocate an inline type instance of that type and +// A value type might be returned from the call but we don't know its +// type. Either we get a buffered value type (and nothing needs to be done) +// or one of the values being returned is the klass of the value type +// and we need to allocate a value type instance of that type and // initialize it with other values being returned. In that case, we // first try a fast path allocation and initialize the value with the -// inline klass's pack handler or we fall back to a runtime call. +// value klass's pack handler or we fall back to a runtime call. void PhaseMacroExpand::expand_mh_intrinsic_return(CallStaticJavaNode* call) { assert(call->method()->is_method_handle_intrinsic(), "must be a method handle intrinsic call"); Node* ret = call->proj_out_or_null(TypeFunc::Parms); @@ -2828,7 +2831,7 @@ void PhaseMacroExpand::expand_mh_intrinsic_return(CallStaticJavaNode* call) { return; } const TypeFunc* tf = call->_tf; - const TypeTuple* domain = OptoRuntime::store_inline_type_fields_Type()->domain_cc(); + const TypeTuple* domain = OptoRuntime::store_value_type_fields_Type()->domain_cc(); const TypeFunc* new_tf = TypeFunc::make(tf->domain_sig(), tf->domain_cc(), tf->range_sig(), domain, true); call->_tf = new_tf; // Make sure the change of type is applied before projections are processed by igvn @@ -2848,7 +2851,7 @@ void PhaseMacroExpand::expand_mh_intrinsic_return(CallStaticJavaNode* call) { Node* ex_io = new Node(ctl); Node* res = new Node(ctl); - // Allocate a new buffered inline type only if a new one is not returned + // Allocate a new buffered value type only if a new one is not returned Node* cast = transform_later(new CastP2XNode(ctl, res)); Node* mask = MakeConX(0x1); Node* masked = transform_later(new AndXNode(cast, mask)); @@ -2860,7 +2863,7 @@ void PhaseMacroExpand::expand_mh_intrinsic_return(CallStaticJavaNode* call) { Node* no_allocation_ctl = transform_later(new IfFalseNode(allocation_iff)); Node* no_allocation_res = transform_later(new CheckCastPPNode(no_allocation_ctl, res, TypeInstPtr::BOTTOM)); - // Try to allocate a new buffered inline instance either from TLAB or eden space + // Try to allocate a new buffered value instance either from TLAB or eden space Node* needgc_ctrl = nullptr; // needgc means slowcase, i.e. allocation failed CallLeafNoFPNode* handler_call; const bool alloc_in_place = UseTLAB; @@ -2877,15 +2880,15 @@ void PhaseMacroExpand::expand_mh_intrinsic_return(CallStaticJavaNode* call) { Node* fast_oop = bs->obj_allocate(this, mem, allocation_ctl, size_in_bytes, io, needgc_ctrl, fast_oop_ctrl, fast_oop_rawmem, AllocateInstancePrefetchLines); - // Allocation succeed, initialize buffered inline instance header firstly, - // and then initialize its fields with an inline class specific handler + // Allocation succeed, initialize buffered value instance header firstly, + // and then initialize its fields with a value class specific handler Node* mark_word_node; if (UseCompactObjectHeaders) { // COH: We need to load the prototype from the klass at runtime since it encodes the klass pointer already. mark_word_node = make_load_raw(fast_oop_ctrl, fast_oop_rawmem, klass_node, in_bytes(Klass::prototype_header_offset()), TypeRawPtr::BOTTOM, T_ADDRESS); } else { // Otherwise, use the static prototype. - mark_word_node = makecon(TypeRawPtr::make((address)markWord::inline_type_prototype().value())); + mark_word_node = makecon(TypeRawPtr::make((address)markWord::value_type_prototype().value())); } fast_oop_rawmem = make_store_raw(fast_oop_ctrl, fast_oop_rawmem, fast_oop, oopDesc::mark_offset_in_bytes(), mark_word_node, T_ADDRESS); @@ -2894,9 +2897,9 @@ void PhaseMacroExpand::expand_mh_intrinsic_return(CallStaticJavaNode* call) { fast_oop_rawmem = make_store_raw(fast_oop_ctrl, fast_oop_rawmem, fast_oop, oopDesc::klass_offset_in_bytes(), klass_node, T_METADATA); fast_oop_rawmem = make_store_raw(fast_oop_ctrl, fast_oop_rawmem, fast_oop, oopDesc::klass_gap_offset_in_bytes(), intcon(0), T_INT); } - Node* members = make_load_raw(fast_oop_ctrl, fast_oop_rawmem, klass_node, in_bytes(InlineKlass::adr_members_offset()), TypeRawPtr::BOTTOM, T_ADDRESS); - Node* pack_handler = make_load_raw(fast_oop_ctrl, fast_oop_rawmem, members, in_bytes(InlineKlass::pack_handler_offset()), TypeRawPtr::BOTTOM, T_ADDRESS); - handler_call = new CallLeafNoFPNode(OptoRuntime::pack_inline_type_Type(), + Node* members = make_load_raw(fast_oop_ctrl, fast_oop_rawmem, klass_node, in_bytes(ValueKlass::adr_members_offset()), TypeRawPtr::BOTTOM, T_ADDRESS); + Node* pack_handler = make_load_raw(fast_oop_ctrl, fast_oop_rawmem, members, in_bytes(ValueKlass::pack_handler_offset()), TypeRawPtr::BOTTOM, T_ADDRESS); + handler_call = new CallLeafNoFPNode(OptoRuntime::pack_value_type_Type(), nullptr, "pack handler", TypeRawPtr::BOTTOM); @@ -2912,9 +2915,9 @@ void PhaseMacroExpand::expand_mh_intrinsic_return(CallStaticJavaNode* call) { } // Allocation failed, fall back to a runtime call - CallStaticJavaNode* slow_call = new CallStaticJavaNode(OptoRuntime::store_inline_type_fields_Type(), - SharedRuntime::store_inline_type_fields_to_buf_entry(), - "store_inline_type_fields", + CallStaticJavaNode* slow_call = new CallStaticJavaNode(OptoRuntime::store_value_type_fields_Type(), + SharedRuntime::store_value_type_fields_to_buf_entry(), + "store_value_type_fields", TypePtr::BOTTOM); slow_call->init_req(TypeFunc::Control, needgc_ctrl); slow_call->init_req(TypeFunc::Memory, mem); @@ -3164,6 +3167,49 @@ void PhaseMacroExpand::expand_flatarraycheck_node(FlatArrayCheckNode* check) { } } +void PhaseMacroExpand::expand_add_sub_i128t_node(Int128TBinaryNode* addsub) { + if (Matcher::match_rule_supported(addsub->Opcode())) { + addsub->remove_flag(Node::Flag_is_macro); + C->remove_macro_node(addsub); + return; + } + + bool is_add = addsub->Opcode() == Op_AddI128T; + Node* new_lo; + if (is_add) { + new_lo = _igvn.transform(new AddLNode(addsub->lo1(), addsub->lo2())); + } else { + new_lo = _igvn.transform(new SubLNode(addsub->lo1(), addsub->lo2())); + } + + if (Node* lo = addsub->result_lo_or_null(); lo != nullptr) { + _igvn.replace_node(lo, new_lo); + } + + // uint64_t lo1, lo2, hi1, hi2 + // uint64_t sum_lo = lo1 + lo2 + // uint64_t sum_lo_overflow = sum_lo < lo2 ? 1 : 0 + // uint64_t sum_hi = hi1 + hi2 + sum_lo_overflow = hi1 + hi2 + (sum_lo < lo2 ? 1 : 0) + // uint64_t dif_lo = lo1 - lo2 + // uint64_t dif_lo_overflow = lo1 < lo2 ? 1 : 0 + // uint64_t dif_hi = hi1 - hi2 - dif_lo_overflow = hi1 - hi2 - (lo1 < lo2 ? 1 : 0) + if (Node* hi = addsub->result_hi_or_null(); hi != nullptr) { + Node* overflow_cmp = _igvn.transform(new CmpULNode(is_add ? new_lo : addsub->lo1(), addsub->lo2())); + Node* overflow_bol = _igvn.transform(new BoolNode(overflow_cmp, BoolTest::lt)); + Node* overflow_int = _igvn.transform(new CMoveLNode(overflow_bol, _igvn.longcon(0), _igvn.longcon(1), TypeLong::LONG)); + Node* hi2 = _igvn.transform(new AddLNode(addsub->hi2(), overflow_int)); + Node* new_hi; + if (is_add) { + new_hi = _igvn.transform(new AddLNode(addsub->hi1(), hi2)); + } else { + new_hi = _igvn.transform(new SubLNode(addsub->hi1(), hi2)); + } + _igvn.replace_node(hi, new_hi); + } + + _igvn.remove_dead_node(addsub, PhaseIterGVN::NodeOrigin::Graph); +} + // Perform refining of strip mined loop nodes in the macro nodes list. void PhaseMacroExpand::refine_strip_mined_loop_macro_nodes() { for (int i = C->macro_count(); i > 0; i--) { @@ -3279,7 +3325,9 @@ void PhaseMacroExpand::eliminate_macro_nodes(bool eliminate_locks) { n->is_OpaqueConstantBool() || n->is_OpaqueInitializedAssertionPredicate() || n->Opcode() == Op_MaxL || - n->Opcode() == Op_MinL, + n->Opcode() == Op_MinL || + n->Opcode() == Op_AddI128T || + n->Opcode() == Op_SubI128T, "unknown node type in macro list"); } if (C->failing()) { @@ -3470,6 +3518,10 @@ bool PhaseMacroExpand::expand_macro_nodes() { transform_later(call); break; } + case Op_AddI128T: + case Op_SubI128T: + expand_add_sub_i128t_node(static_cast(n)); + break; default: assert(false, "unknown node type in macro list"); } diff --git a/src/hotspot/share/opto/macro.hpp b/src/hotspot/share/opto/macro.hpp index dc59906623c6..c6fe13f4ef9c 100644 --- a/src/hotspot/share/opto/macro.hpp +++ b/src/hotspot/share/opto/macro.hpp @@ -33,6 +33,7 @@ class AllocateNode; class AllocateArrayNode; class CallNode; +class Int128TBinaryNode; class SubTypeCheckNode; class Node; class PhaseIterGVN; @@ -115,13 +116,13 @@ class PhaseMacroExpand : public Phase { Node* value_from_alloc(BasicType ft, const TypeOopPtr* adr_t, AllocateNode* alloc); Node* value_from_mem(Node* start, Node* ctl, BasicType ft, const Type* ftype, const TypeOopPtr* adr_t, AllocateNode* alloc); Node* value_from_mem_phi(Node* mem, BasicType ft, const Type* ftype, const TypeOopPtr* adr_t, AllocateNode* alloc, Node_Stack* value_phis, int level); - Node* inline_type_from_mem(ciInlineKlass* vk, const TypeAryPtr* elem_adr_type, int elem_idx, int offset_in_element, bool null_free, AllocateNode* alloc, SafePointNode* sfpt); + Node* value_type_from_mem(ciValueKlass* vk, const TypeAryPtr* elem_adr_type, int elem_idx, int offset_in_element, bool null_free, AllocateNode* alloc, SafePointNode* sfpt); bool eliminate_boxing_node(CallStaticJavaNode* call); bool eliminate_allocate_node(AllocateNode *alloc); void undo_previous_scalarizations(Unique_Node_List& safepoints_done, AllocateNode* alloc); bool scalar_replacement(AllocateNode* alloc, Unique_Node_List& safepoints); - void process_users_of_allocation(CallNode *alloc, bool inline_alloc = false); + void process_users_of_allocation(CallNode *alloc, bool value_type_alloc = false); void eliminate_gc_barrier(Node *p2x); void mark_eliminated_box(Node* box, Node* obj); @@ -220,6 +221,8 @@ class PhaseMacroExpand : public Phase { void expand_flatarraycheck_node(FlatArrayCheckNode* check); + void expand_add_sub_i128t_node(Int128TBinaryNode* addsub); + int replace_input(Node *use, Node *oldref, Node *newref); void migrate_outs(Node *old, Node *target); Node* opt_bits_test(Node* ctrl, Node* region, int edge, Node* word); diff --git a/src/hotspot/share/opto/macroArrayCopy.cpp b/src/hotspot/share/opto/macroArrayCopy.cpp index a39f9a00337a..f37f66a474eb 100644 --- a/src/hotspot/share/opto/macroArrayCopy.cpp +++ b/src/hotspot/share/opto/macroArrayCopy.cpp @@ -1299,9 +1299,9 @@ const TypePtr* PhaseMacroExpand::adjust_for_flat_array(const TypeAryPtr* top_des Node*& dest_offset, Node*& length, BasicType& dest_elem, Node*& dest_length) { #ifdef ASSERT - assert(top_dest->elem()->make_ptr()->is_instptr()->is_inlinetypeptr(), "must be concrete value klass"); + assert(top_dest->elem()->make_ptr()->is_instptr()->is_valueklassptr(), "must be concrete value klass"); BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - bool needs_barriers = top_dest->elem()->inline_klass()->contains_oops() && + bool needs_barriers = top_dest->elem()->value_klass()->contains_oops() && bs->array_copy_requires_gc_barriers(dest_length != nullptr, T_OBJECT, false, false, BarrierSetC2::Optimization); assert(!needs_barriers || StressReflectiveCode, "Flat arraycopy would require GC barriers"); #endif @@ -1493,15 +1493,15 @@ void PhaseMacroExpand::expand_arraycopy_node(ArrayCopyNode *ac) { if (src_elem != dest_elem || top_src->is_flat() != top_dest->is_flat() || dest_elem == T_VOID) { // 1) and 2) go_to_slow_path = true; - } else if ((top_src->is_flat() && !top_src->elem()->is_inlinetypeptr()) || - (top_dest->is_flat() && !top_dest->elem()->is_inlinetypeptr())) { + } else if ((top_src->is_flat() && !top_src->elem()->is_valueklassptr()) || + (top_dest->is_flat() && !top_dest->elem()->is_valueklassptr())) { // 3) go_to_slow_path = true; } else if (top_dest->is_flat() && bs->array_copy_requires_gc_barriers(alloc != nullptr, T_OBJECT, false, false, BarrierSetC2::Optimization) && - top_dest->elem()->inline_klass()->contains_oops()) { + top_dest->elem()->value_klass()->contains_oops()) { // 4) - assert(top_src->is_flat() && top_src->elem()->inline_klass()->contains_oops(), "must match"); + assert(top_src->is_flat() && top_src->elem()->value_klass()->contains_oops(), "must match"); go_to_slow_path = true; } diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index 1542d7c8d625..3465a1a6491d 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -166,7 +166,7 @@ void Matcher::verify_new_nodes_only(Node* xroot) { } #endif -// Array of RegMask, one per returned values (inline type instances can +// Array of RegMask, one per returned values (value type instances can // be returned as multiple return values, one per field) RegMask* Matcher::return_values_mask(const TypeFunc* tf) const { const TypeTuple* range = tf->range_cc(); @@ -223,6 +223,12 @@ void Matcher::match( ) { if (C->failing()) { return; } + + // Compute the old incoming SP (may be called FP) as + // OptoReg::stack0() + locks + in_preserve_stack_slots + pad2. + _old_SP = C->compute_old_SP(); + assert( is_even(_old_SP), "must be even" ); + assert(_return_addr_mask.is_empty(), "return address mask must be empty initially"); _return_addr_mask.insert(return_addr()); @@ -285,11 +291,6 @@ void Matcher::match( ) { // Do some initial frame layout. - // Compute the old incoming SP (may be called FP) as - // OptoReg::stack0() + locks + in_preserve_stack_slots + pad2. - _old_SP = C->compute_old_SP(); - assert( is_even(_old_SP), "must be even" ); - // Compute highest incoming stack argument as // _old_SP + out_preserve_stack_slots + incoming argument size. _in_arg_limit = OptoReg::add(_old_SP, C->out_preserve_stack_slots()); diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 274b4d3e1106..3c361d3f210a 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -24,8 +24,8 @@ */ #include "ci/ciFlatArrayKlass.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciInstanceKlass.hpp" +#include "ci/ciValueKlass.hpp" #include "classfile/javaClasses.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmIntrinsics.hpp" @@ -44,7 +44,6 @@ #include "opto/compile.hpp" #include "opto/connode.hpp" #include "opto/convertnode.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/loopnode.hpp" #include "opto/machnode.hpp" #include "opto/matcher.hpp" @@ -58,6 +57,7 @@ #include "opto/regmask.hpp" #include "opto/rootnode.hpp" #include "opto/traceMergeStoresTag.hpp" +#include "opto/valuetypenode.hpp" #include "opto/vectornode.hpp" #include "runtime/arguments.hpp" #include "utilities/align.hpp" @@ -243,7 +243,7 @@ Node* MemNode::optimize_simple_memory_chain(Node* mchain, const TypeOopPtr* t_oo if (phase->is_IterGVN() && phase->C->allow_macro_nodes() && load != nullptr && load->is_Load() && !load->as_Load()->is_mismatched_access()) { is_strict_final_load = t_oop->is_ptr_to_strict_final_field(); #ifdef ASSERT - if ((t_oop->is_inlinetypeptr() && t_oop->inline_klass()->contains_field_offset(t_oop->offset())) || t_oop->is_ptr_to_boxed_value()) { + if ((t_oop->is_valueklassptr() && t_oop->value_klass()->contains_field_offset(t_oop->offset())) || t_oop->is_ptr_to_boxed_value()) { assert(is_strict_final_load, "sanity check for basic cases"); } #endif // ASSERT @@ -1226,7 +1226,7 @@ static bool skip_through_membars(Compile::AliasType* atp, const TypeInstPtr* tp, (tp != nullptr) && (tp->isa_aryptr() != nullptr) && tp->isa_aryptr()->is_stable(); - return (eliminate_boxing && non_volatile) || is_stable_ary || tp->is_inlinetypeptr(); + return (eliminate_boxing && non_volatile) || is_stable_ary || tp->is_valueklassptr(); } return false; @@ -1306,13 +1306,13 @@ Node* LoadNode::can_see_arraycopy_value(Node* st, PhaseGVN* phase) const { return nullptr; } -static Node* see_through_inline_type(PhaseValues* phase, const LoadNode* load, Node* base, int offset) { +static Node* see_through_value_type(PhaseValues* phase, const LoadNode* load, Node* base, int offset) { if (load->is_mismatched_access() || base == nullptr) { return nullptr; } - InlineTypeNode* vt = base->isa_InlineType(); - if (vt == nullptr || offset < vt->type()->inline_klass()->payload_offset()) { + ValueTypeNode* vt = base->isa_ValueType(); + if (vt == nullptr || offset < vt->type()->value_klass()->payload_offset()) { return nullptr; } @@ -1332,8 +1332,8 @@ Node* LoadNode::can_see_stored_value_through_membars(Node* st, PhaseValues* phas Node* ld_adr = in(MemNode::Address); intptr_t ld_off = 0; Node* ld_base = AddPNode::Ideal_base_and_offset(ld_adr, phase, ld_off); - // Try to see through an InlineTypeNode - Node* value = see_through_inline_type(phase, this, ld_base, ld_off); + // Try to see through an ValueTypeNode + Node* value = see_through_value_type(phase, this, ld_base, ld_off); if (value != nullptr) { return value; } @@ -1494,16 +1494,16 @@ Node* MemNode::can_see_stored_value(Node* st, PhaseValues* phase) const { if (init_value->is_EncodeP()) { init_value = init_value->in(1); } - if (!init_value->is_InlineType() || ld_adr_type->field_offset() == Type::Offset::bottom) { + if (!init_value->is_ValueType() || ld_adr_type->field_offset() == Type::Offset::bottom) { return nullptr; } - ciInlineKlass* vk = phase->type(init_value)->inline_klass(); + ciValueKlass* vk = phase->type(init_value)->value_klass(); int field_offset_in_payload = ld_adr_type->field_offset().get(); if (field_offset_in_payload == vk->null_marker_offset_in_payload()) { - return init_value->as_InlineType()->get_null_marker(); + return init_value->as_ValueType()->get_null_marker(); } else { - return init_value->as_InlineType()->field_value_by_offset(field_offset_in_payload + vk->payload_offset(), true); + return init_value->as_ValueType()->field_value_by_offset(field_offset_in_payload + vk->payload_offset(), true); } } assert(ld_alloc->in(AllocateNode::RawInitValue) == nullptr, "init value may not be null"); @@ -2196,7 +2196,7 @@ Node* LoadNode::Ideal_load_common(PhaseGVN* phase, bool can_reshape) { // Check for useless control edge in some common special cases if (in(MemNode::Control) != nullptr // TODO 8350865 Can we re-enable this? - && !(phase->type(address)->is_inlinetypeptr() && is_mismatched_access()) + && !(phase->type(address)->is_valueklassptr() && is_mismatched_access()) && can_remove_control() && phase->type(base)->higher_equal(TypePtr::NOTNULL) && all_controls_dominate(base, phase->C->start(), phase)) { @@ -2453,8 +2453,8 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { int offset = tinst->offset(); if (ik == phase->C->env()->Class_klass()) { ciType* t = tinst->java_mirror_type(); - if (t != nullptr && t->is_inlinetype() && offset == t->as_inline_klass()->field_map_offset()) { - ciConstant map = t->as_inline_klass()->get_field_map(); + if (t != nullptr && t->is_value_klass() && offset == t->as_value_klass()->field_map_offset()) { + ciConstant map = t->as_value_klass()->get_field_map(); bool is_narrow_oop = (bt == T_NARROWOOP); return Type::make_from_constant(map, true, 1, is_narrow_oop); } @@ -2511,8 +2511,8 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { assert(Opcode() == Op_LoadI, "must load an int from _super_check_offset"); return TypeInt::make(klass->super_check_offset()); } - if (klass->is_inlinetype() && tkls->offset() == in_bytes(InstanceKlass::acmp_maps_offset_offset())) { - return TypeInt::make(klass->as_inline_klass()->field_map_offset()); + if (klass->is_value_klass() && tkls->offset() == in_bytes(InstanceKlass::acmp_maps_offset_offset())) { + return TypeInt::make(klass->as_value_klass()->field_map_offset()); } if (klass->is_obj_array_klass() && tkls->offset() == in_bytes(ObjArrayKlass::next_refined_array_klass_offset())) { // Fold loads from LibraryCallKit::load_default_refined_array_klass @@ -2622,7 +2622,7 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { Node* alloc = is_new_object_mark_load(); if (alloc != nullptr) { if (Arguments::is_valhalla_enabled()) { - // The mark word may contain property bits (inline, flat, null-free) + // The mark word may contain property bits (value, flat, null-free) Node* klass_node = alloc->in(AllocateNode::KlassNode); const TypeKlassPtr* tkls = phase->type(klass_node)->isa_klassptr(); if (tkls != nullptr && tkls->is_loaded() && tkls->klass_is_exact()) { diff --git a/src/hotspot/share/opto/mulnode.cpp b/src/hotspot/share/opto/mulnode.cpp index 305731f3d0c7..93b73c17cd40 100644 --- a/src/hotspot/share/opto/mulnode.cpp +++ b/src/hotspot/share/opto/mulnode.cpp @@ -872,11 +872,11 @@ Node *AndLNode::Ideal(PhaseGVN *phase, bool can_reshape) { if (in1->is_Load() && phase->type(in1)->isa_long()) { const TypePtr* adr_t = phase->type(in1->in(MemNode::Address))->isa_ptr(); if (adr_t != nullptr && adr_t->offset() == oopDesc::mark_offset_in_bytes()) { - if (mask == markWord::inline_type_pattern) { - if (adr_t->is_inlinetypeptr()) { + if (mask == markWord::value_type_pattern) { + if (adr_t->is_valueklassptr()) { set_req_X(1, in(2), phase); return this; - } else if (!adr_t->can_be_inline_type()) { + } else if (!adr_t->can_be_value_type()) { set_req_X(1, phase->longcon(0), phase); return this; } diff --git a/src/hotspot/share/opto/multnode.cpp b/src/hotspot/share/opto/multnode.cpp index 7223a08e8761..27a3a3400cdc 100644 --- a/src/hotspot/share/opto/multnode.cpp +++ b/src/hotspot/share/opto/multnode.cpp @@ -24,7 +24,6 @@ #include "opto/callnode.hpp" #include "opto/cfgnode.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/matcher.hpp" #include "opto/mathexactnode.hpp" #include "opto/multnode.hpp" @@ -32,6 +31,7 @@ #include "opto/phaseX.hpp" #include "opto/regmask.hpp" #include "opto/type.hpp" +#include "opto/valuetypenode.hpp" #include "utilities/vmError.hpp" //============================================================================= @@ -134,7 +134,7 @@ const Type* ProjNode::proj_type(const Type* t) const { CallStaticJavaNode* call = in(0)->isa_CallStaticJava(); if (call != nullptr && call->is_boxing_method()) { // The result of autoboxing is always non-null on normal path. - if (call->tf()->returns_inline_type_as_fields()) { + if (call->tf()->returns_value_type_as_fields()) { // Last returned value is the null marker if (_con == call->tf()->range_cc()->cnt() - 1) { t = TypeInt::ONE; @@ -214,9 +214,9 @@ Node* ProjNode::Identity(PhaseGVN* phase) { CallStaticJavaNode* call = in(0)->isa_CallStaticJava(); if (call != nullptr) { - if (call->is_boxing_method() && call->method()->return_type()->is_inlinetype()) { + if (call->is_boxing_method() && call->method()->return_type()->is_value_klass()) { // Boxing (for example, via Integer.valueOf(int)) - if (call->tf()->returns_inline_type_as_fields()) { + if (call->tf()->returns_value_type_as_fields()) { if (_con == TypeFunc::Parms) { // Oop projection: Keep it to avoid re-buffering. If unused, // it will go away and enable removal of the boxing call. @@ -234,9 +234,9 @@ Node* ProjNode::Identity(PhaseGVN* phase) { return call->in(TypeFunc::Parms + 1); } else { Node* arg = call->in(TypeFunc::Parms); - if (arg->is_InlineType()) { + if (arg->is_ValueType()) { assert(!phase->type(arg)->maybe_null(), "missing receiver null check?"); - return arg->as_InlineType()->field_value(0); + return arg->as_ValueType()->field_value(0); } } } diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index 7670e6ade89a..d92b9f060626 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -33,7 +33,6 @@ #include "opto/castnode.hpp" #include "opto/cfgnode.hpp" #include "opto/connode.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/loopnode.hpp" #include "opto/machnode.hpp" #include "opto/matcher.hpp" @@ -43,6 +42,7 @@ #include "opto/regmask.hpp" #include "opto/rootnode.hpp" #include "opto/type.hpp" +#include "opto/valuetypenode.hpp" #include "utilities/copy.hpp" #include "utilities/macros.hpp" #include "utilities/powerOfTwo.hpp" @@ -573,8 +573,8 @@ Node *Node::clone() const { n->as_SafePoint()->clone_jvms(C); n->as_SafePoint()->clone_replaced_nodes(); } - if (n->is_InlineType()) { - C->add_inline_type(n); + if (n->is_ValueType()) { + C->add_value_type(n); } if (n->is_LoadFlat() || n->is_StoreFlat()) { C->add_flat_access(n); @@ -642,8 +642,8 @@ void Node::destruct(PhaseValues* phase) { if (for_post_loop_opts_igvn()) { compile->remove_from_post_loop_opts_igvn(this); } - if (is_InlineType()) { - compile->remove_inline_type(this); + if (is_ValueType()) { + compile->remove_value_type(this); } if (for_merge_stores_igvn()) { compile->remove_from_merge_stores_igvn(this); @@ -1255,6 +1255,11 @@ bool Node::has_special_unique_user() const { } }; +bool Node::should_process_when_disconnect_output(Node* output) const { + return (is_Phi() && as_Phi()->is_dead_phi()) || + output->is_data_proj_of_pure_function(this); +} + //--------------------------find_exact_control--------------------------------- // Skip Proj and CatchProj nodes chains. Check for Null and Top. Node* Node::find_exact_control(Node* ctrl) { @@ -1487,7 +1492,7 @@ static void kill_dead_code( Node *dead, PhaseIterGVN *igvn ) { // The restriction (outcnt() <= 2) is the same as in set_req_X() // and remove_globally_dead_node(). igvn->add_users_to_worklist( n ); - } else if (dead->is_data_proj_of_pure_function(n)) { + } else if (n->should_process_when_disconnect_output(dead)) { igvn->_worklist.push(n); } } diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index be3f5b604601..ef9646ac1289 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -188,7 +188,7 @@ class SubTypeCheckNode; class Type; class TypeNode; class UnlockNode; -class InlineTypeNode; +class ValueTypeNode; class LoadFlatNode; class StoreFlatNode; class VectorNode; @@ -774,7 +774,7 @@ class Node { DEFINE_CLASS_ID(NegV, Vector, 8) DEFINE_CLASS_ID(SaturatingVector, Vector, 9) DEFINE_CLASS_ID(MulVL, Vector, 10) - DEFINE_CLASS_ID(InlineType, Type, 8) + DEFINE_CLASS_ID(ValueType, Type, 8) DEFINE_CLASS_ID(Con, Type, 9) DEFINE_CLASS_ID(ConI, Con, 0) DEFINE_CLASS_ID(SafePointScalarMerge, Type, 10) @@ -1047,7 +1047,7 @@ class Node { DEFINE_CLASS_QUERY(Sub) DEFINE_CLASS_QUERY(SubTypeCheck) DEFINE_CLASS_QUERY(Type) - DEFINE_CLASS_QUERY(InlineType) + DEFINE_CLASS_QUERY(ValueType) DEFINE_CLASS_QUERY(LoadFlat) DEFINE_CLASS_QUERY(StoreFlat) DEFINE_CLASS_QUERY(Vector) @@ -1293,6 +1293,14 @@ class Node { // for the transformations to happen. bool has_special_unique_user() const; + // Some nodes can be processed when one of its outputs is disconnected + bool should_process_when_disconnect_output(Node* output) const; + +private: + bool is_data_proj_of_pure_function(const Node* maybe_pure_function) const; + +public: + // Skip Proj and CatchProj nodes chains. Check for Null and Top. Node* find_exact_control(Node* ctrl); @@ -1456,8 +1464,6 @@ class Node { bool is_div_or_mod(BasicType bt) const; - bool is_data_proj_of_pure_function(const Node* maybe_pure_function) const; - //----------------- Printing, etc #ifndef PRODUCT public: diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index 460c0c466779..aeb775836131 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -285,10 +285,10 @@ void PhaseOutput::Output() { } else { if (C->method()) { if (C->method()->has_scalarized_args()) { - // Add entry point to unpack all inline type arguments + // Add entry point to unpack all value type arguments C->cfg()->insert(broot, 0, new MachVEPNode(&verified_entry, /* verified */ true, /* receiver_only */ false)); if (!C->method()->is_static()) { - // Add verified/unverified entry points to only unpack inline type receiver at interface calls + // Add verified/unverified entry points to only unpack value type receiver at interface calls C->cfg()->insert(broot, 0, new MachVEPNode(&verified_entry, /* verified */ false, /* receiver_only */ false)); C->cfg()->insert(broot, 0, new MachVEPNode(&verified_entry, /* verified */ true, /* receiver_only */ true)); C->cfg()->insert(broot, 0, new MachVEPNode(&verified_entry, /* verified */ false, /* receiver_only */ true)); @@ -338,27 +338,27 @@ void PhaseOutput::Output() { shorten_branches(blk_starts); if (!C->is_osr_compilation() && C->has_scalarized_args()) { - // Compute the offsets of the entry points required by the inline type calling convention + // Compute the offsets of the entry points required by the value type calling convention if (!C->method()->is_static()) { // We have entries at the beginning of the method, implemented by the first 4 nodes. // Entry (unverified) @ offset 0 - // Verified_Inline_Entry_RO - // Inline_Entry (unverified) - // Verified_Inline_Entry + // Verified_Value_Entry_RO + // Value_Entry (unverified) + // Verified_Value_Entry uint offset = 0; _code_offsets.set_value(CodeOffsets::Entry, offset); offset += ((MachVEPNode*)broot->get_node(0))->size(C->regalloc()); - _code_offsets.set_value(CodeOffsets::Verified_Inline_Entry_RO, offset); + _code_offsets.set_value(CodeOffsets::Verified_Value_Entry_RO, offset); offset += ((MachVEPNode*)broot->get_node(1))->size(C->regalloc()); - _code_offsets.set_value(CodeOffsets::Inline_Entry, offset); + _code_offsets.set_value(CodeOffsets::Value_Entry, offset); offset += ((MachVEPNode*)broot->get_node(2))->size(C->regalloc()); - _code_offsets.set_value(CodeOffsets::Verified_Inline_Entry, offset); + _code_offsets.set_value(CodeOffsets::Verified_Value_Entry, offset); } else { _code_offsets.set_value(CodeOffsets::Entry, CodeOffsets::no_such_entry_point); // will be patched later - _code_offsets.set_value(CodeOffsets::Verified_Inline_Entry, 0); + _code_offsets.set_value(CodeOffsets::Verified_Value_Entry, 0); } } @@ -749,7 +749,7 @@ void PhaseOutput::set_sv_for_object_node(GrowableArray *objs, static jint array_description_value(const TypeAryPtr* ary_type) { ciArrayKlass* array_klass = ary_type->exact_klass()->as_array_klass(); - const bool is_element_inline = array_klass->element_klass()->is_inlinetype(); + const bool is_element_inline = array_klass->element_klass()->is_value_klass(); ArrayProperties properties = ArrayProperties::Default() .with_null_restricted(is_element_inline && array_klass->is_elem_null_free()) .with_non_atomic(is_element_inline && !array_klass->is_elem_atomic()); @@ -793,10 +793,10 @@ void PhaseOutput::FillLocArray( int idx, MachSafePointNode* sfpt, Node *local, assert(cik->is_instance_klass() || cik->is_array_klass(), "Not supported allocation."); uint first_ind = spobj->first_index(sfpt->jvms()); - // Nullable, scalarized inline types have a null_marker input + // Nullable, scalarized value types have a null_marker input // that needs to be checked before using the field values. ScopeValue* properties = nullptr; - if (cik->is_inlinetype()) { + if (cik->is_value_klass()) { Node* null_marker_node = sfpt->in(first_ind++); assert(null_marker_node != nullptr, "null_marker node not found"); if (!null_marker_node->is_top()) { @@ -1151,7 +1151,7 @@ void PhaseOutput::Process_OopMap_Node(MachNode *mach, int current_offset) { ciKlass* cik = t->is_oopptr()->exact_klass(); assert(cik->is_instance_klass() || cik->is_array_klass(), "Not supported allocation."); - assert(!cik->is_inlinetype(), "Synchronization on value object?"); + assert(!cik->is_value_klass(), "Synchronization on value object?"); ScopeValue* properties = nullptr; if (cik->is_array_klass() && !cik->is_type_array_klass()) { properties = new ConstantIntValue(array_description_value(t->is_aryptr())); @@ -3191,7 +3191,7 @@ void PhaseOutput::init_scratch_buffer_blob(int const_size) { _scratch_const_size = const_size; int size = C2Compiler::initial_code_buffer_size(const_size); if (C->has_scalarized_args()) { - // Inline type entry points (MachVEPNodes) require lots of space when + // Value type entry points (MachVEPNodes) require lots of space when // unpacking fields from buffered arguments. Increase the scratch buffer // for field moves, GC barriers and oop verification accordingly. const int move_size = 32; @@ -3205,20 +3205,20 @@ void PhaseOutput::init_scratch_buffer_blob(int const_size) { barrier_size += 400; } ciMethod* method = C->method(); - auto add_inline_arg_size = [&](ciInlineKlass* vk) { - size += vk->inline_arg_length() * move_size; + auto add_value_arg_size = [&](ciValueKlass* vk) { + size += vk->value_arg_length() * move_size; size += vk->oop_count() * barrier_size; }; int arg_num = 0; if (!method->is_static()) { if (method->is_scalarized_arg(arg_num)) { - add_inline_arg_size(method->holder()->as_inline_klass()); + add_value_arg_size(method->holder()->as_value_klass()); } arg_num++; } for (ciSignatureStream str(method->signature()); !str.at_return_type(); str.next()) { if (method->is_scalarized_arg(arg_num)) { - add_inline_arg_size(str.type()->as_inline_klass()); + add_value_arg_size(str.type()->as_value_klass()); } arg_num++; } @@ -3338,11 +3338,11 @@ void PhaseOutput::install_code(ciMethod* target, _code_offsets.set_value(CodeOffsets::OSR_Entry, _first_block_size); } else { _code_offsets.set_value(CodeOffsets::Verified_Entry, _first_block_size); - if (_code_offsets.value(CodeOffsets::Verified_Inline_Entry) == CodeOffsets::no_such_entry_point) { - _code_offsets.set_value(CodeOffsets::Verified_Inline_Entry, _first_block_size); + if (_code_offsets.value(CodeOffsets::Verified_Value_Entry) == CodeOffsets::no_such_entry_point) { + _code_offsets.set_value(CodeOffsets::Verified_Value_Entry, _first_block_size); } - if (_code_offsets.value(CodeOffsets::Verified_Inline_Entry_RO) == CodeOffsets::no_such_entry_point) { - _code_offsets.set_value(CodeOffsets::Verified_Inline_Entry_RO, _first_block_size); + if (_code_offsets.value(CodeOffsets::Verified_Value_Entry_RO) == CodeOffsets::no_such_entry_point) { + _code_offsets.set_value(CodeOffsets::Verified_Value_Entry_RO, _first_block_size); } if (_code_offsets.value(CodeOffsets::Entry) == CodeOffsets::no_such_entry_point) { _code_offsets.set_value(CodeOffsets::Entry, _first_block_size); diff --git a/src/hotspot/share/opto/parse.hpp b/src/hotspot/share/opto/parse.hpp index 2f0f8558d84e..283ee1cb300e 100644 --- a/src/hotspot/share/opto/parse.hpp +++ b/src/hotspot/share/opto/parse.hpp @@ -501,7 +501,7 @@ class Parse : public GraphKit { Node* prepare_array_addressing(BasicType type, int vals, const Type*& elemtype); Node* get_ptr_to_array_element(Node* array, Node* idx, BasicType elembt, const TypeInt* sizetype, Node* control); bool needs_range_check(const TypeInt* size_type, const Node* index) const; - Node* create_speculative_inline_type_array_checks(Node* array, const TypeAryPtr* array_type, const Type*& element_type); + Node* create_speculative_value_type_array_checks(Node* array, const TypeAryPtr* array_type, const Type*& element_type); Node* cast_to_speculative_array_type(Node* array, const TypeAryPtr*& array_type, const Type*& element_type); Node* cast_to_profiled_array_type(Node* const array); Node* speculate_non_null_free_array(Node* array, const TypeAryPtr*& array_type); @@ -556,7 +556,7 @@ class Parse : public GraphKit { void do_get_xxx(Node* obj, ciField* field); void do_put_xxx(Node* obj, ciField* field, bool is_field); - ciType* improve_abstract_inline_type_klass(ciType* field_klass); + ciType* improve_abstract_value_type_klass(ciType* field_klass); // implementation of object creation bytecodes void do_new(); diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp index 2d1e0550fb69..4557f1e1702a 100644 --- a/src/hotspot/share/opto/parse1.cpp +++ b/src/hotspot/share/opto/parse1.cpp @@ -34,7 +34,6 @@ #include "opto/castnode.hpp" #include "opto/convertnode.hpp" #include "opto/idealGraphPrinter.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/locknode.hpp" #include "opto/memnode.hpp" #include "opto/opaquenode.hpp" @@ -42,6 +41,7 @@ #include "opto/rootnode.hpp" #include "opto/runtime.hpp" #include "opto/type.hpp" +#include "opto/valuetypenode.hpp" #include "runtime/arguments.hpp" #include "runtime/handles.inline.hpp" #include "runtime/safepointMechanism.hpp" @@ -180,7 +180,7 @@ Node* Parse::check_interpreter_type(Node* l, ciType* ci_type, SafePointNode* &ba // TypeFlow asserted a specific object type. Value must have that type. assert(_gvn.type(l) == TypePtr::NULL_PTR || _gvn.type(l)->isa_oopptr(), "must be an oop"); if (ci_type->is_null_free()) { - // Check inline types for null here to prevent checkcast from adding an + // Check value types for null here to prevent checkcast from adding an // exception state before the bytecode entry (use 'bad_type_ctrl' instead). Node* bad_type_ctrl = nullptr; l = null_check_oop(l, &bad_type_ctrl); @@ -260,14 +260,14 @@ void Parse::load_interpreter_state(Node* osr_buf) { Node* box = _gvn.transform(osr_box); - // Displaced headers and locked objects are interleaved in the + // Object monitor cache and locked objects are interleaved in the // temp OSR buffer. We only copy the locked objects out here. // Fetch the locked object from the OSR temp buffer and copy to our fastlock node. Node* lock_object = fetch_interpreter_state(index*2, Type::get_const_basic_type(T_OBJECT), monitors_addr); - // Try and copy the displaced header to the BoxNode - Node* displaced_hdr = fetch_interpreter_state((index*2) + 1, Type::get_const_basic_type(T_ADDRESS), monitors_addr); + // Try and copy the object monitor cache to the BoxNode + Node* object_monitor_cache = fetch_interpreter_state((index*2) + 1, Type::get_const_basic_type(T_ADDRESS), monitors_addr); - store_to_memory(control(), box, displaced_hdr, T_ADDRESS, MemNode::unordered); + store_to_memory(control(), box, object_monitor_cache, T_ADDRESS, MemNode::unordered); // Build a bogus FastLockNode (no code will be generated) and push the // monitor into our debug info. @@ -393,7 +393,7 @@ void Parse::load_interpreter_state(Node* osr_buf) { // Keep all oop locals alive until the method returns as if there are // reachability fences for them at the end of the method. Node* loc = local(index); - if (!loc->is_InlineType() && loc->bottom_type() != TypePtr::NULL_PTR) { + if (!loc->is_ValueType() && loc->bottom_type() != TypePtr::NULL_PTR) { assert(loc->bottom_type()->isa_oopptr() != nullptr, "%s", Type::str(loc->bottom_type())); _stress_rf_hook->add_req(loc); } @@ -410,7 +410,7 @@ void Parse::load_interpreter_state(Node* osr_buf) { // Keep all oops on stack alive until the method returns as if there are // reachability fences for them at the end of the method. Node* stk = stack(index); - if (!stk->is_InlineType() && stk->bottom_type() != TypePtr::NULL_PTR) { + if (!stk->is_ValueType() && stk->bottom_type() != TypePtr::NULL_PTR) { assert(stk->bottom_type()->isa_oopptr() != nullptr, "%s", Type::str(stk->bottom_type())); _stress_rf_hook->add_req(stk); } @@ -901,15 +901,15 @@ JVMState* Compile::build_start_state(StartNode* start, const TypeFunc* tf) { for (uint j = 0; i < (uint)arg_size; i++) { const Type* t = tf->domain_sig()->field_at(i); Node* parm = nullptr; - if (t->is_inlinetypeptr() && method()->is_scalarized_arg(arg_num)) { - // Inline type arguments are not passed by reference: we get an argument per - // field of the inline type. Build InlineTypeNodes from the inline type arguments. + if (t->is_valueklassptr() && method()->is_scalarized_arg(arg_num)) { + // Value type arguments are not passed by reference: we get an argument per + // field of the value type. Build ValueTypeNodes from the value type arguments. GraphKit kit(jvms, &gvn); kit.set_control(map->control()); Node* old_mem = map->memory(); - // Use immutable memory for inline type loads and restore it below + // Use immutable memory for value type loads and restore it below kit.set_all_memory(C->immutable_memory()); - parm = InlineTypeNode::make_from_multi(&kit, start, t->inline_klass(), j, /* in= */ true, /* null_free= */ !t->maybe_null()); + parm = ValueTypeNode::make_from_multi(&kit, start, t->value_klass(), j, /* in= */ true, /* null_free= */ !t->maybe_null()); assert(map == kit.map(), "broken if map changes"); map->set_control(kit.control()); map->set_memory(old_mem); @@ -959,17 +959,17 @@ void Compile::return_values(JVMState* jvms) { kit.inc_sp(-ret_size); // pop the return value(s) kit.sync_jvms(); Node* res = kit.argument(0); - if (tf()->returns_inline_type_as_fields()) { - // Multiple return values (inline type fields): add as many edges + if (tf()->returns_value_type_as_fields()) { + // Multiple return values (value type fields): add as many edges // to the Return node as returned values. - InlineTypeNode* vt = res->as_InlineType(); + ValueTypeNode* vt = res->as_ValueType(); ret->add_req_batch(nullptr, tf()->range_cc()->cnt() - TypeFunc::Parms); if (vt->is_allocated(&kit.gvn()) && !StressCallingConvention) { ret->init_req(TypeFunc::Parms, vt); } else { // Return the tagged klass pointer to signal scalarization to the caller Node* tagged_klass = vt->tagged_klass(kit.gvn()); - // Return null if the inline type is null (null marker field is not set) + // Return null if the value type is null (null marker field is not set) Node* conv = kit.gvn().transform(new ConvI2LNode(vt->get_null_marker())); Node* shl = kit.gvn().transform(new LShiftLNode(conv, kit.intcon(63))); Node* shr = kit.gvn().transform(new RShiftLNode(shl, kit.intcon(63))); @@ -1346,7 +1346,7 @@ void Parse::do_method_entry() { int max_locals = jvms()->loc_size(); for (int idx = 0; idx < max_locals; idx++) { Node* loc = local(idx); - if (!loc->is_InlineType() && + if (!loc->is_ValueType() && loc->bottom_type()->isa_oopptr() != nullptr && !is_auto_boxed_primitive(loc)) { // ignore auto-boxed primitives _stress_rf_hook->add_req(loc); @@ -1399,7 +1399,7 @@ void Parse::do_method_entry() { lock_obj = makecon(t_lock); } else { // Else pass the "this" pointer, lock_obj = local(0); // which is Parm0 from StartNode - assert(!_gvn.type(lock_obj)->make_oopptr()->can_be_inline_type(), "can't be an inline type"); + assert(!_gvn.type(lock_obj)->make_oopptr()->can_be_value_type(), "can't be a value type"); } // Clear out dead values from the debug info. kill_dead_locals(); @@ -1418,12 +1418,12 @@ void Parse::do_method_entry() { for (int i = 0; i < arg_size; i++) { Node* parm = local(i); const Type* t = _gvn.type(parm); - if (t->is_inlinetypeptr()) { + if (t->is_valueklassptr()) { // If the parameter is a value object, try to scalarize it if we know that it is unrestricted (not early larval) // Parameters are non-larval except the receiver of a constructor, which must be an early larval object. if (!(i == 0 && method()->receiver_maybe_larval())) { - // Create InlineTypeNode from the oop and replace the parameter - Node* vt = InlineTypeNode::make_from_oop(this, parm, t->inline_klass()); + // Create ValueTypeNode from the oop and replace the parameter + Node* vt = ValueTypeNode::make_from_oop(this, parm, t->value_klass()); replace_in_map(parm, vt); } } else if (UseTypeSpeculation && (i == (arg_size - 1)) && depth() == 1 && method()->is_varargs() && t->isa_aryptr()) { @@ -1884,7 +1884,7 @@ void Parse::merge_common(Parse::Block* target, int pnum) { assert(sp() == target->start_sp(), ""); clean_stack(sp()); - // Check for merge conflicts involving inline types + // Check for merge conflicts involving value types JVMState* old_jvms = map()->jvms(); int old_bci = bci(); JVMState* tmp_jvms = old_jvms->clone_shallow(C); @@ -1911,21 +1911,21 @@ void Parse::merge_common(Parse::Block* target, int pnum) { ct = target->flow()->stack_type_at(stk_idx); } if (t != nullptr && t != Type::BOTTOM) { - // An object can appear in the JVMS as either an oop or an InlineTypeNode. If the merge is - // an InlineTypeNode, we need all the merge inputs to be InlineTypeNodes. Else, if the + // An object can appear in the JVMS as either an oop or an ValueTypeNode. If the merge is + // an ValueTypeNode, we need all the merge inputs to be ValueTypeNodes. Else, if the // merge is an oop, each merge input needs to be either an oop or an buffered - // InlineTypeNode. - if (!t->is_inlinetypeptr()) { - // The merge cannot be an InlineTypeNode, ensure the input is buffered if it is an - // InlineTypeNode - if (n->is_InlineType()) { - map()->set_req(j, n->as_InlineType()->buffer(this)); + // ValueTypeNode. + if (!t->is_valueklassptr()) { + // The merge cannot be an ValueTypeNode, ensure the input is buffered if it is an + // ValueTypeNode + if (n->is_ValueType()) { + map()->set_req(j, n->as_ValueType()->buffer(this)); } } else { // Scalarize the value object if it is not larval - if (!n->is_InlineType() && !ct->is_early_larval()) { + if (!n->is_ValueType() && !ct->is_early_larval()) { assert(_gvn.type(n) == TypePtr::NULL_PTR, "must be a null constant"); - map()->set_req(j, InlineTypeNode::make_null(_gvn, t->inline_klass())); + map()->set_req(j, ValueTypeNode::make_null(_gvn, t->value_klass())); } } } @@ -2031,7 +2031,7 @@ void Parse::merge_common(Parse::Block* target, int pnum) { Node* phi; if (m->is_Phi() && m->as_Phi()->region() == r) { phi = m; - } else if (m->is_InlineType() && m->as_InlineType()->has_phi_inputs(r)) { + } else if (m->is_ValueType() && m->as_ValueType()->has_phi_inputs(r)) { phi = m; } else { phi = nullptr; @@ -2082,18 +2082,18 @@ void Parse::merge_common(Parse::Block* target, int pnum) { // - the corresponding control edges is top (a dead incoming path) // It is a bug if we create a phi which sees a garbage value on a live path. - // Merging two inline types? - if (phi != nullptr && phi->is_InlineType()) { + // Merging two value types? + if (phi != nullptr && phi->is_ValueType()) { // Reload current state because it may have been updated by ensure_phi assert(phi == map()->in(j), "unexpected value in map"); - assert(phi->as_InlineType()->has_phi_inputs(r), ""); - InlineTypeNode* vtm = phi->as_InlineType(); // Current inline type - InlineTypeNode* vtn = n->as_InlineType(); // Incoming inline type - assert(vtm == phi, "Inline type should have Phi input"); + assert(phi->as_ValueType()->has_phi_inputs(r), ""); + ValueTypeNode* vtm = phi->as_ValueType(); // Current value type + ValueTypeNode* vtn = n->as_ValueType(); // Incoming value type + assert(vtm == phi, "Value type should have Phi input"); #ifdef ASSERT if (TraceOptoParse) { - tty->print_cr("\nMerging inline types"); + tty->print_cr("\nMerging value types"); tty->print_cr("Current:"); vtm->dump(2); tty->print_cr("Incoming:"); @@ -2280,8 +2280,8 @@ int Parse::Block::add_new_path() { if (n->is_Phi() && n->as_Phi()->region() == r) { assert(n->req() == pnum, "must be same size as region"); n->add_req(nullptr); - } else if (n->is_InlineType() && n->as_InlineType()->has_phi_inputs(r)) { - n->as_InlineType()->add_new_path(r); + } else if (n->is_ValueType() && n->as_ValueType()->has_phi_inputs(r)) { + n->as_ValueType()->add_new_path(r); } } } @@ -2319,7 +2319,7 @@ Node* Parse::ensure_phi(int idx, bool nocreate) { if (o->is_Phi() && o->as_Phi()->region() == region) { return o->as_Phi(); } - InlineTypeNode* vt = o->isa_InlineType(); + ValueTypeNode* vt = o->isa_ValueType(); if (vt != nullptr && vt->has_phi_inputs(region)) { return vt; } @@ -2356,10 +2356,10 @@ Node* Parse::ensure_phi(int idx, bool nocreate) { return nullptr; } - if (vt != nullptr && t->is_inlinetypeptr()) { - // Inline types are merged by merging their field values. - // Create a cloned InlineTypeNode with phi inputs that - // represents the merged inline type and update the map. + if (vt != nullptr && t->is_valueklassptr()) { + // Value types are merged by merging their field values. + // Create a cloned ValueTypeNode with phi inputs that + // represents the merged value type and update the map. vt = vt->clone_with_phis(&_gvn, region); map->set_req(idx, vt); return vt; @@ -2512,28 +2512,28 @@ void Parse::return_current(Node* value) { if (value != nullptr) { Node* phi = _exits.argument(0); const Type* return_type = phi->bottom_type(); - if ((tf()->returns_inline_type_as_fields() || (_caller->has_method() && !Compile::current()->inlining_incrementally())) && - return_type->is_inlinetypeptr()) { - // Inline type is returned as fields, make sure it is scalarized - if (!value->is_InlineType()) { - value = InlineTypeNode::make_from_oop(this, value, return_type->inline_klass()); + if ((tf()->returns_value_type_as_fields() || (_caller->has_method() && !Compile::current()->inlining_incrementally())) && + return_type->is_valueklassptr()) { + // Value type is returned as fields, make sure it is scalarized + if (!value->is_ValueType()) { + value = ValueTypeNode::make_from_oop(this, value, return_type->value_klass()); } if (!_caller->has_method() || Compile::current()->inlining_incrementally()) { // Returning from root or an incrementally inlined method. Make sure all non-flat // fields are buffered and re-execute if allocation triggers deoptimization. PreserveReexecuteState preexecs(this); - assert(tf()->returns_inline_type_as_fields(), "must be returned as fields"); + assert(tf()->returns_value_type_as_fields(), "must be returned as fields"); jvms()->set_should_reexecute(true); inc_sp(1); - value = value->as_InlineType()->allocate_fields(this); + value = value->as_ValueType()->allocate_fields(this); } - } else if (value->is_InlineType()) { - // Inline type is returned as oop, make sure it is buffered and re-execute + } else if (value->is_ValueType()) { + // Value type is returned as oop, make sure it is buffered and re-execute // if allocation triggers deoptimization. PreserveReexecuteState preexecs(this); jvms()->set_should_reexecute(true); inc_sp(1); - value = value->as_InlineType()->buffer(this); + value = value->as_ValueType()->buffer(this); } // ...else // If returning oops to an interface-return, there is a silent free diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp index 3d548e93eac1..363853e80979 100644 --- a/src/hotspot/share/opto/parse2.cpp +++ b/src/hotspot/share/opto/parse2.cpp @@ -22,9 +22,9 @@ * */ -#include "ci/ciInlineKlass.hpp" #include "ci/ciMethodData.hpp" #include "ci/ciSymbols.hpp" +#include "ci/ciValueKlass.hpp" #include "classfile/vmSymbols.hpp" #include "compiler/compileLog.hpp" #include "interpreter/linkResolver.hpp" @@ -38,7 +38,6 @@ #include "opto/divnode.hpp" #include "opto/idealGraphPrinter.hpp" #include "opto/idealKit.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/matcher.hpp" #include "opto/memnode.hpp" #include "opto/mulnode.hpp" @@ -46,6 +45,7 @@ #include "opto/parse.hpp" #include "opto/runtime.hpp" #include "opto/subtypenode.hpp" +#include "opto/valuetypenode.hpp" #include "runtime/arguments.hpp" #include "runtime/deoptimization.hpp" #include "runtime/globals.hpp" @@ -82,14 +82,14 @@ void Parse::array_load(BasicType bt) { Node* array_index = pop(); Node* array = pop(); - // Handle inline type arrays + // Handle value type arrays const TypeOopPtr* element_ptr = elemtype->make_oopptr(); const TypeAryPtr* array_type = _gvn.type(array)->is_aryptr(); if (!array_type->is_not_flat()) { // Cannot statically determine if array is a flat array, emit runtime check - assert(UseArrayFlattening && is_reference_type(bt) && element_ptr->can_be_inline_type() && - (!element_ptr->is_inlinetypeptr() || element_ptr->inline_klass()->maybe_flat_in_array()), "array can't be flat"); + assert(UseArrayFlattening && is_reference_type(bt) && element_ptr->can_be_value_type() && + (!element_ptr->is_valueklassptr() || element_ptr->value_klass()->maybe_flat_in_array()), "array can't be flat"); IdealKit ideal(this); IdealVariable res(ideal); ideal.declarations_done(); @@ -112,8 +112,8 @@ void Parse::array_load(BasicType bt) { decorator_set |= C2_UNKNOWN_CONTROL_LOAD; } Node* ld = access_load_at(not_flat_ary, adr, adr_type, element_ptr, bt, decorator_set); - if (element_ptr->is_inlinetypeptr()) { - ld = InlineTypeNode::make_from_oop(this, ld, element_ptr->inline_klass()); + if (element_ptr->is_valueklassptr()) { + ld = ValueTypeNode::make_from_oop(this, ld, element_ptr->value_klass()); } ideal.set(res, ld); } @@ -122,29 +122,29 @@ void Parse::array_load(BasicType bt) { // Flat array sync_kit(ideal); if (!array_type->is_not_flat()) { - if (element_ptr->is_inlinetypeptr()) { - ciInlineKlass* vk = element_ptr->inline_klass(); + if (element_ptr->is_valueklassptr()) { + ciValueKlass* vk = element_ptr->value_klass(); Node* flat_array = cast_to_flat_array(array, vk); // It may be the case that array is only known to be not flat when we try to cast it to a // flat array. For example, array is a not-null-free array and vk does not have a // nullable layout. if (!flat_array->is_top()) { - Node* vt = InlineTypeNode::make_from_flat_array(this, vk, flat_array, array_index); + Node* vt = ValueTypeNode::make_from_flat_array(this, vk, flat_array, array_index); ideal.set(res, vt); } else { - ideal.set(res, InlineTypeNode::make_null(gvn(), vk)); + ideal.set(res, ValueTypeNode::make_null(gvn(), vk)); } } else { // Element type is unknown, and thus we cannot statically determine the exact flat array layout. Emit a - // runtime call to correctly load the inline type element from the flat array. - Node* inline_type = load_from_unknown_flat_array(array, array_index, element_ptr); + // runtime call to correctly load the value type element from the flat array. + Node* value_type = load_from_unknown_flat_array(array, array_index, element_ptr); bool is_null_free = array_type->is_null_free() || (!UseNullableAtomicValueFlattening && !UseNullableNonAtomicValueFlattening); if (is_null_free) { - inline_type = cast_not_null(inline_type); + value_type = cast_not_null(value_type); } - ideal.set(res, inline_type); + ideal.set(res, value_type); } } ideal.sync_kit(this); @@ -164,10 +164,10 @@ void Parse::array_load(BasicType bt) { Node* ld = access_load_at(array, adr, adr_type, elemtype, bt, IN_HEAP | IS_ARRAY | C2_CONTROL_DEPENDENT_LOAD); ld = record_profile_for_speculation_at_array_load(ld); - // Loading an inline type from a non-flat array - if (element_ptr != nullptr && element_ptr->is_inlinetypeptr()) { - assert(!array_type->is_null_free() || !element_ptr->maybe_null(), "inline type array elements should never be null"); - ld = InlineTypeNode::make_from_oop(this, ld, element_ptr->inline_klass()); + // Loading a value type from a non-flat array + if (element_ptr != nullptr && element_ptr->is_valueklassptr()) { + assert(!array_type->is_null_free() || !element_ptr->maybe_null(), "value type array elements should never be null"); + ld = ValueTypeNode::make_from_oop(this, ld, element_ptr->value_klass()); } push_node(bt, ld); } @@ -186,8 +186,8 @@ Node* Parse::load_from_unknown_flat_array(Node* array, Node* array_index, const inc_sp(2); kill_dead_locals(); call = make_runtime_call(RC_NO_LEAF | RC_NO_IO, - OptoRuntime::load_unknown_inline_Type(), - OptoRuntime::load_unknown_inline_Java(), + OptoRuntime::load_unknown_value_Type(), + OptoRuntime::load_unknown_value_Java(), nullptr, TypeRawPtr::BOTTOM, array, array_index); } @@ -196,7 +196,7 @@ Node* Parse::load_from_unknown_flat_array(Node* array, Node* array_index, const insert_mem_bar_volatile(Op_MemBarCPUOrder, C->get_alias_index(TypeAryPtr::INLINES)); - // Keep track of the information that the inline type is in flat arrays + // Keep track of the information that the value type is in flat arrays const Type* unknown_value = element_ptr->is_instptr()->cast_to_flat_in_array(); return _gvn.transform(new CheckCastPPNode(control(), buffer, unknown_value)); } @@ -231,13 +231,13 @@ void Parse::array_store(BasicType bt) { const Type* stored_value_casted_type = _gvn.type(stored_value_casted); // Based on the value to be stored, try to determine if the array is not null-free and/or not flat. // This is only legal for non-null stores because the array_store_check always passes for null, even - // if the array is null-free. Null stores are handled in GraphKit::inline_array_null_guard(). - bool not_inline = !stored_value_casted_type->maybe_null() && !stored_value_casted_type->is_oopptr()->can_be_inline_type(); - bool not_null_free = not_inline; - bool not_flat = not_inline || ( stored_value_casted_type->is_inlinetypeptr() && - !stored_value_casted_type->inline_klass()->maybe_flat_in_array()); + // if the array is null-free. Null stores are handled in GraphKit::value_array_null_guard(). + bool not_value = !stored_value_casted_type->maybe_null() && !stored_value_casted_type->is_oopptr()->can_be_value_type(); + bool not_null_free = not_value; + bool not_flat = not_value || ( stored_value_casted_type->is_valueklassptr() && + !stored_value_casted_type->value_klass()->maybe_flat_in_array()); if (!array_type->is_not_null_free() && not_null_free) { - // Storing a non-inline type, mark array as not null-free. + // Storing a non-value type, mark array as not null-free. array_type = array_type->cast_to_not_null_free(); Node* cast = _gvn.transform(new CheckCastPPNode(control(), array, array_type)); replace_in_map(array, cast); @@ -251,15 +251,15 @@ void Parse::array_store(BasicType bt) { array = cast; } - if (array_type->is_null_free() && elemtype->is_inlinetypeptr() && elemtype->inline_klass()->is_empty()) { - // Array of null-free empty inline type, there is only 1 state for the elements + if (array_type->is_null_free() && elemtype->is_valueklassptr() && elemtype->value_klass()->is_empty()) { + // Array of null-free empty value type, there is only 1 state for the elements assert(!stored_value_casted_type->maybe_null(), "should be guaranteed by array store check"); return; } if (!array_type->is_not_flat()) { - // Array might be a flat array, emit runtime checks (for null, a simple inline_array_null_guard is sufficient). - assert(UseArrayFlattening && !not_flat && elemtype->is_oopptr()->can_be_inline_type() && + // Array might be a flat array, emit runtime checks (for null, a simple value_array_null_guard is sufficient). + assert(UseArrayFlattening && !not_flat && elemtype->is_oopptr()->can_be_value_type() && (!array_type->klass_is_exact() || array_type->is_flat()), "array can't be a flat array"); // If by chance (or using layout disabling flags), only the nullable version is flattenable // we could avoid this test in the else branch thereunder (the "Flat array" block) and do it @@ -268,8 +268,8 @@ void Parse::array_store(BasicType bt) { // flat layout, 3. there is no null-free flat layout. Without flags, if a nullable // array is flattenable, so would be the null-free version. So, this optimization would // only apply with extra (experimental) flags which makes the optimization not worth. - array = inline_array_null_guard(array, stored_value_casted, 3); - // Reload array type which could have been updated by inline_array_null_guard(). + array = value_array_null_guard(array, stored_value_casted, 3); + // Reload array type which could have been updated by value_array_null_guard(). array_type = _gvn.type(array)->is_aryptr(); IdealKit ideal(this); ideal.if_then(flat_array_test(array, /* flat = */ false)); { @@ -286,12 +286,12 @@ void Parse::array_store(BasicType bt) { // Flat array sync_kit(ideal); if (!array_type->is_not_flat()) { - // Try to determine the inline klass type of the stored value - ciInlineKlass* vk = nullptr; - if (stored_value_casted_type->is_inlinetypeptr()) { - vk = stored_value_casted_type->inline_klass(); - } else if (elemtype->is_inlinetypeptr()) { - vk = elemtype->inline_klass(); + // Try to determine the value klass type of the stored value + ciValueKlass* vk = nullptr; + if (stored_value_casted_type->is_valueklassptr()) { + vk = stored_value_casted_type->value_klass(); + } else if (elemtype->is_valueklassptr()) { + vk = elemtype->value_klass(); } if (vk != nullptr) { @@ -307,12 +307,12 @@ void Parse::array_store(BasicType bt) { jvms()->set_should_reexecute(true); inc_sp(3); - if (!stored_value_casted->is_InlineType()) { + if (!stored_value_casted->is_ValueType()) { assert(_gvn.type(stored_value_casted) == TypePtr::NULL_PTR, "Unexpected value"); - stored_value_casted = InlineTypeNode::make_null(_gvn, vk); + stored_value_casted = ValueTypeNode::make_null(_gvn, vk); } - stored_value_casted->as_InlineType()->store_flat_array(this, flat_array, array_index); + stored_value_casted->as_ValueType()->store_flat_array(this, flat_array, array_index); } } else { // Element type is unknown, emit a runtime call since the flat array layout is not statically known. @@ -326,8 +326,8 @@ void Parse::array_store(BasicType bt) { return; } else if (!array_type->is_not_null_free()) { // Array is not flat but may be null free - assert(elemtype->is_oopptr()->can_be_inline_type(), "array can't be null-free"); - array = inline_array_null_guard(array, stored_value_casted, 3); + assert(elemtype->is_oopptr()->can_be_value_type(), "array can't be null-free"); + array = value_array_null_guard(array, stored_value_casted, 3); } } inc_sp(3); @@ -351,8 +351,8 @@ void Parse::store_to_unknown_flat_array(Node* array, Node* const idx, Node* non_ inc_sp(3); kill_dead_locals(); call = make_runtime_call(RC_NO_LEAF | RC_NO_IO, - OptoRuntime::store_unknown_inline_Type(), - OptoRuntime::store_unknown_inline_Java(), + OptoRuntime::store_unknown_value_Type(), + OptoRuntime::store_unknown_value_Java(), nullptr, TypeRawPtr::BOTTOM, non_null_stored_value, array, idx); } @@ -399,7 +399,7 @@ Node* Parse::prepare_array_addressing(BasicType type, int vals, const Type*& ele return top(); } - ary = create_speculative_inline_type_array_checks(ary, arytype, elemtype); + ary = create_speculative_value_type_array_checks(ary, arytype, elemtype); if (needs_range_check(sizetype, idx)) { create_range_check(idx, ary, sizetype); @@ -474,11 +474,11 @@ void Parse::create_range_check(Node* idx, Node* ary, const TypeInt* sizetype) { } } -// For inline type arrays, we can use the profiling information for array accesses to speculate on the type, flatness, +// For value type arrays, we can use the profiling information for array accesses to speculate on the type, flatness, // and null-freeness. We can either prepare the speculative type for later uses or emit explicit speculative checks with // traps now. In the latter case, the speculative type guarantees can avoid additional runtime checks later (e.g. // non-null-free implies non-flat which allows us to remove flatness checks). This makes the graph simpler. -Node* Parse::create_speculative_inline_type_array_checks(Node* array, const TypeAryPtr* array_type, +Node* Parse::create_speculative_value_type_array_checks(Node* array, const TypeAryPtr* array_type, const Type*& element_type) { if (!array_type->is_flat() && !array_type->is_not_flat()) { // For arrays that might be flat, speculate that the array has the exact type reported in the profile data such that @@ -490,7 +490,7 @@ Node* Parse::create_speculative_inline_type_array_checks(Node* array, const Type array = cast_to_profiled_array_type(array); } - // Even though the type does not tell us whether we have an inline type array or not, we can still check the profile data + // Even though the type does not tell us whether we have a value type array or not, we can still check the profile data // whether we have a non-null-free or non-flat array. Speculating on a non-null-free array doesn't help aaload but could // be profitable for a subsequent aastore. if (!array_type->is_null_free() && !array_type->is_not_null_free()) { @@ -2086,8 +2086,8 @@ void Parse::acmp_type_check(Node* input, const TypeOopPtr* tinput, ProfilePtrKin } acmp_type_check_or_trap(&cast, input_type, reason); } else { - // No specific type, check for inline type - BuildCutout unless(this, inline_type_test(cast, /* is_inline = */ false), PROB_MAX); + // No specific type, check for value type + BuildCutout unless(this, value_type_test(cast, /* is_value = */ false), PROB_MAX); inc_sp(2); uncommon_trap_exact(Deoptimization::Reason_class_check, Deoptimization::Action_maybe_recompile); } @@ -2123,17 +2123,17 @@ void Parse::do_acmp(BoolTest::mask btest, Node* left, Node* right) { ciKlass* right_type = nullptr; ProfilePtrKind left_ptr = ProfileUnknownNull; ProfilePtrKind right_ptr = ProfileUnknownNull; - bool left_inline_type = true; - bool right_inline_type = true; + bool left_value_type = true; + bool right_value_type = true; // Leverage profiling at acmp if (UseACmpProfile) { - method()->acmp_profiled_type(bci(), left_type, right_type, left_ptr, right_ptr, left_inline_type, right_inline_type); + method()->acmp_profiled_type(bci(), left_type, right_type, left_ptr, right_ptr, left_value_type, right_value_type); if (too_many_traps_or_recompiles(Deoptimization::Reason_class_check) || too_many_traps_or_recompiles(Deoptimization::Reason_speculate_class_check)) { left_type = nullptr; right_type = nullptr; - left_inline_type = true; - right_inline_type = true; + left_value_type = true; + right_value_type = true; } if (too_many_traps_or_recompiles(Deoptimization::Reason_null_check) || too_many_traps_or_recompiles(Deoptimization::Reason_null_assert)) { left_ptr = ProfileUnknownNull; @@ -2159,18 +2159,18 @@ void Parse::do_acmp(BoolTest::mask btest, Node* left, Node* right) { return; } - // Allocate inline type operands and re-execute on deoptimization - if (left->is_InlineType()) { + // Allocate value type operands and re-execute on deoptimization + if (left->is_ValueType()) { PreserveReexecuteState preexecs(this); inc_sp(2); jvms()->set_should_reexecute(true); - left = left->as_InlineType()->buffer(this); + left = left->as_ValueType()->buffer(this); } - if (right->is_InlineType()) { + if (right->is_ValueType()) { PreserveReexecuteState preexecs(this); inc_sp(2); jvms()->set_should_reexecute(true); - right = right->as_InlineType()->buffer(this); + right = right->as_ValueType()->buffer(this); } // First, do a normal pointer comparison @@ -2179,9 +2179,9 @@ void Parse::do_acmp(BoolTest::mask btest, Node* left, Node* right) { Node* cmp = CmpP(left, right); record_for_igvn(cmp); cmp = optimize_cmp_with_klass(cmp); - if (tleft == nullptr || !tleft->can_be_inline_type() || - tright == nullptr || !tright->can_be_inline_type()) { - // This is sufficient, if one of the operands can't be an inline type + if (tleft == nullptr || !tleft->can_be_value_type() || + tright == nullptr || !tright->can_be_value_type()) { + // This is sufficient, if one of the operands can't be a value type do_if(btest, cmp); return; } @@ -2258,23 +2258,23 @@ void Parse::do_acmp(BoolTest::mask btest, Node* left, Node* right) { acmp_always_null_input(right, tright, btest, eq_region); return; } - if (left_type != nullptr && !left_type->is_inlinetype()) { + if (left_type != nullptr && !left_type->is_value_klass()) { // Comparison with an object of known type acmp_type_check(left, tleft, left_ptr, left_type, btest, eq_region); return; } - if (right_type != nullptr && !right_type->is_inlinetype()) { + if (right_type != nullptr && !right_type->is_value_klass()) { // Comparison with an object of known type acmp_type_check(right, tright, right_ptr, right_type, btest, eq_region); return; } - if (!left_inline_type) { - // Comparison with an object known not to be an inline type + if (!left_value_type) { + // Comparison with an object known not to be a value type acmp_type_check(left, tleft, left_ptr, nullptr, btest, eq_region); return; } - if (!right_inline_type) { - // Comparison with an object known not to be an inline type + if (!right_value_type) { + // Comparison with an object known not to be a value type acmp_type_check(right, tright, right_ptr, nullptr, btest, eq_region); return; } @@ -2288,27 +2288,27 @@ void Parse::do_acmp(BoolTest::mask btest, Node* left, Node* right) { Node* kls_right = nullptr; if (!stopped()) { - // First operand is non-null, check if it is the speculative inline type if possible - // (which later allows isSubstitutable to be intrinsified), or any inline type if no + // First operand is non-null, check if it is the speculative value type if possible + // (which later allows isSubstitutable to be intrinsified), or any value type if no // speculation is available. - if (right_type != nullptr && right_type->is_inlinetype()) { + if (right_type != nullptr && right_type->is_value_klass()) { acmp_type_check_or_trap(¬_null_right, right_type, Deoptimization::Reason_speculate_class_check); } else { - Node* is_value = inline_type_test(not_null_right); + Node* is_value = value_type_test(not_null_right); IfNode* is_value_iff = create_and_map_if(control(), is_value, PROB_FAIR, COUNT_UNKNOWN); Node* not_value = _gvn.transform(new IfFalseNode(is_value_iff)); ne_region->init_req(2, not_value); set_control(_gvn.transform(new IfTrueNode(is_value_iff))); } - // The first operand is an inline type, check if the second operand is non-null + // The first operand is a value type, check if the second operand is non-null not_null_left = acmp_null_check(left, tleft, left_ptr, null_ctl); ne_region->init_req(3, null_ctl); if (!stopped()) { - // Check if lhs operand is of a specific speculative inline type (see above). + // Check if lhs operand is of a specific speculative value type (see above). // If not, we don't need to enforce that the lhs is a value object since we know // it already for the rhs, and must enforce that they have the same type. - if (left_type != nullptr && left_type->is_inlinetype()) { + if (left_type != nullptr && left_type->is_value_klass()) { acmp_type_check_or_trap(¬_null_left, left_type, Deoptimization::Reason_speculate_class_check); } if (!stopped()) { @@ -2343,14 +2343,14 @@ void Parse::do_acmp(BoolTest::mask btest, Node* left, Node* right) { IfNode* mask_iff = nullptr; // If any operand has a precisely known type, isSubstitutable will be intrinsified, so we don't need the fast path - if (UseAcmpFastPath && !_gvn.type(not_null_left)->is_inlinetypeptr() && !_gvn.type(not_null_right)->is_inlinetypeptr()) { + if (UseAcmpFastPath && !_gvn.type(not_null_left)->is_valueklassptr() && !_gvn.type(not_null_right)->is_valueklassptr()) { /* Here, we are generating the fast path (the slow path being the call to isSubstitutable) - * See the declarations of _fast_acmp_offset and _fast_acmp_mask in InlineKlass::Members + * See the declarations of _fast_acmp_offset and _fast_acmp_mask in ValueKlass::Members * for details about the fast path logic, and the meaning of these values. */ - Node* members_addr = off_heap_plus_addr(kls_right, in_bytes(InlineKlass::adr_members_offset())); + Node* members_addr = off_heap_plus_addr(kls_right, in_bytes(ValueKlass::adr_members_offset())); Node* members = make_load(control(), members_addr, TypeRawPtr::BOTTOM, T_ADDRESS, MemNode::unordered); - Node* offset_addr = off_heap_plus_addr(members, in_bytes(InlineKlass::fast_acmp_offset_offset())); + Node* offset_addr = off_heap_plus_addr(members, in_bytes(ValueKlass::fast_acmp_offset_offset())); Node* offset = make_load(control(), offset_addr, TypeInt::INT, T_INT, MemNode::unordered); Node* offset_bol = BoolCmpI(offset, BoolTest::lt, zerocon(T_INT)); @@ -2364,7 +2364,7 @@ void Parse::do_acmp(BoolTest::mask btest, Node* left, Node* right) { set_control(fast_path_ctl); Node* offset_l = ConvI2L(offset); - Node* fast_acmp_mask_addr = off_heap_plus_addr(members, in_bytes(InlineKlass::fast_acmp_mask_offset())); + Node* fast_acmp_mask_addr = off_heap_plus_addr(members, in_bytes(ValueKlass::fast_acmp_mask_offset())); Node* fast_acmp_mask = make_load(control(), fast_acmp_mask_addr, TypeLong::LONG, T_LONG, MemNode::unordered); // *(left + offset) & mask == *(right + offset) & mask @@ -2540,7 +2540,7 @@ IfNode* Parse::acmp_fast_path_if_from_substitutable_call(PhaseGVN* phase, CallSt if (!offset_addr_add->in(AddPNode::Base)->is_top()) return nullptr; if (offset_addr_add->in(AddPNode::Address)->Opcode() != Op_LoadP) return nullptr; LoadNode* load_members = offset_addr_add->in(AddPNode::Address)->as_Load(); - if (!is_con_offset(offset_addr_add->in(AddPNode::Offset), InlineKlass::fast_acmp_offset_offset())) return nullptr; + if (!is_con_offset(offset_addr_add->in(AddPNode::Offset), ValueKlass::fast_acmp_offset_offset())) return nullptr; assert(load_members->in(2) != nullptr, ""); if (!load_members->in(2)->is_AddP()) return nullptr; @@ -2551,7 +2551,7 @@ IfNode* Parse::acmp_fast_path_if_from_substitutable_call(PhaseGVN* phase, CallSt assert(members_addr_add->in(AddPNode::Offset) != nullptr, ""); if (!members_addr_add->in(AddPNode::Base)->is_top()) return nullptr; if (!phase->type(members_addr_add->in(AddPNode::Address))->isa_instklassptr()) return nullptr; - if (!is_con_offset(members_addr_add->in(AddPNode::Offset), InlineKlass::adr_members_offset())) return nullptr; + if (!is_con_offset(members_addr_add->in(AddPNode::Offset), ValueKlass::adr_members_offset())) return nullptr; return iff; } @@ -2831,8 +2831,8 @@ void Parse::sharpen_type_after_if(BoolTest::mask btest, // Delay transform() call to allow recovery of pre-cast value at the control merge. _gvn.set_type_bottom(ccast); record_for_igvn(ccast); - if (tboth->is_inlinetypeptr()) { - ccast = InlineTypeNode::make_from_oop(this, ccast, tboth->isa_oopptr()->exact_klass(true)->as_inline_klass()); + if (tboth->is_valueklassptr()) { + ccast = ValueTypeNode::make_from_oop(this, ccast, tboth->isa_oopptr()->exact_klass(true)->as_value_klass()); } // Here's the payoff. replace_in_map(obj, ccast); @@ -2937,9 +2937,9 @@ Node* Parse::optimize_cmp_with_klass(Node* c) { inc_sp(2); obj = maybe_cast_profiled_obj(obj, k); dec_sp(2); - if (obj->is_InlineType()) { - assert(obj->as_InlineType()->is_allocated(&_gvn), "must be allocated"); - obj = obj->as_InlineType()->get_oop(); + if (obj->is_ValueType()) { + assert(obj->as_ValueType()->is_allocated(&_gvn), "must be allocated"); + obj = obj->as_ValueType()->get_oop(); } // Make the CmpP use the casted obj addp = basic_plus_adr(obj, addp->in(AddPNode::Offset)); @@ -3736,10 +3736,10 @@ void Parse::do_one_bytecode() { maybe_add_safepoint(iter().get_dest()); a = null(); b = pop(); - if (b->is_InlineType()) { - // Null checking a scalarized but nullable inline type. Check the null marker + if (b->is_ValueType()) { + // Null checking a scalarized but nullable value type. Check the null marker // input instead of the oop input to avoid keeping buffer allocations alive - c = _gvn.transform(new CmpINode(b->as_InlineType()->get_null_marker(), zerocon(T_INT))); + c = _gvn.transform(new CmpINode(b->as_ValueType()->get_null_marker(), zerocon(T_INT))); } else { if (!_gvn.type(b)->speculative_maybe_null() && !too_many_traps(Deoptimization::Reason_speculate_null_check)) { diff --git a/src/hotspot/share/opto/parse3.cpp b/src/hotspot/share/opto/parse3.cpp index c928670df0d6..e9acd1b46e22 100644 --- a/src/hotspot/share/opto/parse3.cpp +++ b/src/hotspot/share/opto/parse3.cpp @@ -31,12 +31,12 @@ #include "oops/objArrayKlass.hpp" #include "opto/addnode.hpp" #include "opto/castnode.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/memnode.hpp" #include "opto/parse.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" #include "opto/subnode.hpp" +#include "opto/valuetypenode.hpp" #include "runtime/deoptimization.hpp" #include "runtime/handles.inline.hpp" @@ -130,13 +130,13 @@ void Parse::do_get_xxx(Node* obj, ciField* field) { } } - if (obj->is_InlineType()) { + if (obj->is_ValueType()) { assert(!field->is_static(), "must not be a static field"); - InlineTypeNode* vt = obj->as_InlineType(); + ValueTypeNode* vt = obj->as_ValueType(); Node* value = vt->field_value_by_offset(field->offset_in_bytes(), false); const Type* value_type = _gvn.type(value); - if (value_type->is_inlinetypeptr()) { - value = InlineTypeNode::make_from_oop(this, value, value_type->inline_klass()); + if (value_type->is_valueklassptr()) { + value = ValueTypeNode::make_from_oop(this, value, value_type->value_klass()); } pop(); push_node(field->layout_type(), value); @@ -144,7 +144,7 @@ void Parse::do_get_xxx(Node* obj, ciField* field) { } ciType* field_klass = field->type(); - field_klass = improve_abstract_inline_type_klass(field_klass); + field_klass = improve_abstract_value_type_klass(field_klass); int offset = field->offset_in_bytes(); bool must_assert_null = false; Node* adr = basic_plus_adr(obj, obj, offset); @@ -152,16 +152,16 @@ void Parse::do_get_xxx(Node* obj, ciField* field) { "slice of address and input slice don't match"); Node* ld = nullptr; - if (field_klass->is_inlinetype()) { // could also have an abstract value class - ciInlineKlass* vk = field_klass->as_inline_klass(); + if (field_klass->is_value_klass()) { // could also have an abstract value class + ciValueKlass* vk = field_klass->as_value_klass(); if (field->is_null_free() && vk->is_empty()) { - // Loading from a field of an empty inline type. Just return the default instance. - ld = InlineTypeNode::make_all_zero(_gvn, vk); + // Loading from a field of an empty value type. Just return the default instance. + ld = ValueTypeNode::make_all_zero(_gvn, vk); } else if (field->is_flat()) { - // Loading from a flat inline type field. + // Loading from a flat value type field. bool is_immutable = field->is_final() && field->is_strict(); bool atomic = field->is_atomic(); - ld = InlineTypeNode::make_from_flat(this, vk, obj, adr, atomic, is_immutable, field->is_null_free(), IN_HEAP | MO_UNORDERED); + ld = ValueTypeNode::make_from_flat(this, vk, obj, adr, atomic, is_immutable, field->is_null_free(), IN_HEAP | MO_UNORDERED); } } if (ld == nullptr) { @@ -197,9 +197,9 @@ void Parse::do_get_xxx(Node* obj, ciField* field) { DecoratorSet decorators = IN_HEAP; decorators |= field->is_volatile() ? MO_SEQ_CST : MO_UNORDERED; ld = access_load_at(obj, adr, adr_type, type, bt, decorators); - if (field_klass->is_inlinetype()) { - // Load a non-flattened inline type from memory - ld = InlineTypeNode::make_from_oop(this, ld, field_klass->as_inline_klass()); + if (field_klass->is_value_klass()) { + // Load a non-flattened value type from memory + ld = ValueTypeNode::make_from_oop(this, ld, field_klass->as_value_klass()); } } @@ -239,8 +239,8 @@ void Parse::do_get_xxx(Node* obj, ciField* field) { } // If the field klass is an abstract value klass (for which we do not know the layout, yet), it could have a unique -// concrete sub klass for which we have a fixed layout. This allows us to use InlineTypeNodes instead. -ciType* Parse::improve_abstract_inline_type_klass(ciType* field_klass) { +// concrete sub klass for which we have a fixed layout. This allows us to use ValueTypeNodes instead. +ciType* Parse::improve_abstract_value_type_klass(ciType* field_klass) { Dependencies* dependencies = C->dependencies(); if (UseUniqueSubclasses && dependencies != nullptr && field_klass->is_instance_klass()) { ciInstanceKlass* instance_klass = field_klass->as_instance_klass(); @@ -273,26 +273,26 @@ void Parse::do_put_xxx(Node* obj, ciField* field, bool is_field) { Node* adr = basic_plus_adr(obj, obj, offset); - // We cannot store into a non-larval object, so obj must not be an InlineTypeNode - assert(!obj->is_InlineType(), "InlineTypeNodes are non-larval value objects"); + // We cannot store into a non-larval object, so obj must not be an ValueTypeNode + assert(!obj->is_ValueType(), "ValueTypeNodes are non-larval value objects"); ciType* field_klass = field->type(); bool do_store = true; - if (field_klass->is_inlinetype()) { // could also have an abstract value class - ciInlineKlass* vk = field_klass->as_inline_klass(); + if (field_klass->is_value_klass()) { // could also have an abstract value class + ciValueKlass* vk = field_klass->as_value_klass(); if (field->empty_null_free_initialized_value_field(!method()->is_object_constructor())) { - // Storing to an empty, null-free inline type field that is already initialized. Ignore. + // Storing to an empty, null-free value type field that is already initialized. Ignore. return; } if (field->is_flat()) { - // Storing to a flat inline type field. - if (!val->is_InlineType()) { + // Storing to a flat value type field. + if (!val->is_ValueType()) { assert(gvn().type(val) == TypePtr::NULL_PTR, "Unexpected value"); - val = InlineTypeNode::make_null(gvn(), vk); + val = ValueTypeNode::make_null(gvn(), vk); } inc_sp(1); bool is_immutable = field->is_final() && field->is_strict(); bool atomic = field->is_atomic(); - val->as_InlineType()->store_flat(this, obj, adr, atomic, is_immutable, field->is_null_free(), IN_HEAP | MO_UNORDERED); + val->as_ValueType()->store_flat(this, obj, adr, atomic, is_immutable, field->is_null_free(), IN_HEAP | MO_UNORDERED); dec_sp(1); do_store = false; } @@ -374,8 +374,8 @@ void Parse::do_newarray() { array_klass); return; } else if (array_klass->element_klass() != nullptr && - array_klass->element_klass()->is_inlinetype() && - !array_klass->element_klass()->as_inline_klass()->is_initialized()) { + array_klass->element_klass()->is_value_klass() && + !array_klass->element_klass()->as_value_klass()->is_initialized()) { uncommon_trap(Deoptimization::Reason_uninitialized, Deoptimization::Action_reinterpret, nullptr); @@ -448,7 +448,7 @@ void Parse::do_multianewarray() { length[j] = pop(); elem_klass = elem_klass->as_array_klass()->element_klass(); } - if (elem_klass != nullptr && elem_klass->is_inlinetype() && !elem_klass->as_inline_klass()->is_initialized()) { + if (elem_klass != nullptr && elem_klass->is_value_klass() && !elem_klass->as_value_klass()->is_initialized()) { inc_sp(ndimensions); uncommon_trap(Deoptimization::Reason_uninitialized, Deoptimization::Action_reinterpret, diff --git a/src/hotspot/share/opto/parseHelper.cpp b/src/hotspot/share/opto/parseHelper.cpp index b3638a822e77..9f1f67eae89e 100644 --- a/src/hotspot/share/opto/parseHelper.cpp +++ b/src/hotspot/share/opto/parseHelper.cpp @@ -22,19 +22,19 @@ * */ -#include "ci/ciInlineKlass.hpp" #include "ci/ciSymbols.hpp" +#include "ci/ciValueKlass.hpp" #include "compiler/compileLog.hpp" #include "oops/flatArrayKlass.hpp" #include "oops/objArrayKlass.hpp" #include "opto/addnode.hpp" #include "opto/castnode.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/memnode.hpp" #include "opto/mulnode.hpp" #include "opto/parse.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" +#include "opto/valuetypenode.hpp" #include "runtime/sharedRuntime.hpp" //------------------------------make_dtrace_method_entry_exit ---------------- @@ -250,37 +250,37 @@ Node* Parse::array_store_check(const Type*& elemtype) { Node* p2 = off_heap_plus_addr(array_klass, element_klass_offset); Node* a_e_klass = _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), p2, tak)); - // If we statically know that this is an inline type array, use precise element klass for checkcast + // If we statically know that this is a value type array, use precise element klass for checkcast const TypeAryPtr* arytype = _gvn.type(ary)->is_aryptr(); const TypePtr* elem_ptr = elemtype->make_ptr(); bool null_free = arytype->is_null_free(); - if (elem_ptr->is_inlinetypeptr()) { - // We statically know that this is an inline type array, use precise klass ptr - a_e_klass = makecon(TypeKlassPtr::make(elemtype->inline_klass())); + if (elem_ptr->is_valueklassptr()) { + // We statically know that this is a value type array, use precise klass ptr + a_e_klass = makecon(TypeKlassPtr::make(elemtype->value_klass())); } #ifdef ASSERT if (!StressReflectiveCode && array_klass->is_Con() != a_e_klass->is_Con()) { // When the element type is exact, the array type also needs to be exact. There is one exception, though: // Nullable arrays are not exact because the null-free array is a subtype while the element type being a // concrete value class (i.e. final) is always exact. - assert(!array_klass->is_Con() && a_e_klass->is_Con() && elem_ptr->is_inlinetypeptr() && !null_free, + assert(!array_klass->is_Con() && a_e_klass->is_Con() && elem_ptr->is_valueklassptr() && !null_free, "a constant element type either matches a constant array type or a non-constant nullable value class array"); } // If the element type is exact, the array can be null-free (i.e. the element type is NotNull) if: - // - The elements are inline types + // - The elements are value types // - The array is from an autobox cache. // If the element type is inexact, it could represent multiple null-free arrays. Since autobox cache arrays // are local to very few cache classes and are only used in the valueOf() methods, they are always exact and are not // merged or hidden behind super types. Therefore, an inexact null-free array always represents some kind of - // inline type array - either of an abstract value class or Object. + // value type array - either of an abstract value class or Object. if (null_free) { ciKlass* klass = elem_ptr->is_instptr()->instance_klass(); if (klass->exact_klass()) { - assert(elem_ptr->is_inlinetypeptr() || arytype->is_autobox_cache(), "elements must be inline type or autobox cache"); + assert(elem_ptr->is_valueklassptr() || arytype->is_autobox_cache(), "elements must be value type or autobox cache"); } else { - assert(!arytype->is_autobox_cache() && elem_ptr->can_be_inline_type() && - (klass->is_java_lang_Object() || klass->is_abstract()), "cannot have inexact non-inline type elements"); + assert(!arytype->is_autobox_cache() && elem_ptr->can_be_value_type() && + (klass->is_java_lang_Object() || klass->is_abstract()), "cannot have inexact non-value type elements"); } } #endif // ASSERT diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index d816eeeb816e..1d0d24a6635a 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -1038,6 +1038,21 @@ void PhaseIterGVN::trace_PhaseIterGVN_verbose(Node* n, int num_processed) { } #endif /* ASSERT */ +// Whether a node can be killed during IGVN. While transform may kill a node based on its inputs, +// this can also decide to kill a node based on its outputs. +bool PhaseIterGVN::can_kill(Node* n) const { + if (n->is_top()) { + return false; + } + if (n->outcnt() == 0) { + return true; + } + if (n->is_Phi() && n->as_Phi()->is_dead_phi()) { + return true; + } + return false; +} + bool PhaseIterGVN::needs_deep_revisit(const Node* n) const { // LoadNode::Value() -> can_see_stored_value() walks up through many memory // nodes. LoadNode::Ideal() -> find_previous_store() also walks up to 50 @@ -1086,7 +1101,9 @@ bool PhaseIterGVN::drain_worklist() { return true; } DEBUG_ONLY(trace_PhaseIterGVN_verbose(n, _num_processed++);) - if (n->outcnt() != 0) { + if (can_kill(n)) { + remove_globally_dead_node(n, NodeOrigin::Graph); + } else if (!n->is_top()) { NOT_PRODUCT(const Type* oldtype = type_or_null(n)); // Do the transformation DEBUG_ONLY(int live_nodes_before = C->live_nodes();) @@ -1102,8 +1119,6 @@ bool PhaseIterGVN::drain_worklist() { "(should be at most %d)", increase, max_live_nodes_increase_per_iteration); NOT_PRODUCT(trace_PhaseIterGVN(n, nn, oldtype, progress);) - } else if (!n->is_top()) { - remove_dead_node(n, NodeOrigin::Graph); } loop_count++; } @@ -2362,7 +2377,7 @@ void PhaseIterGVN::remove_globally_dead_node(Node* dead, NodeOrigin origin) { } assert(!(i < imax), "sanity"); } - } else if (dead->is_data_proj_of_pure_function(in)) { + } else if (in->should_process_when_disconnect_output(dead)) { _worklist.push(in); } if (ReduceFieldZeroing && dead->is_Load() && i == MemNode::Memory && @@ -2528,20 +2543,29 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_ uint use_op = use->Opcode(); if(use->is_Cmp()) { // Enable CMP/BOOL optimization add_users_to_worklist0(use, worklist); // Put Bool on worklist - if (use->outcnt() > 0) { - Node* bol = use->raw_out(0); - if (bol->outcnt() > 0) { - Node* iff = bol->raw_out(0); - if (iff->outcnt() == 2) { + for (DUIterator_Fast jmax, j = use->fast_outs(jmax); j < jmax; j++) { + Node* bol = use->fast_out(j); + if (!bol->is_Bool()) { + continue; + } + for (DUIterator_Fast kmax, k = bol->fast_outs(kmax); k < kmax; k++) { + Node* bol_use = bol->fast_out(k); + if (bol_use->is_CMove()) { + // CMoveNode::Identity folds "(x == y) ? y : x" by comparing the inputs + // of the Cmp with those of the CMove. + worklist.push(bol_use); + } else if (bol_use->is_If() && bol_use->outcnt() == 2) { // Look for the 'is_x2logic' pattern: "x ? : 0 : 1" and put the // phi merging either 0 or 1 onto the worklist - Node* ifproj0 = iff->raw_out(0); - Node* ifproj1 = iff->raw_out(1); - if (ifproj0->outcnt() > 0 && ifproj1->outcnt() > 0) { + Node* ifproj0 = bol_use->raw_out(0); + Node* ifproj1 = bol_use->raw_out(1); + if (ifproj0->is_IfProj() && ifproj1->is_IfProj() && + ifproj0->outcnt() > 0 && ifproj1->outcnt() > 0) { Node* region0 = ifproj0->raw_out(0); Node* region1 = ifproj1->raw_out(0); - if( region0 == region1 ) + if (region0 == region1 && region0->is_Region()) { add_users_to_worklist0(region0, worklist); + } } } } @@ -2622,15 +2646,15 @@ void PhaseIterGVN::add_users_of_use_to_worklist(Node* n, Node* use, Unique_Node_ } } - // Inline type nodes can have other inline types as users. If an input gets - // updated, make sure that inline type users get a chance for optimization. - if (use->is_InlineType() || use->is_DecodeN()) { + // Value type nodes can have other value types as users. If an input gets + // updated, make sure that value type users get a chance for optimization. + if (use->is_ValueType() || use->is_DecodeN()) { auto push_the_uses_to_worklist = [&](Node* n){ - if (n->is_InlineType()) { + if (n->is_ValueType()) { worklist.push(n); } }; - auto is_boundary = [](Node* n){ return !n->is_InlineType(); }; + auto is_boundary = [](Node* n){ return !n->is_ValueType(); }; use->visit_uses(push_the_uses_to_worklist, is_boundary, true); } // If changed Cast input, notify down for Phi, Sub, and Xor - all do "uncast" @@ -3565,7 +3589,11 @@ void Node::set_req_X( uint i, Node *n, PhaseIterGVN *igvn ) { set_req(i, n); // old goes dead? - if( old ) { + if (old != nullptr) { + if (old->should_process_when_disconnect_output(this)) { + igvn->_worklist.push(old); + } + switch (old->outcnt()) { case 0: // Put into the worklist to kill later. We do not kill it now because the diff --git a/src/hotspot/share/opto/phaseX.hpp b/src/hotspot/share/opto/phaseX.hpp index c57529213933..9f7b9d790375 100644 --- a/src/hotspot/share/opto/phaseX.hpp +++ b/src/hotspot/share/opto/phaseX.hpp @@ -477,6 +477,8 @@ class PhaseIterGVN : public PhaseGVN { // Idealize old Node 'n' with respect to its inputs and its value virtual Node *transform_old( Node *a_node ); + bool can_kill(Node* n) const; + // Drain the IGVN worklist: process nodes until the worklist is empty. // Returns true if compilation was aborted (node limit or infinite loop), // false on normal completion. diff --git a/src/hotspot/share/opto/printinlining.cpp b/src/hotspot/share/opto/printinlining.cpp index 06d14a7f3af2..18b411835684 100644 --- a/src/hotspot/share/opto/printinlining.cpp +++ b/src/hotspot/share/opto/printinlining.cpp @@ -35,6 +35,9 @@ outputStream* InlinePrinter::record(ciMethod* callee, JVMState* state, InliningR if (!is_enabled()) { return &_nullStream; } + if (is_suspended()) { + return &_nullStream; + } outputStream* stream = locate(state, callee)->add(result); if (msg != nullptr) { stream->print("%s", msg); diff --git a/src/hotspot/share/opto/printinlining.hpp b/src/hotspot/share/opto/printinlining.hpp index e331593ec0e6..e45f5075a8d3 100644 --- a/src/hotspot/share/opto/printinlining.hpp +++ b/src/hotspot/share/opto/printinlining.hpp @@ -114,6 +114,8 @@ class InlinePrinter { Compile* C; + uint _suspend_depth; + // In case print inline is disabled, this null stream is returned from ::record() nullStream _nullStream; @@ -126,7 +128,7 @@ class InlinePrinter { IPInlineSite _root{nullptr, 0}; public: - InlinePrinter(Compile* compile) : C(compile) {} + InlinePrinter(Compile* compile) : C(compile), _suspend_depth(0) {} // Saves the result of an inline attempt of method at state. // An optional string message with more details that is copied to the stream for this attempt. Pointer is not captured. @@ -136,6 +138,18 @@ class InlinePrinter { // Prints all collected inlining information to the given output stream. void print_on(outputStream* tty) const; + + bool is_suspended() const { return _suspend_depth > 0; } + void suspend() { _suspend_depth++; } + void resume() { assert(_suspend_depth > 0, "unbalanced resume"); _suspend_depth--; } +}; + +class InlinePrinterSuspendScope : public StackObj { + private: + InlinePrinter* const _printer; + public: + InlinePrinterSuspendScope(InlinePrinter* printer) : _printer(printer) { _printer->suspend(); } + ~InlinePrinterSuspendScope() { _printer->resume(); } }; #endif // PRINTINLINING_HPP diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index 62ea21e7fe29..f5095700a1fa 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -47,11 +47,11 @@ #include "memory/resourceArea.hpp" #include "oops/flatArrayKlass.hpp" #include "oops/flatArrayOop.inline.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/klass.inline.hpp" #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" +#include "oops/valueKlass.inline.hpp" #include "oops/valuePayload.inline.hpp" #include "opto/ad.hpp" #include "opto/addnode.hpp" @@ -2457,7 +2457,7 @@ static void trace_exception(outputStream* st, oop exception_oop, address excepti st->print_raw_cr(tempst.freeze()); } -const TypeFunc *OptoRuntime::store_inline_type_fields_Type() { +const TypeFunc *OptoRuntime::store_value_type_fields_Type() { // create input type (domain) uint total = SharedRuntime::java_return_convention_max_int + SharedRuntime::java_return_convention_max_float*2; const Type **fields = TypeTuple::fields(total); @@ -2484,7 +2484,7 @@ const TypeFunc *OptoRuntime::store_inline_type_fields_Type() { return TypeFunc::make(domain, range); } -const TypeFunc *OptoRuntime::pack_inline_type_Type() { +const TypeFunc *OptoRuntime::pack_value_type_Type() { // create input type (domain) uint total = 1 + SharedRuntime::java_return_convention_max_int + SharedRuntime::java_return_convention_max_float*2; const Type **fields = TypeTuple::fields(total); @@ -2512,7 +2512,7 @@ const TypeFunc *OptoRuntime::pack_inline_type_Type() { return TypeFunc::make(domain, range); } -JRT_BLOCK_ENTRY(void, OptoRuntime::load_unknown_inline_C(flatArrayOopDesc* array, int index, JavaThread* current)) +JRT_BLOCK_ENTRY(void, OptoRuntime::load_unknown_value_C(flatArrayOopDesc* array, int index, JavaThread* current)) JRT_BLOCK; oop buffer = array->obj_at(index, THREAD); deoptimize_caller_frame(current, HAS_PENDING_EXCEPTION); @@ -2520,7 +2520,7 @@ JRT_BLOCK_ENTRY(void, OptoRuntime::load_unknown_inline_C(flatArrayOopDesc* array JRT_BLOCK_END; JRT_END -const TypeFunc* OptoRuntime::load_unknown_inline_Type() { +const TypeFunc* OptoRuntime::load_unknown_value_Type() { // create input type (domain) const Type** fields = TypeTuple::fields(2); fields[TypeFunc::Parms] = TypeOopPtr::NOTNULL; @@ -2537,7 +2537,7 @@ const TypeFunc* OptoRuntime::load_unknown_inline_Type() { return TypeFunc::make(domain, range); } -JRT_BLOCK_ENTRY(void, OptoRuntime::store_unknown_inline_C(instanceOopDesc* buffer, flatArrayOopDesc* array, int index, JavaThread* current)) +JRT_BLOCK_ENTRY(void, OptoRuntime::store_unknown_value_C(instanceOopDesc* buffer, flatArrayOopDesc* array, int index, JavaThread* current)) JRT_BLOCK; array->obj_at_put(index, buffer, THREAD); if (HAS_PENDING_EXCEPTION) { @@ -2546,7 +2546,7 @@ JRT_BLOCK_ENTRY(void, OptoRuntime::store_unknown_inline_C(instanceOopDesc* buffe JRT_BLOCK_END; JRT_END -const TypeFunc* OptoRuntime::store_unknown_inline_Type() { +const TypeFunc* OptoRuntime::store_unknown_value_Type() { // create input type (domain) const Type** fields = TypeTuple::fields(3); fields[TypeFunc::Parms] = TypeInstPtr::NOTNULL; diff --git a/src/hotspot/share/opto/runtime.hpp b/src/hotspot/share/opto/runtime.hpp index a5c932142fd2..023c1ddfaa91 100644 --- a/src/hotspot/share/opto/runtime.hpp +++ b/src/hotspot/share/opto/runtime.hpp @@ -265,8 +265,8 @@ class OptoRuntime : public AllStatic { static void register_finalizer_C(oopDesc* obj, JavaThread* current); public: - static void load_unknown_inline_C(flatArrayOopDesc* array, int index, JavaThread* current); - static void store_unknown_inline_C(instanceOopDesc* buffer, flatArrayOopDesc* array, int index, JavaThread* current); + static void load_unknown_value_C(flatArrayOopDesc* array, int index, JavaThread* current); + static void store_unknown_value_C(instanceOopDesc* buffer, flatArrayOopDesc* array, int index, JavaThread* current); static bool is_callee_saved_register(MachRegisterNumbers reg); @@ -299,8 +299,8 @@ class OptoRuntime : public AllStatic { static address slow_arraycopy_Java() { return _slow_arraycopy_Java; } static address register_finalizer_Java() { return _register_finalizer_Java; } - static address load_unknown_inline_Java() { return _load_unknown_inline_Java; } - static address store_unknown_inline_Java() { return _store_unknown_inline_Java; } + static address load_unknown_value_Java() { return _load_unknown_value_Java; } + static address store_unknown_value_Java() { return _store_unknown_value_Java; } static address vthread_end_first_transition_Java() { return _vthread_end_first_transition_Java; } static address vthread_start_final_transition_Java() { return _vthread_start_final_transition_Java; } @@ -771,11 +771,11 @@ class OptoRuntime : public AllStatic { } #endif // INCLUDE_JFR - static const TypeFunc* load_unknown_inline_Type(); - static const TypeFunc* store_unknown_inline_Type(); + static const TypeFunc* load_unknown_value_Type(); + static const TypeFunc* store_unknown_value_Type(); - static const TypeFunc* store_inline_type_fields_Type(); - static const TypeFunc* pack_inline_type_Type(); + static const TypeFunc* store_value_type_fields_Type(); + static const TypeFunc* pack_value_type_Type(); // Dtrace support. entry and exit probes have the same signature static inline const TypeFunc* dtrace_method_entry_exit_Type() { diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp index 4ea516547029..c5af3c6cf29d 100644 --- a/src/hotspot/share/opto/subnode.cpp +++ b/src/hotspot/share/opto/subnode.cpp @@ -32,7 +32,6 @@ #include "opto/castnode.hpp" #include "opto/cfgnode.hpp" #include "opto/convertnode.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/loopnode.hpp" #include "opto/matcher.hpp" #include "opto/movenode.hpp" @@ -41,6 +40,7 @@ #include "opto/opcodes.hpp" #include "opto/phaseX.hpp" #include "opto/subnode.hpp" +#include "opto/valuetypenode.hpp" #include "runtime/arguments.hpp" #include "runtime/sharedRuntime.hpp" #include "utilities/reverse_bits.hpp" @@ -822,38 +822,36 @@ const Type* CmpUNode::Value(PhaseGVN* phase) const { // Skip cases when input types are top or bottom. if ((t11 != Type::TOP) && (t11 != TypeInt::INT) && (t12 != Type::TOP) && (t12 != TypeInt::INT)) { - const TypeInt *r0 = t11->is_int(); - const TypeInt *r1 = t12->is_int(); - jlong lo_r0 = r0->_lo; - jlong hi_r0 = r0->_hi; - jlong lo_r1 = r1->_lo; - jlong hi_r1 = r1->_hi; + const TypeInt *ti11 = t11->is_int(); + const TypeInt *ti12 = t12->is_int(); + jlong lo_ti11_range = ti11->_lo; + jlong hi_ti11_range = ti11->_hi; + jlong lo_ti12_range = ti12->_lo; + jlong hi_ti12_range = ti12->_hi; if (in1_op == Op_SubI) { - jlong tmp = hi_r1; - hi_r1 = -lo_r1; - lo_r1 = -tmp; + jlong tmp = hi_ti12_range; + hi_ti12_range = -lo_ti12_range; + lo_ti12_range = -tmp; // Note, for substructing [minint,x] type range // long arithmetic provides correct overflow answer. // The confusion come from the fact that in 32-bit // -minint == minint but in 64-bit -minint == maxint+1. } - jlong lo_long = lo_r0 + lo_r1; - jlong hi_long = hi_r0 + hi_r1; - int lo_tr1 = min_jint; - int hi_tr1 = (int)hi_long; - int lo_tr2 = (int)lo_long; - int hi_tr2 = max_jint; - bool underflow = lo_long != (jlong)lo_tr2; - bool overflow = hi_long != (jlong)hi_tr1; + jlong lo_sum_range = lo_ti11_range + lo_ti12_range; + jlong hi_sum_range = hi_ti11_range + hi_ti12_range; + int hi_wrapped_range = (int)hi_sum_range; + int lo_wrapped_range = (int)lo_sum_range; + bool underflow = lo_sum_range != (jlong)lo_wrapped_range; + bool overflow = hi_sum_range != (jlong)hi_wrapped_range; // Use sub(t1, t2) when there is no overflow (one type range) // or when both overflow and underflow (too complex). - if ((underflow != overflow) && (hi_tr1 < lo_tr2)) { + if ((underflow != overflow) && (hi_wrapped_range < lo_wrapped_range)) { // Overflow only on one boundary, compare 2 separate type ranges. - int w = MAX2(r0->_widen, r1->_widen); // _widen does not matter here - const TypeInt* tr1 = TypeInt::make(lo_tr1, hi_tr1, w); - const TypeInt* tr2 = TypeInt::make(lo_tr2, hi_tr2, w); - const TypeInt* cmp1 = sub(tr1, t2)->is_int(); - const TypeInt* cmp2 = sub(tr2, t2)->is_int(); + int w = MAX2(ti11->_widen, ti12->_widen); // _widen does not matter here + const TypeInt* wrapped_range1 = TypeInt::make(min_jint, hi_wrapped_range, w); + const TypeInt* wrapped_range2 = TypeInt::make(lo_wrapped_range, max_jint, w); + const TypeInt* cmp1 = sub(wrapped_range1, t2)->is_int(); + const TypeInt* cmp2 = sub(wrapped_range2, t2)->is_int(); // Compute union, so that cmp handles all possible results from the two cases const Type* t_cmp = cmp1->meet(cmp2); // Pick narrowest type, based on overflow computation and on immediate inputs @@ -906,9 +904,9 @@ Node* CmpLNode::Ideal(PhaseGVN* phase, bool can_reshape) { Node* orIn = in(1)->in(i); if (orIn->Opcode() == Op_CastP2X) { Node* castIn = orIn->in(1); - if (castIn->is_InlineType()) { + if (castIn->is_ValueType()) { // Replace the CastP2X by the null marker - InlineTypeNode* vt = castIn->as_InlineType(); + ValueTypeNode* vt = castIn->as_ValueType(); Node* nm = phase->transform(new ConvI2LNode(vt->get_null_marker())); phase->is_IterGVN()->replace_input_of(in(1), i, nm); return this; @@ -1028,7 +1026,7 @@ const Type *CmpPNode::sub( const Type *t1, const Type *t2 ) const { unrelated_classes = xklass0; } if (!unrelated_classes) { - // Handle inline type arrays + // Handle value type arrays if ((r0->is_flat_in_array() && r1->is_not_flat_in_array()) || (r1->is_flat_in_array() && r0->is_not_flat_in_array())) { // One type is in flat arrays but the other type is not. Must be unrelated. @@ -1114,7 +1112,7 @@ static inline Node* isa_const_java_mirror(PhaseGVN* phase, Node* n, bool& might_ ciKlass* mirror_klass = mirror_type->as_klass(); if (mirror_klass->is_array_klass() && !mirror_klass->is_type_array_klass()) { - if (!mirror_klass->can_be_inline_array_klass()) { + if (!mirror_klass->can_be_value_array_klass()) { // Special case for non-value arrays: They only have one (default) refined class, use it ciArrayKlass* refined_mirror_klass = ciObjArrayKlass::make(mirror_klass->as_array_klass()->element_klass(), true); return phase->makecon(TypeAryKlassPtr::make(refined_mirror_klass, Type::trust_interfaces)); @@ -1135,12 +1133,12 @@ static inline Node* isa_const_java_mirror(PhaseGVN* phase, Node* n, bool& might_ Node* CmpPNode::Ideal(PhaseGVN *phase, bool can_reshape) { Node* uncast_in1 = in(1)->uncast(); Node* uncast_in2 = in(2)->uncast(); - if (uncast_in1->is_InlineType() && phase->type(uncast_in2)->is_zero_type()) { - // Null checking a scalarized but nullable inline type. Check the null marker + if (uncast_in1->is_ValueType() && phase->type(uncast_in2)->is_zero_type()) { + // Null checking a scalarized but nullable value type. Check the null marker // input instead of the oop input to avoid keeping buffer allocations alive. - return new CmpINode(uncast_in1->as_InlineType()->get_null_marker(), phase->intcon(0)); + return new CmpINode(uncast_in1->as_ValueType()->get_null_marker(), phase->intcon(0)); } - if (uncast_in1->is_InlineType() || uncast_in2->is_InlineType()) { + if (uncast_in1->is_ValueType() || uncast_in2->is_ValueType()) { // In C2 IR, CmpP on value objects is a pointer comparison, not a value comparison. // For non-null operands it cannot reliably be true, since their buffer oops are not // guaranteed to be identical. Therefore, the comparison can only be true when both @@ -1150,8 +1148,8 @@ Node* CmpPNode::Ideal(PhaseGVN *phase, bool can_reshape) { Node* input[2]; for (int i = 1; i <= 2; ++i) { Node* uncast_in = in(i)->uncast(); - if (uncast_in->is_InlineType()) { - input[i-1] = phase->transform(new ConvI2LNode(uncast_in->as_InlineType()->get_null_marker())); + if (uncast_in->is_ValueType()) { + input[i-1] = phase->transform(new ConvI2LNode(uncast_in->as_ValueType()->get_null_marker())); } else { input[i-1] = phase->transform(new CastP2XNode(nullptr, uncast_in)); } @@ -1266,7 +1264,7 @@ Node* CmpPNode::Ideal(PhaseGVN *phase, bool can_reshape) { superklass = t2->exact_klass(); assert(!superklass->is_flat_array_klass(), "Unexpected flat array klass"); if (superklass->is_obj_array_klass()) { - if (superklass->as_array_klass()->element_klass()->is_inlinetype() && !superklass->as_array_klass()->is_refined()) { + if (superklass->as_array_klass()->element_klass()->is_value_klass() && !superklass->as_array_klass()->is_refined()) { return nullptr; } else { // Special case for non-value arrays: They only have one (default) refined class, use it diff --git a/src/hotspot/share/opto/subtypenode.cpp b/src/hotspot/share/opto/subtypenode.cpp index 91076d0cef74..7adefe138e13 100644 --- a/src/hotspot/share/opto/subtypenode.cpp +++ b/src/hotspot/share/opto/subtypenode.cpp @@ -50,7 +50,7 @@ const Type* SubTypeCheckNode::sub(const Type* sub_t, const Type* super_t) const // Similar to logic in CmpPNode::sub() bool unrelated_classes = false; - // Handle inline type arrays + // Handle value type arrays // // The super klass can be an exact non-array klass constant which is known to be not flat in array (e.g. Object) // while the sub klass could very well be flat in array: diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 748c9298c2a0..8365afeb72dd 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -25,13 +25,13 @@ #include "ci/ciField.hpp" #include "ci/ciFlatArray.hpp" #include "ci/ciFlatArrayKlass.hpp" -#include "ci/ciInlineKlass.hpp" #include "ci/ciInstanceKlass.hpp" #include "ci/ciMetadata.hpp" #include "ci/ciMethodData.hpp" #include "ci/ciObjArrayKlass.hpp" #include "ci/ciObject.hpp" #include "ci/ciTypeFlow.hpp" +#include "ci/ciValueKlass.hpp" #include "classfile/javaClasses.hpp" #include "classfile/symbolTable.hpp" #include "compiler/compileLog.hpp" @@ -2267,11 +2267,11 @@ const TypeTuple *TypeTuple::LONG_PAIR; const TypeTuple *TypeTuple::INT_CC_PAIR; const TypeTuple *TypeTuple::LONG_CC_PAIR; -static void collect_inline_fields(ciInlineKlass* vk, const Type** field_array, uint& pos) { +static void collect_inline_fields(ciValueKlass* vk, const Type** field_array, uint& pos) { for (int i = 0; i < vk->nof_declared_nonstatic_fields(); i++) { ciField* field = vk->declared_nonstatic_field_at(i); if (field->is_flat()) { - collect_inline_fields(field->type()->as_inline_klass(), field_array, pos); + collect_inline_fields(field->type()->as_value_klass(), field_array, pos); if (!field->is_null_free()) { // Use T_INT instead of T_BOOLEAN here because the upper bits can contain garbage if the holder // is null and C2 will only zero them for T_INT assuming that T_BOOLEAN is already canonicalized. @@ -2294,9 +2294,9 @@ const TypeTuple* TypeTuple::make_range(ciSignature* sig, InterfaceHandling inter ciType* return_type = sig->return_type(); uint arg_cnt = return_type->size(); if (ret_vt_fields) { - arg_cnt = return_type->as_inline_klass()->inline_arg_slots() + 1; + arg_cnt = return_type->as_value_klass()->value_arg_slots() + 1; if (is_call) { - // InlineTypeNode::NullMarker field returned by scalarized calls + // ValueTypeNode::NullMarker field returned by scalarized calls arg_cnt++; } } @@ -2314,9 +2314,9 @@ const TypeTuple* TypeTuple::make_range(ciSignature* sig, InterfaceHandling inter if (ret_vt_fields) { uint pos = TypeFunc::Parms; field_array[pos++] = get_const_type(return_type); // Oop might be null when returning as fields - collect_inline_fields(return_type->as_inline_klass(), field_array, pos); + collect_inline_fields(return_type->as_value_klass(), field_array, pos); if (is_call) { - // InlineTypeNode::NullMarker field returned by scalarized calls + // ValueTypeNode::NullMarker field returned by scalarized calls field_array[pos++] = get_const_basic_type(T_BOOLEAN); } assert(pos == (TypeFunc::Parms + arg_cnt), "out of bounds"); @@ -2358,9 +2358,9 @@ const TypeTuple *TypeTuple::make_domain(ciMethod* method, InterfaceHandling inte const Type** field_array = fields(arg_cnt); if (!method->is_static()) { ciInstanceKlass* recv = method->holder(); - if (vt_fields_as_args && recv->is_inlinetype() && recv->as_inline_klass()->can_be_passed_as_fields() && method->is_scalarized_arg(0)) { + if (vt_fields_as_args && recv->is_value_klass() && recv->as_value_klass()->can_be_passed_as_fields() && method->is_scalarized_arg(0)) { field_array[pos++] = get_const_type(recv, interface_handling); // buffer argument - collect_inline_fields(recv->as_inline_klass(), field_array, pos); + collect_inline_fields(recv->as_value_klass(), field_array, pos); } else { field_array[pos++] = get_const_type(recv, interface_handling)->join_speculative(TypePtr::NOTNULL); } @@ -2381,11 +2381,11 @@ const TypeTuple *TypeTuple::make_domain(ciMethod* method, InterfaceHandling inte field_array[pos++] = Type::HALF; break; case T_OBJECT: - if (type->is_inlinetype() && vt_fields_as_args && method->is_scalarized_arg(i + (method->is_static() ? 0 : 1))) { + if (type->is_value_klass() && vt_fields_as_args && method->is_scalarized_arg(i + (method->is_static() ? 0 : 1))) { field_array[pos++] = get_const_type(type, interface_handling); // buffer argument - // InlineTypeNode::NullMarker field used for null checking + // ValueTypeNode::NullMarker field used for null checking field_array[pos++] = get_const_basic_type(T_BOOLEAN); - collect_inline_fields(type->as_inline_klass(), field_array, pos); + collect_inline_fields(type->as_value_klass(), field_array, pos); } else { field_array[pos++] = get_const_type(type, interface_handling); } @@ -2638,7 +2638,7 @@ bool TypeAry::ary_must_be_exact() const { if (tinst->instance_klass()->is_final()) { // Even though MyValue is final, MyValue[] is only exact if MyValue is not a value class, // because there may be many refined type for MyValue[] - if (tinst->is_inlinetypeptr()) { + if (tinst->is_valueklassptr()) { return false; } return true; @@ -3209,17 +3209,17 @@ bool TypePtr::would_improve_ptr(ProfilePtrKind ptr_kind) const { } TypePtr::FlatInArray TypePtr::compute_flat_in_array(ciInstanceKlass* instance_klass, bool is_exact) { - if (!instance_klass->can_be_inline_klass(is_exact) || !UseArrayFlattening) { + if (!instance_klass->can_be_value_klass(is_exact) || !UseArrayFlattening) { // Definitely not a value class, or flattening is not even enabled, and thus never flat in an array. return NotFlat; } - if (instance_klass->is_inlinetype()) { - if (instance_klass->as_inline_klass()->maybe_flat_in_array()) { + if (instance_klass->is_value_klass()) { + if (instance_klass->as_value_klass()->maybe_flat_in_array()) { return MaybeFlat; } return NotFlat; } - // It's not an inline class, but can still be, so we don't know. + // It's not a value class, but can still be, so we don't know. return MaybeFlat; } @@ -3622,6 +3622,7 @@ void TypeInterfaces::verify() const { #endif const TypeInterfaces* TypeInterfaces::union_with(const TypeInterfaces* other) const { + ResourceMark rm; GrowableArray result_list; int i = 0; int j = 0; @@ -3663,6 +3664,7 @@ const TypeInterfaces* TypeInterfaces::union_with(const TypeInterfaces* other) co } const TypeInterfaces* TypeInterfaces::intersection_with(const TypeInterfaces* other) const { + ResourceMark rm; GrowableArray result_list; int i = 0; int j = 0; @@ -3789,8 +3791,8 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const TypeInterfaces* inter _is_ptr_to_narrowoop = UseCompressedOops; } else if (UseCompressedOops && this->isa_aryptr() && this->offset() != arrayOopDesc::length_offset_in_bytes()) { if (klass()->is_flat_array_klass() && field_offset != Offset::top && field_offset != Offset::bottom) { - // Check if the field of the inline type array element contains oops - ciInlineKlass* vk = klass()->as_flat_array_klass()->element_klass()->as_inline_klass(); + // Check if the field of the value type array element contains oops + ciValueKlass* vk = klass()->as_flat_array_klass()->element_klass()->as_value_klass(); int foffset = field_offset.get() + vk->payload_offset(); BasicType field_bt; ciField* field = vk->get_field_by_offset(foffset, false); @@ -3995,7 +3997,7 @@ const Type* TypeOopPtr::xjoin_helper(const Type* t) const { //--------------------------make_from_klass_common----------------------------- // Computes the element-type given a klass. const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_change, bool try_for_exact, InterfaceHandling interface_handling) { - if (klass->is_instance_klass() || klass->is_inlinetype()) { + if (klass->is_instance_klass() || klass->is_value_klass()) { Compile* C = Compile::current(); Dependencies* deps = C->dependencies(); assert((deps != nullptr) == (C->method() != nullptr && C->method()->code_size() > 0), "sanity"); @@ -4025,7 +4027,7 @@ const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_ const TypeInterfaces* interfaces = TypePtr::interfaces(klass, true, true, false, interface_handling); return TypeInstPtr::make(TypePtr::BotPTR, klass, interfaces, klass_is_exact, nullptr, Offset(0), flat_in_array); } else if (klass->is_obj_array_klass()) { - // Element is an object or inline type array. Recursively call ourself. + // Element is an object or value type array. Recursively call ourself. ciObjArrayKlass* array_klass = klass->as_obj_array_klass(); const TypeOopPtr* etype = TypeOopPtr::make_from_klass_common(array_klass->element_klass(), /* klass_change= */ false, try_for_exact, interface_handling); bool xk = array_klass->is_loaded() && array_klass->is_refined(); @@ -4048,16 +4050,16 @@ const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_ } } else { const TypeOopPtr* exact_etype = etype; - if (etype->can_be_inline_type()) { - // Use exact type if element can be an inline type + if (etype->can_be_value_type()) { + // Use exact type if element can be a value type exact_etype = TypeOopPtr::make_from_klass_common(klass->as_array_klass()->element_klass(), /* klass_change= */ true, /* try_for_exact= */ true, interface_handling); } flat = false; - bool not_inline = !exact_etype->can_be_inline_type(); + bool not_value = !exact_etype->can_be_value_type(); null_free = false; - not_null_free = not_inline; - not_flat = !UseArrayFlattening || not_inline || (exact_etype->is_inlinetypeptr() && !exact_etype->inline_klass()->maybe_flat_in_array()); + not_null_free = not_value; + not_flat = !UseArrayFlattening || not_value || (exact_etype->is_valueklassptr() && !exact_etype->value_klass()->maybe_flat_in_array()); atomic = not_flat; } @@ -4090,8 +4092,8 @@ const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_const const bool make_constant = require_constant || o->should_be_constant(); ciKlass* klass = o->klass(); - if (klass->is_instance_klass() || klass->is_inlinetype()) { - // Element is an instance or inline type + if (klass->is_instance_klass() || klass->is_value_klass()) { + // Element is an instance or value type if (make_constant) { return TypeInstPtr::make(o); } else { @@ -5179,9 +5181,9 @@ bool TypeAryPtr::empty(void) const { } // Reference array is always possible. Only flat array with non-flattenable content can be an issue. - if (const TypeOopPtr* elem_ptr = elem()->make_oopptr(); _ary->_flat && elem_ptr != nullptr && elem_ptr->is_inlinetypeptr()) { + if (const TypeOopPtr* elem_ptr = elem()->make_oopptr(); _ary->_flat && elem_ptr != nullptr && elem_ptr->is_valueklassptr()) { auto impossible_layout_with_null_freeness = [this](bool null_free, bool atomic) -> bool { - ArrayDescription description = elem()->inline_klass()->array_description_of_array_properties(ArrayProperties::Default().with_null_restricted(null_free).with_non_atomic(!atomic)); + ArrayDescription description = elem()->value_klass()->array_description_of_array_properties(ArrayProperties::Default().with_null_restricted(null_free).with_non_atomic(!atomic)); return !LayoutKindHelper::is_flat(description._layout_kind); // We get a contradiction between _ary->_flat and array_layout_selection }; auto impossible_layout = [&](bool atomic) -> bool { @@ -5287,9 +5289,9 @@ const TypePtr* TypeAryPtr::add_field_offset_and_offset(intptr_t offset) const { offset += header; } } - if (elem()->make_oopptr()->is_inlinetypeptr() && (offset >= (intptr_t)header || offset < 0)) { - // Try to get the field of the inline type array element we are pointing to - ciInlineKlass* vk = elem()->inline_klass(); + if (elem()->make_oopptr()->is_valueklassptr() && (offset >= (intptr_t)header || offset < 0)) { + // Try to get the field of the value type array element we are pointing to + ciValueKlass* vk = elem()->value_klass(); int shift = flat_log_elem_size(); int mask = (1 << shift) - 1; int field_offset = static_cast((offset - header) & mask); @@ -5301,7 +5303,7 @@ const TypePtr* TypeAryPtr::add_field_offset_and_offset(intptr_t offset) const { return add_offset(offset - adj); } -// Return offset incremented by field_offset for flat inline type arrays +// Return offset incremented by field_offset for flat value type arrays int TypeAryPtr::flat_offset() const { int offset = _offset.get(); if (offset != OffsetBot && offset != OffsetTop && @@ -5631,7 +5633,7 @@ const TypeKlassPtr* TypeAryPtr::as_klass_type(bool try_for_exact) const { } else { const TypeInstKlassPtr* elem_klass = elem->is_instklassptr(); if (try_for_exact && !xk && elem_klass->klass_is_exact() && - !elem_klass->exact_klass()->as_instance_klass()->can_be_inline_klass()) { + !elem_klass->exact_klass()->as_instance_klass()->can_be_value_klass()) { xk = true; } } @@ -6027,7 +6029,7 @@ const TypeKlassPtr* TypeInstKlassPtr::try_improve() const { return this; } -bool TypeInstKlassPtr::can_be_inline_array() const { +bool TypeInstKlassPtr::can_be_value_array() const { return _klass->equals(ciEnv::current()->Object_klass()) && TypeAryKlassPtr::_array_interfaces->contains(_interfaces); } @@ -6048,16 +6050,16 @@ void TypeInstKlassPtr::dump2(Dict& d, uint depth, outputStream* st) const { const TypeAryKlassPtr* TypeAryKlassPtr::OBJECT_ARRAY; // Not-null object array klass const TypeAryKlassPtr* TypeAryKlassPtr::OBJECT_ARRAY_OR_NULL; // Maybe-null object array klass -bool TypeAryKlassPtr::can_be_inline_array() const { - return _elem->isa_instklassptr() && _elem->is_instklassptr()->_klass->can_be_inline_klass(); +bool TypeAryKlassPtr::can_be_value_array() const { + return _elem->isa_instklassptr() && _elem->is_instklassptr()->_klass->can_be_value_klass(); } -bool TypeInstPtr::can_be_inline_array() const { +bool TypeInstPtr::can_be_value_array() const { return _klass->equals(ciEnv::current()->Object_klass()) && TypeAryPtr::_array_interfaces->contains(_interfaces); } -bool TypeAryPtr::can_be_inline_array() const { - return elem()->make_ptr() && elem()->make_ptr()->isa_instptr() && elem()->make_ptr()->is_instptr()->_klass->can_be_inline_klass(); +bool TypeAryPtr::can_be_value_array() const { + return elem()->make_ptr() && elem()->make_ptr()->isa_instptr() && elem()->make_ptr()->is_instptr()->_klass->can_be_value_klass(); } const TypeAryKlassPtr *TypeAryKlassPtr::make(PTR ptr, const Type* elem, ciKlass* k, Offset offset, bool not_flat, bool not_null_free, bool flat, bool null_free, bool atomic, bool refined_type) { @@ -6279,10 +6281,10 @@ const TypeAryKlassPtr* TypeAryKlassPtr::cast_to_exactness(bool klass_is_exact) c } else { // cast_to_exactness(false) means get the TypeAryKlassPtr representing all values that subtype // this value - bool not_inline = !_elem->isa_instklassptr() || !_elem->is_instklassptr()->instance_klass()->can_be_inline_klass(); - bool not_flat = !UseArrayFlattening || not_inline || - (_elem->isa_instklassptr() && _elem->is_instklassptr()->instance_klass()->is_inlinetype() && !_elem->is_instklassptr()->instance_klass()->maybe_flat_in_array()); - bool not_null_free = not_inline; + bool not_value = !_elem->isa_instklassptr() || !_elem->is_instklassptr()->instance_klass()->can_be_value_klass(); + bool not_flat = !UseArrayFlattening || not_value || + (_elem->isa_instklassptr() && _elem->is_instklassptr()->instance_klass()->is_value_klass() && !_elem->is_instklassptr()->instance_klass()->maybe_flat_in_array()); + bool not_null_free = not_value; bool atomic = not_flat; return make(NotNull, elem, nullptr, _offset, not_flat, not_null_free, false, false, atomic, false); } @@ -6317,10 +6319,10 @@ const TypeAryPtr* TypeAryKlassPtr::as_exact_instance_type(bool klass_change) con null_free = false; // There are asserts that expect us to not be entirely naive about properties. // Only arrays of value classes can be null free. Otherwise, not_null_free == true. That is if the element type - // is not an instance class, or this instance class cannot be an inline type, it's surely not null-restricted. + // is not an instance class, or this instance class cannot be a value type, it's surely not null-restricted. not_null_free = is_java_primitive(elem()->basic_type()) || elem()->isa_aryklassptr() != nullptr || - (elem()->isa_instklassptr() != nullptr && !elem()->is_instklassptr()->can_be_inline_type()); + (elem()->isa_instklassptr() != nullptr && !elem()->is_instklassptr()->can_be_value_type()); bool array_can_be_flat; if (elem()->isa_instklassptr()) { FlatInArray elem_flat_in_array = elem()->is_instklassptr()->flat_in_array(); @@ -6613,7 +6615,7 @@ const TypeTuple* osr_domain() { } // Build a TypeFunc with both the Java-signature view ('sig') and the actual calling- -// convention view ('cc') of inline types. In the signature, an inline type is a single +// convention view ('cc') of value types. In the signature, a value type is a single // oop slot. In the scalarized calling convention, it is expanded to its field // values (plus null marker and optional oop to the heap buffer). // The 'is_call' argument distinguishes between the return signature of a method at calls @@ -6622,18 +6624,18 @@ const TypeTuple* osr_domain() { const TypeFunc* TypeFunc::make(ciMethod* method, bool is_call, bool is_osr_compilation) { Compile* C = Compile::current(); const TypeFunc* tf = nullptr; - // Inline types are not passed/returned by reference, instead each field of - // the inline type is passed/returned as an argument. We maintain two views of + // Value types are not passed/returned by reference, instead each field of + // the value type is passed/returned as an argument. We maintain two views of // the argument/return list here: one based on the signature (with an inline // type argument/return as a single slot), one based on the actual calling - // convention (with an inline type argument/return as a list of its fields). + // convention (with a value type argument/return as a list of its fields). bool has_scalar_args = method->has_scalarized_args() && !is_osr_compilation; // Fall back to the non-scalarized calling convention when compiling a call via a mismatching method if (is_call && method->mismatch()) { has_scalar_args = false; } ciSignature* sig = method->signature(); - bool has_scalar_ret = !method->is_native() && sig->return_type()->is_inlinetype() && sig->return_type()->as_inline_klass()->can_be_returned_as_fields(); + bool has_scalar_ret = !method->is_native() && sig->return_type()->is_value_klass() && sig->return_type()->as_value_klass()->can_be_returned_as_fields(); // Don't cache on scalarized return because the range depends on 'is_call' if (!is_osr_compilation && !has_scalar_ret) { tf = C->last_tf(method); // check cache diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index aa25d0cc9eac..09079419d27f 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -25,7 +25,7 @@ #ifndef SHARE_OPTO_TYPE_HPP #define SHARE_OPTO_TYPE_HPP -#include "ci/ciInlineKlass.hpp" +#include "ci/ciValueKlass.hpp" #include "opto/adlcVMDeps.hpp" #include "opto/compile.hpp" #include "opto/rangeinference.hpp" @@ -360,8 +360,8 @@ class Type { virtual bool is_finite() const; // Has a finite value virtual bool is_nan() const; // Is not a number (NaN) - bool is_inlinetypeptr() const; - virtual ciInlineKlass* inline_klass() const; + bool is_valueklassptr() const; + virtual ciValueKlass* value_klass() const; // Returns this ptr type or the equivalent ptr type for this compressed pointer. const TypePtr* make_ptr() const; @@ -1033,7 +1033,7 @@ class TypeAry : public Type { const TypeInt *_size; // Elements in array const bool _stable; // Are elements @Stable? - // Inline type array properties + // Value type array properties const bool _flat; // Array is flat const bool _not_flat; // Array is never flat const bool _null_free; // Array is null-free @@ -1330,7 +1330,7 @@ class TypePtr : public Type { static FlatInArray compute_flat_in_array_if_unknown(ciInstanceKlass* instance_klass, bool is_exact, FlatInArray old_flat_in_array); - virtual bool can_be_inline_type() const { return false; } + virtual bool can_be_value_type() const { return false; } virtual bool is_flat_in_array() const { return flat_in_array() == Flat; } virtual bool is_not_flat_in_array() const { return flat_in_array() == NotFlat; } virtual FlatInArray flat_in_array() const { return NotFlat; } @@ -1526,8 +1526,8 @@ class TypeOopPtr : public TypePtr { return instance_id() == t->instance_id(); } - virtual bool can_be_inline_type() const { return (_klass == nullptr || _klass->can_be_inline_klass(_klass_is_exact)); } - virtual bool can_be_inline_array() const { ShouldNotReachHere(); return false; } + virtual bool can_be_value_type() const { return (_klass == nullptr || _klass->can_be_value_klass(_klass_is_exact)); } + virtual bool can_be_value_array() const { ShouldNotReachHere(); return false; } virtual intptr_t get_con() const; @@ -1675,7 +1675,7 @@ class TypeInstPtr : public TypeOopPtr { const TypeKlassPtr* as_klass_type(bool try_for_exact = false) const; - virtual bool can_be_inline_array() const; + virtual bool can_be_value_array() const; // Convenience common pre-built types. static const TypeInstPtr *NOTNULL; @@ -1726,7 +1726,7 @@ class TypeAryPtr : public TypeOopPtr { virtual uint hash() const; // Type specific hashing const TypeAry *_ary; // Array we point into const bool _is_autobox_cache; - // For flat inline type arrays, each field of the inline type in + // For flat value type arrays, each field of the value type in // the array has its own memory slice so we need to keep track of // which field is accessed const Offset _field_offset; @@ -1757,7 +1757,7 @@ class TypeAryPtr : public TypeOopPtr { const TypeInt* size() const { return _ary->_size; } bool is_stable() const { return _ary->_stable; } - // Inline type array properties + // Value type array properties bool is_flat() const { return _ary->_flat; } bool is_not_flat() const { return _ary->_not_flat; } bool is_null_free() const { return _ary->_null_free; } @@ -1804,7 +1804,7 @@ class TypeAryPtr : public TypeOopPtr { virtual const Type* xmeet_helper(const Type* t) const; virtual const Type* xjoin_helper(const Type* t) const; - // Inline type array properties + // Value type array properties const TypeAryPtr* cast_to_flat(bool flat) const; const TypeAryPtr* cast_to_not_flat(bool not_flat = true) const; const TypeAryPtr* cast_to_null_free(bool null_free) const; @@ -1827,10 +1827,10 @@ class TypeAryPtr : public TypeOopPtr { const TypeAryPtr* with_field_offset(int offset) const; const TypePtr* add_field_offset_and_offset(intptr_t offset) const; - virtual bool can_be_inline_type() const { return false; } + virtual bool can_be_value_type() const { return false; } virtual const TypeKlassPtr* as_klass_type(bool try_for_exact = false) const; - virtual bool can_be_inline_array() const; + virtual bool can_be_value_array() const; // Convenience common pre-built types. static const TypeAryPtr* BOTTOM; @@ -1970,7 +1970,7 @@ class TypeKlassPtr : public TypePtr { virtual const TypeKlassPtr* with_offset(intptr_t offset) const { ShouldNotReachHere(); return nullptr; } - virtual bool can_be_inline_array() const { ShouldNotReachHere(); return false; } + virtual bool can_be_value_array() const { ShouldNotReachHere(); return false; } virtual const TypeKlassPtr* try_improve() const { return this; } @@ -2018,7 +2018,7 @@ class TypeInstKlassPtr : public TypeKlassPtr { bool is_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const; bool maybe_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const; - virtual bool can_be_inline_type() const { return (_klass == nullptr || _klass->can_be_inline_klass(klass_is_exact())); } + virtual bool can_be_value_type() const { return (_klass == nullptr || _klass->can_be_value_klass(klass_is_exact())); } static const TypeInstKlassPtr *make(ciKlass* k, InterfaceHandling interface_handling) { const TypeInterfaces* interfaces = TypePtr::interfaces(k, true, true, false, interface_handling); @@ -2054,7 +2054,7 @@ class TypeInstKlassPtr : public TypeKlassPtr { virtual FlatInArray flat_in_array() const { return _flat_in_array; } - virtual bool can_be_inline_array() const; + virtual bool can_be_value_array() const; // Convenience common pre-built types. static const TypeInstKlassPtr* OBJECT; // Not-null object klass or below @@ -2142,7 +2142,7 @@ class TypeAryKlassPtr : public TypeKlassPtr { bool is_not_null_free() const { return _not_null_free; } bool is_atomic() const { return _atomic; } bool is_refined_type() const { return _refined_type; } - virtual bool can_be_inline_array() const; + virtual bool can_be_value_array() const; // Convenience common pre-built types. static const TypeAryKlassPtr* OBJECT_ARRAY; // Not-null object array klass @@ -2285,15 +2285,15 @@ class TypeFunc : public Type { virtual bool singleton(void) const; // TRUE if type is a singleton virtual bool empty(void) const; // TRUE if type is vacuous - // Domains of inputs: inline type arguments are not passed by - // reference, instead each field of the inline type is passed as an + // Domains of inputs: value type arguments are not passed by + // reference, instead each field of the value type is passed as an // argument. We maintain 2 views of the argument list here: one - // based on the signature (with an inline type argument as a single + // based on the signature (with a value type argument as a single // slot), one based on the actual calling convention (with a value // type argument as a list of its fields). const TypeTuple* const _domain_sig; const TypeTuple* const _domain_cc; - // Range of results. Similar to domains: an inline type result can be + // Range of results. Similar to domains: a value type result can be // returned in registers in which case range_cc lists all fields and // is the actual calling convention. const TypeTuple* const _range_sig; @@ -2325,7 +2325,7 @@ class TypeFunc : public Type { BasicType return_type() const; - bool returns_inline_type_as_fields() const { + bool returns_value_type_as_fields() const { // First condition is not sufficient because returned value class can be empty assert(_range_sig == _range_cc || _scalarized_return, "Only possible with scalarized return"); return _scalarized_return; @@ -2607,12 +2607,12 @@ inline bool Type::is_floatingpoint() const { return false; } -inline bool Type::is_inlinetypeptr() const { - return isa_instptr() != nullptr && is_instptr()->instance_klass()->is_inlinetype(); +inline bool Type::is_valueklassptr() const { + return isa_instptr() != nullptr && is_instptr()->instance_klass()->is_value_klass(); } -inline ciInlineKlass* Type::inline_klass() const { - return make_ptr()->is_instptr()->instance_klass()->as_inline_klass(); +inline ciValueKlass* Type::value_klass() const { + return make_ptr()->is_instptr()->instance_klass()->as_value_klass(); } template <> diff --git a/src/hotspot/share/opto/inlinetypenode.cpp b/src/hotspot/share/opto/valuetypenode.cpp similarity index 80% rename from src/hotspot/share/opto/inlinetypenode.cpp rename to src/hotspot/share/opto/valuetypenode.cpp index 48dc5ec1562e..b27434189792 100644 --- a/src/hotspot/share/opto/inlinetypenode.cpp +++ b/src/hotspot/share/opto/valuetypenode.cpp @@ -22,7 +22,7 @@ * */ -#include "ci/ciInlineKlass.hpp" +#include "ci/ciValueKlass.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/c2/barrierSetC2.hpp" #include "gc/shared/gc_globals.hpp" @@ -34,7 +34,6 @@ #include "opto/compile.hpp" #include "opto/convertnode.hpp" #include "opto/graphKit.hpp" -#include "opto/inlinetypenode.hpp" #include "opto/memnode.hpp" #include "opto/movenode.hpp" #include "opto/multnode.hpp" @@ -46,19 +45,20 @@ #include "opto/rootnode.hpp" #include "opto/subnode.hpp" #include "opto/type.hpp" +#include "opto/valuetypenode.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/growableArray.hpp" #include "utilities/pair.hpp" #include "utilities/tuple.hpp" -// Clones the inline type to handle control flow merges involving multiple inline types. +// Clones the value type to handle control flow merges involving multiple value types. // The inputs are replaced by PhiNodes to represent the merged values for the given region. -// init_with_top: input of phis above the returned InlineTypeNode are initialized to top. -InlineTypeNode* InlineTypeNode::clone_with_phis(PhaseGVN* gvn, Node* region, SafePointNode* map, bool is_non_null, bool init_with_top) { - InlineTypeNode* vt = clone_if_required(gvn, map); - const Type* t = Type::get_const_type(inline_klass()); +// init_with_top: input of phis above the returned ValueTypeNode are initialized to top. +ValueTypeNode* ValueTypeNode::clone_with_phis(PhaseGVN* gvn, Node* region, SafePointNode* map, bool is_non_null, bool init_with_top) { + ValueTypeNode* vt = clone_if_required(gvn, map); + const Type* t = Type::get_const_type(value_klass()); gvn->set_type(vt, t); - vt->as_InlineType()->set_type(t); + vt->as_ValueType()->set_type(t); Node* const top = gvn->C->top(); @@ -94,7 +94,7 @@ InlineTypeNode* InlineTypeNode::clone_with_phis(PhaseGVN* gvn, Node* region, Saf Node* value = vt->field_value(i); if (field->is_flat()) { // Handle flat fields recursively - value = value->as_InlineType()->clone_with_phis(gvn, region, map); + value = value->as_ValueType()->clone_with_phis(gvn, region, map); } else { t = Type::get_const_type(type); value = PhiNode::make(region, init_with_top ? top : value, t); @@ -107,9 +107,9 @@ InlineTypeNode* InlineTypeNode::clone_with_phis(PhaseGVN* gvn, Node* region, Saf return vt; } -// Checks if the inputs of the InlineTypeNode were replaced by PhiNodes -// for the given region (see InlineTypeNode::clone_with_phis). -bool InlineTypeNode::has_phi_inputs(Node* region) const { +// Checks if the inputs of the ValueTypeNode were replaced by PhiNodes +// for the given region (see ValueTypeNode::clone_with_phis). +bool ValueTypeNode::has_phi_inputs(Node* region) const { // Check oop input bool result = get_oop()->is_Phi() && get_oop()->as_Phi()->region() == region; #ifdef ASSERT @@ -117,8 +117,8 @@ bool InlineTypeNode::has_phi_inputs(Node* region) const { // Check all field value inputs for consistency for (uint i = 0; i < field_count(); ++i) { Node* n = field_value(i); - if (n->is_InlineType()) { - assert(n->as_InlineType()->has_phi_inputs(region), "inconsistent phi inputs"); + if (n->is_ValueType()) { + assert(n->as_ValueType()->has_phi_inputs(region), "inconsistent phi inputs"); } else { assert(n->is_Phi() && n->as_Phi()->region() == region, "inconsistent phi inputs"); } @@ -129,8 +129,8 @@ bool InlineTypeNode::has_phi_inputs(Node* region) const { } // Merges 'this' with 'other' by updating the input PhiNodes added by 'clone_with_phis' -InlineTypeNode* InlineTypeNode::merge_with(PhaseGVN* gvn, const InlineTypeNode* other, int phi_index, bool transform) { - assert(inline_klass() == other->inline_klass(), "Merging incompatible types"); +ValueTypeNode* ValueTypeNode::merge_with(PhaseGVN* gvn, const ValueTypeNode* other, int phi_index, bool transform) { + assert(value_klass() == other->value_klass(), "Merging incompatible types"); // Merge oop inputs PhiNode* phi = get_oop()->as_Phi(); @@ -155,7 +155,7 @@ InlineTypeNode* InlineTypeNode::merge_with(PhaseGVN* gvn, const InlineTypeNode* set_req(NullMarker, gvn->transform(phi)); } } else { - assert(null_marker->find_int_con(0) == 1, "only with a non null inline type"); + assert(null_marker->find_int_con(0) == 1, "only with a non null value type"); } // Merge field values @@ -171,8 +171,8 @@ InlineTypeNode* InlineTypeNode::merge_with(PhaseGVN* gvn, const InlineTypeNode* val2 = gvn->transform(val2); } - assert(val1->is_InlineType() && val2->is_InlineType(), "must be InlineTypeNode: %s - %s", val1->Name(), val2->Name()); - val1->as_InlineType()->merge_with(gvn, val2->as_InlineType(), phi_index, transform); + assert(val1->is_ValueType() && val2->is_ValueType(), "must be ValueTypeNode: %s - %s", val1->Name(), val2->Name()); + val1->as_ValueType()->merge_with(gvn, val2->as_ValueType(), phi_index, transform); } else { assert(val1->is_Phi(), "must be a phi node %s", val1->Name()); val1->set_req(phi_index, val2); @@ -184,8 +184,8 @@ InlineTypeNode* InlineTypeNode::merge_with(PhaseGVN* gvn, const InlineTypeNode* return this; } -// Adds a new merge path to an inline type node with phi inputs -void InlineTypeNode::add_new_path(Node* region) const { +// Adds a new merge path to a value type node with phi inputs +void ValueTypeNode::add_new_path(Node* region) const { assert(has_phi_inputs(region), "must have phi inputs"); PhiNode* phi = get_oop()->as_Phi(); @@ -202,8 +202,8 @@ void InlineTypeNode::add_new_path(Node* region) const { for (uint i = 0; i < field_count(); ++i) { Node* val = field_value(i); - if (val->is_InlineType()) { - val->as_InlineType()->add_new_path(region); + if (val->is_ValueType()) { + val->as_ValueType()->add_new_path(region); } else { val->as_Phi()->add_req(nullptr); assert(val->req() == region->req(), "must be same size as region"); @@ -211,20 +211,20 @@ void InlineTypeNode::add_new_path(Node* region) const { } } -Node* InlineTypeNode::field_value(uint index) const { +Node* ValueTypeNode::field_value(uint index) const { assert(index < field_count(), "index out of bounds"); return in(Values + index); } // Get the value of the field at the given offset. -// If 'recursive' is true, flat inline type fields will be resolved recursively. -Node* InlineTypeNode::field_value_by_offset(int offset, bool recursive) const { +// If 'recursive' is true, flat value type fields will be resolved recursively. +Node* ValueTypeNode::field_value_by_offset(int offset, bool recursive) const { // Find the declared field which contains the field we are looking for - int index = inline_klass()->field_index_by_offset(offset); + int index = value_klass()->field_index_by_offset(offset); Node* value = field_value(index); assert(value != nullptr, "field value not found"); ciField* field = this->field(index); - assert(!field->is_flat() || field->type()->is_inlinetype(), "must be an inline type"); + assert(!field->is_flat() || field->type()->is_value_klass(), "must be a value type"); if (value->is_top()) { // The graph is dying but a load may still ask for a nested field @@ -237,47 +237,47 @@ Node* InlineTypeNode::field_value_by_offset(int offset, bool recursive) const { return value; } - // Flat inline type field - InlineTypeNode* vt = value->as_InlineType(); + // Flat value type field + ValueTypeNode* vt = value->as_ValueType(); assert(field->is_flat(), "must be flat"); if (offset == field->null_marker_offset()) { return vt->get_null_marker(); } else { int sub_offset = offset - field->offset_in_bytes(); // Offset of the flattened field inside the declared field - sub_offset += vt->inline_klass()->payload_offset(); // Add header size + sub_offset += vt->value_klass()->payload_offset(); // Add header size return vt->field_value_by_offset(sub_offset, recursive); } } -void InlineTypeNode::set_field_value(uint index, Node* value) { +void ValueTypeNode::set_field_value(uint index, Node* value) { assert(index < field_count(), "index out of bounds"); set_req(Values + index, value); } -void InlineTypeNode::set_field_value_by_offset(int offset, Node* value) { +void ValueTypeNode::set_field_value_by_offset(int offset, Node* value) { set_field_value(field_index(offset), value); } -uint InlineTypeNode::field_index(int offset) const { +uint ValueTypeNode::field_index(int offset) const { uint i = 0; for (; i < field_count() && field(i)->offset_in_bytes() != offset; i++) { } assert(i < field_count(), "field not found"); return i; } -ciField* InlineTypeNode::field(uint index) const { +ciField* ValueTypeNode::field(uint index) const { assert(index < field_count(), "index out of bounds"); - return inline_klass()->declared_nonstatic_field_at(index); + return value_klass()->declared_nonstatic_field_at(index); } -uint InlineTypeNode::add_fields_to_safepoint(Unique_Node_List& worklist, SafePointNode* sfpt) const { +uint ValueTypeNode::add_fields_to_safepoint(Unique_Node_List& worklist, SafePointNode* sfpt) const { uint cnt = 0; for (uint i = 0; i < field_count(); ++i) { Node* value = field_value(i); ciField* field = this->field(i); - assert(!field->is_flat() || field->type()->is_inlinetype(), "must be an inline type"); + assert(!field->is_flat() || field->type()->is_value_klass(), "must be a value type"); if (field->is_flat()) { - InlineTypeNode* vt = value->as_InlineType(); + ValueTypeNode* vt = value->as_ValueType(); cnt += vt->add_fields_to_safepoint(worklist, sfpt); if (!field->is_null_free()) { // The null marker of a flat field is added right after we scalarize that field @@ -286,8 +286,8 @@ uint InlineTypeNode::add_fields_to_safepoint(Unique_Node_List& worklist, SafePoi } continue; } - if (value->is_InlineType()) { - // Add inline type to the worklist to process later + if (value->is_ValueType()) { + // Add value type to the worklist to process later worklist.push(value); } sfpt->add_req(value); @@ -296,13 +296,13 @@ uint InlineTypeNode::add_fields_to_safepoint(Unique_Node_List& worklist, SafePoi return cnt; } -void InlineTypeNode::make_scalar_in_safepoint(PhaseIterGVN* igvn, Unique_Node_List& worklist, SafePointNode* sfpt) const { +void ValueTypeNode::make_scalar_in_safepoint(PhaseIterGVN* igvn, Unique_Node_List& worklist, SafePointNode* sfpt) const { JVMState* jvms = sfpt->jvms(); assert(jvms != nullptr, "missing JVMS"); uint first_ind = (sfpt->req() - jvms->scloff()); - // Iterate over the inline type fields in order of increasing offset and add the - // field values to the safepoint. Nullable inline types have a null marker field that + // Iterate over the value type fields in order of increasing offset and add the + // field values to the safepoint. Nullable value types have a null marker field that // needs to be checked before using the field values. sfpt->add_req(get_null_marker()); uint nfields = add_fields_to_safepoint(worklist, sfpt); @@ -324,12 +324,12 @@ void InlineTypeNode::make_scalar_in_safepoint(PhaseIterGVN* igvn, Unique_Node_Li } } -bool InlineTypeNode::make_scalar_in_safepoints(PhaseIterGVN* igvn, bool allow_oop) { +bool ValueTypeNode::make_scalar_in_safepoints(PhaseIterGVN* igvn, bool allow_oop) { return make_scalar_in_safepoints(igvn, allow_oop, nullptr); } -bool InlineTypeNode::make_scalar_in_safepoints(PhaseIterGVN* igvn, bool allow_oop, SafePointNode* safepoint) { - // If the inline type has a constant or loaded oop, use the oop instead of scalarization +bool ValueTypeNode::make_scalar_in_safepoints(PhaseIterGVN* igvn, bool allow_oop, SafePointNode* safepoint) { + // If the value type has a constant or loaded oop, use the oop instead of scalarization // in the safepoint to avoid keeping field loads live just for the debug info. Node* oop = get_oop(); bool use_oop = false; @@ -378,7 +378,7 @@ bool InlineTypeNode::make_scalar_in_safepoints(PhaseIterGVN* igvn, bool allow_oo safepoints.push(safepoint); } - // Scalarize the inline type in all safepoint uses but first check if we + // Scalarize the value type in all safepoint uses but first check if we // have enough nodes left to create a new SafePointScalarObjectNode per use. Compile* C = igvn->C; if ((C->live_nodes() + safepoints.size() + NodeLimitFudgeFactor) > C->max_node_limit()) { @@ -401,7 +401,7 @@ bool InlineTypeNode::make_scalar_in_safepoints(PhaseIterGVN* igvn, bool allow_oo } // Now scalarize non-flat fields for (uint i = 0; i < vt_worklist.size(); ++i) { - InlineTypeNode* vt = vt_worklist.at(i)->isa_InlineType(); + ValueTypeNode* vt = vt_worklist.at(i)->isa_ValueType(); if (!vt->make_scalar_in_safepoints(igvn)) { return false; } @@ -412,21 +412,21 @@ bool InlineTypeNode::make_scalar_in_safepoints(PhaseIterGVN* igvn, bool allow_oo return true; } -void InlineTypeNode::load(GraphKit* kit, Node* base, Node* ptr, bool immutable_memory, bool trust_null_free_oop, DecoratorSet decorators) { - // Initialize the inline type by loading its field values from +void ValueTypeNode::load(GraphKit* kit, Node* base, Node* ptr, bool immutable_memory, bool trust_null_free_oop, DecoratorSet decorators) { + // Initialize the value type by loading its field values from // memory and adding the values as input edges to the node. - ciInlineKlass* vk = inline_klass(); + ciValueKlass* vk = value_klass(); for (uint i = 0; i < field_count(); ++i) { ciField* field = this->field(i); - assert(!field->is_flat() || field->type()->is_inlinetype(), "must be an inline type"); + assert(!field->is_flat() || field->type()->is_value_klass(), "must be a value type"); int field_off = field->offset_in_bytes() - vk->payload_offset(); Node* field_ptr = kit->basic_plus_adr(base, ptr, field_off); Node* value = nullptr; ciType* ft = field->type(); bool field_null_free = field->is_null_free(); if (field->is_flat()) { - // Recursively load the flat inline type field - ciInlineKlass* fvk = ft->as_inline_klass(); + // Recursively load the flat value type field + ciValueKlass* fvk = ft->as_value_klass(); bool atomic = field->is_atomic(); value = make_from_flat_impl(kit, fvk, base, field_ptr, atomic, immutable_memory, field_null_free, trust_null_free_oop && field_null_free, decorators); @@ -445,8 +445,8 @@ void InlineTypeNode::load(GraphKit* kit, Node* base, Node* ptr, bool immutable_m } } -void InlineTypeNode::store_flat(GraphKit* kit, Node* base, Node* ptr, bool atomic, bool immutable_memory, bool null_free, DecoratorSet decorators) { - ciInlineKlass* vk = inline_klass(); +void ValueTypeNode::store_flat(GraphKit* kit, Node* base, Node* ptr, bool atomic, bool immutable_memory, bool null_free, DecoratorSet decorators) { + ciValueKlass* vk = value_klass(); bool do_atomic = atomic; // With immutable memory, a non-atomic load and an atomic load are the same if (immutable_memory) { @@ -471,11 +471,11 @@ void InlineTypeNode::store_flat(GraphKit* kit, Node* base, Node* ptr, bool atomi StoreFlatNode::store(kit, base, ptr, this, null_free, decorators); } -void InlineTypeNode::store_flat_array(GraphKit* kit, Node* base, Node* idx) { +void ValueTypeNode::store_flat_array(GraphKit* kit, Node* base, Node* idx) { PhaseGVN& gvn = kit->gvn(); DecoratorSet decorators = IN_HEAP | IS_ARRAY | MO_UNORDERED; kit->C->set_flat_accesses(); - ciInlineKlass* vk = inline_klass(); + ciValueKlass* vk = value_klass(); assert(vk->maybe_flat_in_array(), "element type %s cannot be flat in array", vk->name()->as_utf8()); RegionNode* region = new RegionNode(4); @@ -552,21 +552,21 @@ void InlineTypeNode::store_flat_array(GraphKit* kit, Node* base, Node* idx) { kit->set_i_o(gvn.transform(io)); } -void InlineTypeNode::store(GraphKit* kit, Node* base, Node* ptr, bool immutable_memory, DecoratorSet decorators) const { +void ValueTypeNode::store(GraphKit* kit, Node* base, Node* ptr, bool immutable_memory, DecoratorSet decorators) const { // Write field values to memory - ciInlineKlass* vk = inline_klass(); + ciValueKlass* vk = value_klass(); for (uint i = 0; i < field_count(); ++i) { ciField* field = this->field(i); - assert(!field->is_flat() || field->type()->is_inlinetype(), "must be an inline type"); + assert(!field->is_flat() || field->type()->is_value_klass(), "must be a value type"); int field_off = field->offset_in_bytes() - vk->payload_offset(); Node* field_val = field_value(i); bool field_null_free = field->is_null_free(); ciType* ft = field->type(); Node* field_ptr = kit->basic_plus_adr(base, ptr, field_off); if (field->is_flat()) { - // Recursively store the flat inline type field + // Recursively store the flat value type field bool atomic = field->is_atomic(); - field_val->as_InlineType()->store_flat(kit, base, field_ptr, atomic, immutable_memory, field_null_free, decorators); + field_val->as_ValueType()->store_flat(kit, base, field_ptr, atomic, immutable_memory, field_null_free, decorators); } else { // Store field value to memory BasicType bt = type2field[ft->basic_type()]; @@ -578,23 +578,23 @@ void InlineTypeNode::store(GraphKit* kit, Node* base, Node* ptr, bool immutable_ } // If a value class contains cycle, bail out from trying to expand substitutability check involving it -static bool check_cycle(ciInlineKlass* vk) { +static bool check_cycle(ciValueKlass* vk) { ResourceMark rm; - GrowableArray> visited; + GrowableArray> visited; visited.push(Pair(vk, 0)); while (visited.is_nonempty()) { - ciInlineKlass* current = visited.top().first; + ciValueKlass* current = visited.top().first; bool finish = true; for (int field_idx = visited.top().second; field_idx < current->nof_nonstatic_fields(); field_idx++) { ciField* field = current->nonstatic_field_at(field_idx); ciType* ft = field->type(); - if (!ft->is_inlinetype()) { + if (!ft->is_value_klass()) { continue; } else if (visited.find_if([&](const auto& entry) { return entry.first == ft; }) >= 0) { return true; } else { visited.top().second = field_idx + 1; - visited.push(Pair(ft->as_inline_klass(), 0)); + visited.push(Pair(ft->as_value_klass(), 0)); finish = false; break; } @@ -606,13 +606,13 @@ static bool check_cycle(ciInlineKlass* vk) { return false; } -// Check if 'lhs' and 'rhs' are the same oop, possibly wrapped in an InlineTypeNode. +// Check if 'lhs' and 'rhs' are the same oop, possibly wrapped in an ValueTypeNode. static bool same_oop(PhaseGVN* phase, Node* lhs, Node* rhs) { - InlineTypeNode* lhs_inline = lhs->isa_InlineType(); + ValueTypeNode* lhs_inline = lhs->isa_ValueType(); if (lhs_inline != nullptr && lhs_inline->is_allocated(phase)) { lhs = lhs_inline->get_oop(); } - InlineTypeNode* rhs_inline = rhs->isa_InlineType(); + ValueTypeNode* rhs_inline = rhs->isa_ValueType(); if (rhs_inline != nullptr && rhs_inline->is_allocated(phase)) { rhs = rhs_inline->get_oop(); } @@ -620,8 +620,8 @@ static bool same_oop(PhaseGVN* phase, Node* lhs, Node* rhs) { } // Check if a substitutability check between 'lhs' and 'rhs' can be implemented in IR -bool InlineTypeNode::can_emit_substitutability_check(PhaseGVN* phase, Node* lhs, Node* rhs) { - // We can't create new InlineTypeNodes after macro expansion +bool ValueTypeNode::can_emit_substitutability_check(PhaseGVN* phase, Node* lhs, Node* rhs) { + // We can't create new ValueTypeNodes after macro expansion if (!phase->C->allow_macro_nodes()) { return false; } @@ -635,33 +635,33 @@ bool InlineTypeNode::can_emit_substitutability_check(PhaseGVN* phase, Node* lhs, return true; } - if (!lhs->bottom_type()->is_ptr()->can_be_inline_type() || - (rhs != nullptr && !rhs->bottom_type()->is_ptr()->can_be_inline_type())) { + if (!lhs->bottom_type()->is_ptr()->can_be_value_type() || + (rhs != nullptr && !rhs->bottom_type()->is_ptr()->can_be_value_type())) { return true; } - if (!lhs->is_InlineType() && (rhs == nullptr || !rhs->is_InlineType())) { + if (!lhs->is_ValueType() && (rhs == nullptr || !rhs->is_ValueType())) { return false; } - if (!lhs->is_InlineType()) { + if (!lhs->is_ValueType()) { swap(lhs, rhs); } - InlineTypeNode* lhs_inline = lhs->as_InlineType(); - InlineTypeNode* rhs_inline = rhs != nullptr ? rhs->isa_InlineType() : nullptr; - if (rhs_inline != nullptr && lhs_inline->type()->inline_klass() != rhs_inline->type()->inline_klass()) { + ValueTypeNode* lhs_inline = lhs->as_ValueType(); + ValueTypeNode* rhs_inline = rhs != nullptr ? rhs->isa_ValueType() : nullptr; + if (rhs_inline != nullptr && lhs_inline->type()->value_klass() != rhs_inline->type()->value_klass()) { // Dead code, can skip the substitutability check return true; } - if (check_cycle(lhs_inline->inline_klass())) { + if (check_cycle(lhs_inline->value_klass())) { return false; } for (uint i = 0; i < lhs_inline->field_count(); i++) { ciType* ft = lhs_inline->field(i)->type(); - if (!ft->can_be_inline_klass()) { + if (!ft->can_be_value_klass()) { continue; } @@ -724,7 +724,7 @@ static Node* emit_substitutability_check_pointer(GraphKit* kit, PhiNode* result, Node* cmp = nullptr; if (same_oop(&gvn, lhs, rhs)) { cmp = kit->intcon(0); - } else if (!lhs_type->is_ptr()->can_be_inline_type() || !rhs_type->is_ptr()->can_be_inline_type()) { + } else if (!lhs_type->is_ptr()->can_be_value_type() || !rhs_type->is_ptr()->can_be_value_type()) { // If one of the sides is not a value object, can only be substitutable if they are the same cmp = kit->CmpP(lhs, rhs); } else if (lhs_type->is_instptr()->as_klass_type()->join(rhs_type->is_instptr()->as_klass_type())->empty()) { @@ -746,12 +746,12 @@ static Node* emit_substitutability_check_pointer(GraphKit* kit, PhiNode* result, return iff_true; } - if (!lhs_type->is_inlinetypeptr() && !rhs_type->is_inlinetypeptr()) { + if (!lhs_type->is_valueklassptr() && !rhs_type->is_valueklassptr()) { return nullptr; } // A cycle, give up - ciInlineKlass* vk = lhs_type->is_inlinetypeptr() ? lhs_type->inline_klass() : rhs_type->inline_klass(); + ciValueKlass* vk = lhs_type->is_valueklassptr() ? lhs_type->value_klass() : rhs_type->value_klass(); if (check_cycle(vk)) { return nullptr; } @@ -759,9 +759,9 @@ static Node* emit_substitutability_check_pointer(GraphKit* kit, PhiNode* result, return NodeSentinel; } -Node* InlineTypeNode::emit_substitutability_check(GraphKit* kit, Node* lhs, Node* rhs) { +Node* ValueTypeNode::emit_substitutability_check(GraphKit* kit, Node* lhs, Node* rhs) { if (!kit->C->allow_macro_nodes()) { - // After macro expansion, InlineTypeNodes are also eliminated, creation of new ones then is not + // After macro expansion, ValueTypeNodes are also eliminated, creation of new ones then is not // allowed return nullptr; } @@ -785,20 +785,20 @@ Node* InlineTypeNode::emit_substitutability_check(GraphKit* kit, Node* lhs, Node const Type* lhs_type = igvn.type(lhs); const Type* rhs_type = igvn.type(rhs); assert(!lhs_type->maybe_null() && !rhs_type->maybe_null(), "must check null beforehand"); - ciInlineKlass* vk = lhs_type->is_inlinetypeptr() ? lhs_type->inline_klass() : rhs_type->inline_klass(); + ciValueKlass* vk = lhs_type->is_valueklassptr() ? lhs_type->value_klass() : rhs_type->value_klass(); const TypeInstPtr* vk_type = TypeOopPtr::make_from_klass(vk)->join(TypePtr::NOTNULL)->is_instptr(); - if (!lhs->is_InlineType()) { + if (!lhs->is_ValueType()) { if (!lhs_type->higher_equal(vk_type)) { lhs = igvn.transform(new CheckCastPPNode(kit->control(), lhs, vk_type, ConstraintCastNode::DependencyType::NonFloatingNarrowing)); } - lhs = InlineTypeNode::make_from_oop(kit, lhs, vk); + lhs = ValueTypeNode::make_from_oop(kit, lhs, vk); } - if (!rhs->is_InlineType()) { + if (!rhs->is_ValueType()) { if (!rhs_type->higher_equal(vk_type)) { rhs = igvn.transform(new CheckCastPPNode(kit->control(), rhs, vk_type, ConstraintCastNode::DependencyType::NonFloatingNarrowing)); } - rhs = InlineTypeNode::make_from_oop(kit, rhs, vk); + rhs = ValueTypeNode::make_from_oop(kit, rhs, vk); } RegionNode* true_region = new RegionNode(3); @@ -851,26 +851,26 @@ Node* InlineTypeNode::emit_substitutability_check(GraphKit* kit, Node* lhs, Node // region for the substitutability check of that field when both sides are notnull, save them on // the worklist to process them later. ResourceMark rm; - using WorklistEntry = Tuple; + using WorklistEntry = Tuple; GrowableArray worklist; - worklist.push(WorklistEntry(kit->control(), true_region, lhs->as_InlineType(), rhs->as_InlineType())); + worklist.push(WorklistEntry(kit->control(), true_region, lhs->as_ValueType(), rhs->as_ValueType())); while (worklist.is_nonempty()) { WorklistEntry entry = worklist.pop(); Node* cur_start_region = entry.get<0>(); RegionNode* cur_true_region = entry.get<1>(); - InlineTypeNode* cur_lhs = entry.get<2>(); - InlineTypeNode* cur_rhs = entry.get<3>(); + ValueTypeNode* cur_lhs = entry.get<2>(); + ValueTypeNode* cur_rhs = entry.get<3>(); kit->set_control(cur_start_region); if (kit->stopped()) { break; } - ciInlineKlass* vk = cur_lhs->inline_klass(); - assert(vk == cur_rhs->inline_klass(), "should not reach here otherwise"); + ciValueKlass* vk = cur_lhs->value_klass(); + assert(vk == cur_rhs->value_klass(), "should not reach here otherwise"); auto is_simple_field = [](ciField* field) { ciType* ft = field->type(); - return is_java_primitive(ft->basic_type()) || !ft->as_klass()->can_be_inline_klass(); + return is_java_primitive(ft->basic_type()) || !ft->as_klass()->can_be_value_klass(); }; // Go through all fields, process the simple ones first @@ -892,8 +892,8 @@ Node* InlineTypeNode::emit_substitutability_check(GraphKit* kit, Node* lhs, Node Node* cur_lhs_field = cur_lhs->field_value(field_idx); Node* cur_rhs_field = cur_rhs->field_value(field_idx); - InlineTypeNode* cur_lhs_inline = cur_lhs_field->isa_InlineType(); - InlineTypeNode* cur_rhs_inline = cur_rhs_field->isa_InlineType(); + ValueTypeNode* cur_lhs_inline = cur_lhs_field->isa_ValueType(); + ValueTypeNode* cur_rhs_inline = cur_rhs_field->isa_ValueType(); Node* preprocess = emit_substitutability_check_pointer(kit, result, cur_lhs_field, cur_rhs_field); if (kit->stopped()) { @@ -975,13 +975,13 @@ Node* InlineTypeNode::emit_substitutability_check(GraphKit* kit, Node* lhs, Node // Can expand this comparison const Type* cur_lhs_field_type = igvn.type(cur_lhs_field); const Type* cur_rhs_field_type = igvn.type(cur_rhs_field); - ciInlineKlass* vk = cur_lhs_field_type->is_inlinetypeptr() ? cur_lhs_field_type->inline_klass() : cur_rhs_field_type->inline_klass(); + ciValueKlass* vk = cur_lhs_field_type->is_valueklassptr() ? cur_lhs_field_type->value_klass() : cur_rhs_field_type->value_klass(); const TypeInstKlassPtr* vk_klass_type = TypeInstKlassPtr::make(vk, Type::ignore_interfaces); Node* vk_klass = igvn.makecon(vk_klass_type); // Both must be vk - // InlineTypeNodes need no (new) field loads, so we can use the uncasted value below. - if (cur_lhs_inline != nullptr && cur_lhs_inline->inline_klass() == vk) { + // ValueTypeNodes need no (new) field loads, so we can use the uncasted value below. + if (cur_lhs_inline != nullptr && cur_lhs_inline->value_klass() == vk) { cur_lhs_field = cur_lhs_inline; } else { Node* not_vk = kit->top(); @@ -990,10 +990,10 @@ Node* InlineTypeNode::emit_substitutability_check(GraphKit* kit, Node* lhs, Node region->add_req(not_vk); result->add_req(igvn.intcon(0)); } - cur_lhs_field = InlineTypeNode::make_from_oop(kit, cur_lhs_field, vk); + cur_lhs_field = ValueTypeNode::make_from_oop(kit, cur_lhs_field, vk); } - if (cur_rhs_inline != nullptr && cur_rhs_inline->inline_klass() == vk) { + if (cur_rhs_inline != nullptr && cur_rhs_inline->value_klass() == vk) { cur_rhs_field = cur_rhs_inline; } else { Node* not_vk = kit->top(); @@ -1002,12 +1002,12 @@ Node* InlineTypeNode::emit_substitutability_check(GraphKit* kit, Node* lhs, Node region->add_req(not_vk); result->add_req(igvn.intcon(0)); } - cur_rhs_field = InlineTypeNode::make_from_oop(kit, cur_rhs_field, vk); + cur_rhs_field = ValueTypeNode::make_from_oop(kit, cur_rhs_field, vk); } if (!kit->stopped()) { - // Push the expanded InlineTypeNodes for processing later - worklist.push(WorklistEntry(kit->control(), field_true_region, cur_lhs_field->as_InlineType(), cur_rhs_field->as_InlineType())); + // Push the expanded ValueTypeNodes for processing later + worklist.push(WorklistEntry(kit->control(), field_true_region, cur_lhs_field->as_ValueType(), cur_rhs_field->as_ValueType())); } kit->set_control(field_true_region); @@ -1024,15 +1024,15 @@ Node* InlineTypeNode::emit_substitutability_check(GraphKit* kit, Node* lhs, Node // Check if identityHashCode of 'arg' can be implemented in IR. // Set klass_hash to be used as the seed of the hash. It might not be available later, // and we want emit_identity_hash_code not to fail on that. -bool InlineTypeNode::can_emit_identity_hash_code(const PhaseIterGVN& igvn, Node* arg, intptr_t& klass_hash) { +bool ValueTypeNode::can_emit_identity_hash_code(const PhaseIterGVN& igvn, Node* arg, intptr_t& klass_hash) { const Type* arg_type = igvn.type(arg); if (arg_type == TypePtr::NULL_PTR) { return true; } - if (!arg_type->is_inlinetypeptr()) { + if (!arg_type->is_valueklassptr()) { return false; } - ciInlineKlass* vk = arg_type->inline_klass(); + ciValueKlass* vk = arg_type->value_klass(); if (vk->number_of_oop_entries_in_acmp_map() > 0) { return false; } @@ -1043,9 +1043,9 @@ bool InlineTypeNode::can_emit_identity_hash_code(const PhaseIterGVN& igvn, Node* return true; } -Node* InlineTypeNode::emit_identity_hash_code(GraphKit* kit, Node* arg, intptr_t klass_hash) { +Node* ValueTypeNode::emit_identity_hash_code(GraphKit* kit, Node* arg, intptr_t klass_hash) { if (!kit->C->allow_macro_nodes()) { - // After macro expansion, InlineTypeNodes are also eliminated, creation of new ones then is not + // After macro expansion, ValueTypeNodes are also eliminated, creation of new ones then is not // allowed return nullptr; } @@ -1068,9 +1068,9 @@ Node* InlineTypeNode::emit_identity_hash_code(GraphKit* kit, Node* arg, intptr_t return phi_result; } - assert(arg_type->is_inlinetypeptr(), "should be a value object at this point"); + assert(arg_type->is_valueklassptr(), "should be a value object at this point"); assert(!arg_type->maybe_null(), "must check null beforehand"); - ciInlineKlass* vk = arg_type->inline_klass(); + ciValueKlass* vk = arg_type->value_klass(); int number_of_nonoop_entries = vk->number_of_nonoop_entries_in_acmp_map(); assert(vk->number_of_oop_entries_in_acmp_map() == 0, "cannot have oops here"); @@ -1130,20 +1130,20 @@ Node* InlineTypeNode::emit_identity_hash_code(GraphKit* kit, Node* arg, intptr_t return phi_result; } -InlineTypeNode* InlineTypeNode::buffer(GraphKit* kit, bool safe_for_replace) { +ValueTypeNode* ValueTypeNode::buffer(GraphKit* kit, bool safe_for_replace) { if (is_allocated(&kit->gvn())) { // Already buffered return this; } - // Check if inline type is already buffered + // Check if value type is already buffered Node* not_buffered_ctl = kit->top(); Node* not_null_oop = kit->null_check_oop(get_oop(), ¬_buffered_ctl, /* never_see_null = */ false, safe_for_replace); if (not_buffered_ctl->is_top()) { // Already buffered - InlineTypeNode* vt = clone_if_required(&kit->gvn(), kit->map(), safe_for_replace); + ValueTypeNode* vt = clone_if_required(&kit->gvn(), kit->map(), safe_for_replace); vt->set_is_buffered(kit->gvn()); - vt = kit->gvn().transform(vt)->as_InlineType(); + vt = kit->gvn().transform(vt)->as_ValueType(); if (safe_for_replace) { kit->replace_in_map(this, vt); } @@ -1152,7 +1152,7 @@ InlineTypeNode* InlineTypeNode::buffer(GraphKit* kit, bool safe_for_replace) { Node* buffered_ctl = kit->control(); kit->set_control(not_buffered_ctl); - // Inline type is not buffered, check if it is null. + // Value type is not buffered, check if it is null. Node* null_ctl = kit->top(); kit->null_check_common(get_null_marker(), T_INT, false, &null_ctl); bool null_free = null_ctl->is_top(); @@ -1160,11 +1160,11 @@ InlineTypeNode* InlineTypeNode::buffer(GraphKit* kit, bool safe_for_replace) { RegionNode* region = new RegionNode(4); PhiNode* oop = PhiNode::make(region, not_null_oop, type()->join_speculative(null_free ? TypePtr::NOTNULL : TypePtr::BOTTOM)); - // InlineType is already buffered + // ValueType is already buffered region->init_req(1, buffered_ctl); oop->init_req(1, not_null_oop); - // InlineType is null + // ValueType is null region->init_req(2, null_ctl); oop->init_req(2, kit->gvn().zerocon(T_OBJECT)); @@ -1174,7 +1174,7 @@ InlineTypeNode* InlineTypeNode::buffer(GraphKit* kit, bool safe_for_replace) { if (!kit->stopped()) { assert(!is_allocated(&kit->gvn()), "already buffered"); PreserveJVMState pjvms(kit); - ciInlineKlass* vk = inline_klass(); + ciValueKlass* vk = value_klass(); // Allocate and initialize buffer, re-execute on deoptimization. kit->jvms()->set_bci(kit->bci()); kit->jvms()->set_should_reexecute(true); @@ -1204,23 +1204,23 @@ InlineTypeNode* InlineTypeNode::buffer(GraphKit* kit, bool safe_for_replace) { kit->record_for_igvn(io); kit->record_for_igvn(mem); - // Use cloned InlineTypeNode to propagate oop from now on + // Use cloned ValueTypeNode to propagate oop from now on Node* res_oop = kit->gvn().transform(oop); - InlineTypeNode* vt = clone_if_required(&kit->gvn(), kit->map(), safe_for_replace); + ValueTypeNode* vt = clone_if_required(&kit->gvn(), kit->map(), safe_for_replace); vt->set_oop(kit->gvn(), res_oop); vt->set_is_buffered(kit->gvn()); - vt = kit->gvn().transform(vt)->as_InlineType(); + vt = kit->gvn().transform(vt)->as_ValueType(); kit->record_for_igvn(vt); if (safe_for_replace) { kit->replace_in_map(this, vt); } - // InlineTypeNode::remove_redundant_allocations piggybacks on split if. + // ValueTypeNode::remove_redundant_allocations piggybacks on split if. // Make sure it gets a chance to remove this allocation. kit->C->set_has_split_ifs(true); return vt; } -bool InlineTypeNode::is_allocated(PhaseGVN* phase) const { +bool ValueTypeNode::is_allocated(PhaseGVN* phase) const { if (phase->type(get_is_buffered()) == TypeInt::ONE) { return true; } @@ -1246,9 +1246,9 @@ static void replace_proj(Compile* C, CallNode* call, uint& proj_idx, Node* value // When a call returns multiple values, it has several result // projections, one per field. Replacing the result of the call by an -// inline type node (after late inlining) requires that for each result -// projection, we find the corresponding inline type field. -void InlineTypeNode::replace_call_results(GraphKit* kit, CallNode* call, Compile* C) const { +// value type node (after late inlining) requires that for each result +// projection, we find the corresponding value type field. +void ValueTypeNode::replace_call_results(GraphKit* kit, CallNode* call, Compile* C) const { uint proj_idx = TypeFunc::Parms; // Replace oop projection replace_proj(C, call, proj_idx, get_oop(), T_OBJECT); @@ -1259,13 +1259,13 @@ void InlineTypeNode::replace_call_results(GraphKit* kit, CallNode* call, Compile assert(proj_idx == call->tf()->range_cc()->cnt(), "missed a projection"); } -void InlineTypeNode::replace_field_projs(Compile* C, CallNode* call, uint& proj_idx) const { +void ValueTypeNode::replace_field_projs(Compile* C, CallNode* call, uint& proj_idx) const { for (uint i = 0; i < field_count(); ++i) { Node* value = field_value(i); ciField* field = this->field(i); - assert(!field->is_flat() || field->type()->is_inlinetype(), "must be an inline type"); + assert(!field->is_flat() || field->type()->is_value_klass(), "must be a value type"); if (field->is_flat()) { - InlineTypeNode* vt = value->as_InlineType(); + ValueTypeNode* vt = value->as_ValueType(); // Replace field projections for flat field vt->replace_field_projs(C, call, proj_idx); if (!field->is_null_free()) { @@ -1279,21 +1279,21 @@ void InlineTypeNode::replace_field_projs(Compile* C, CallNode* call, uint& proj_ } } -InlineTypeNode* InlineTypeNode::allocate_fields(GraphKit* kit) { - InlineTypeNode* vt = clone_if_required(&kit->gvn(), kit->map()); +ValueTypeNode* ValueTypeNode::allocate_fields(GraphKit* kit) { + ValueTypeNode* vt = clone_if_required(&kit->gvn(), kit->map()); for (uint i = 0; i < field_count(); i++) { Node* value = field_value(i); ciField* field = this->field(i); - assert(!field->is_flat() || field->type()->is_inlinetype(), "must be an inline type"); + assert(!field->is_flat() || field->type()->is_value_klass(), "must be a value type"); if (field->is_flat()) { - // Flat inline type field - vt->set_field_value(i, value->as_InlineType()->allocate_fields(kit)); - } else if (value->is_InlineType()) { - // Non-flat inline type field - vt->set_field_value(i, value->as_InlineType()->buffer(kit)); + // Flat value type field + vt->set_field_value(i, value->as_ValueType()->allocate_fields(kit)); + } else if (value->is_ValueType()) { + // Non-flat value type field + vt->set_field_value(i, value->as_ValueType()->buffer(kit)); } } - vt = kit->gvn().transform(vt)->as_InlineType(); + vt = kit->gvn().transform(vt)->as_ValueType(); kit->replace_in_map(this, vt); return vt; } @@ -1326,11 +1326,11 @@ static void replace_allocation(PhaseIterGVN* igvn, Node* res, Node* dom) { igvn->replace_node(res, dom); } -Node* InlineTypeNode::Ideal(PhaseGVN* phase, bool can_reshape) { +Node* ValueTypeNode::Ideal(PhaseGVN* phase, bool can_reshape) { Node* oop = get_oop(); - if (oop->isa_InlineType() && !phase->type(oop)->maybe_null()) { - InlineTypeNode* vtptr = oop->as_InlineType(); - assert(inline_klass() == vtptr->inline_klass(), "inconsistent types"); + if (oop->isa_ValueType() && !phase->type(oop)->maybe_null()) { + ValueTypeNode* vtptr = oop->as_ValueType(); + assert(value_klass() == vtptr->value_klass(), "inconsistent types"); set_oop(*phase, vtptr->get_oop()); set_is_buffered(*phase); set_null_marker(*phase); @@ -1342,17 +1342,17 @@ Node* InlineTypeNode::Ideal(PhaseGVN* phase, bool can_reshape) { // Use base oop if fields are loaded from memory, don't do so if base is the CheckCastPP of an // allocation because the only case we load from a naked CheckCastPP is when we exit a - // constructor of an inline type and we want to relinquish the larval oop there. This has a + // constructor of a value type and we want to relinquish the larval oop there. This has a // couple of benefits: - // - The allocation is likely to be elided earlier if it is not an input of an InlineTypeNode. - // - The InlineTypeNode without an allocation input is more likely to be GVN-ed. This may emerge + // - The allocation is likely to be elided earlier if it is not an input of an ValueTypeNode. + // - The ValueTypeNode without an allocation input is more likely to be GVN-ed. This may emerge // when we try to clone a value object. // - The buffering, if needed, is delayed until it is required. This new allocation, since it is - // created from an InlineTypeNode, is recognized as not having a unique identity and in the + // created from an ValueTypeNode, is recognized as not having a unique identity and in the // future, we can move them around more freely such as hoisting out of loops. This is not true // for the old allocation since larval value objects do have unique identities. Node* base = is_loaded(phase); - if (base != nullptr && !base->is_InlineType() && !phase->type(base)->maybe_null() && phase->C->allow_macro_nodes() && AllocateNode::Ideal_allocation(base) == nullptr) { + if (base != nullptr && !base->is_ValueType() && !phase->type(base)->maybe_null() && phase->C->allow_macro_nodes() && AllocateNode::Ideal_allocation(base) == nullptr) { if (oop != base || !is_allocated(phase)) { set_oop(*phase, base); set_is_buffered(*phase); @@ -1363,19 +1363,19 @@ Node* InlineTypeNode::Ideal(PhaseGVN* phase, bool can_reshape) { if (can_reshape) { PhaseIterGVN* igvn = phase->is_IterGVN(); if (is_allocated(phase)) { - // Search for and remove re-allocations of this inline type. Ignore scalar replaceable ones, + // Search for and remove re-allocations of this value type. Ignore scalar replaceable ones, // they will be removed anyway and changing the memory chain will confuse other optimizations. - // This can happen with late inlining when we first allocate an inline type argument + // This can happen with late inlining when we first allocate a value type argument // but later decide to inline the call after the callee code also triggered allocation. for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) { AllocateNode* alloc = fast_out(i)->isa_Allocate(); - if (alloc != nullptr && alloc->in(AllocateNode::InlineType) == this && !alloc->_is_scalar_replaceable) { + if (alloc != nullptr && alloc->in(AllocateNode::ValueType) == this && !alloc->_is_scalar_replaceable) { // Found a re-allocation Node* res = alloc->result_cast(); if (res != nullptr && res->is_CheckCastPP()) { // Replace allocation by oop and unlink AllocateNode replace_allocation(igvn, res, oop); - igvn->replace_input_of(alloc, AllocateNode::InlineType, igvn->C->top()); + igvn->replace_input_of(alloc, AllocateNode::ValueType, igvn->C->top()); --i; --imax; } } @@ -1386,43 +1386,43 @@ Node* InlineTypeNode::Ideal(PhaseGVN* phase, bool can_reshape) { return nullptr; } -InlineTypeNode* InlineTypeNode::make_uninitialized(PhaseGVN& gvn, ciInlineKlass* vk, bool null_free) { - // Create a new InlineTypeNode with uninitialized values and nullptr oop - InlineTypeNode* vt = new InlineTypeNode(vk, gvn.zerocon(T_OBJECT), null_free); +ValueTypeNode* ValueTypeNode::make_uninitialized(PhaseGVN& gvn, ciValueKlass* vk, bool null_free) { + // Create a new ValueTypeNode with uninitialized values and nullptr oop + ValueTypeNode* vt = new ValueTypeNode(vk, gvn.zerocon(T_OBJECT), null_free); vt->set_is_buffered(gvn, false); vt->set_null_marker(gvn); return vt; } -InlineTypeNode* InlineTypeNode::make_all_zero(PhaseGVN& gvn, ciInlineKlass* vk) { +ValueTypeNode* ValueTypeNode::make_all_zero(PhaseGVN& gvn, ciValueKlass* vk) { return make_all_zero_impl(gvn, vk); } -InlineTypeNode* InlineTypeNode::make_all_zero_impl(PhaseGVN& gvn, ciInlineKlass* vk) { - // Create a new InlineTypeNode initialized with all zero - InlineTypeNode* vt = new InlineTypeNode(vk, gvn.zerocon(T_OBJECT), /* null_free= */ true); +ValueTypeNode* ValueTypeNode::make_all_zero_impl(PhaseGVN& gvn, ciValueKlass* vk) { + // Create a new ValueTypeNode initialized with all zero + ValueTypeNode* vt = new ValueTypeNode(vk, gvn.zerocon(T_OBJECT), /* null_free= */ true); vt->set_is_buffered(gvn, false); vt->set_null_marker(gvn); for (uint i = 0; i < vt->field_count(); ++i) { ciField* field = vt->field(i); - assert(!field->is_flat() || field->type()->is_inlinetype(), "must be an inline type"); + assert(!field->is_flat() || field->type()->is_value_klass(), "must be a value type"); ciType* ft = field->type(); Node* value; if (field->is_null_free()) { - value = make_all_zero_impl(gvn, ft->as_inline_klass()); + value = make_all_zero_impl(gvn, ft->as_value_klass()); } else if (field->is_flat()) { - value = make_null_impl(gvn, ft->as_inline_klass()); + value = make_null_impl(gvn, ft->as_value_klass()); } else { value = gvn.zerocon(ft->basic_type()); } vt->set_field_value(i, value); } - vt = gvn.transform(vt)->as_InlineType(); - assert(vt->is_all_zero(&gvn), "must be the all-zero inline type"); + vt = gvn.transform(vt)->as_ValueType(); + assert(vt->is_all_zero(&gvn), "must be the all-zero value type"); return vt; } -bool InlineTypeNode::is_all_zero(PhaseGVN* gvn, bool flat) const { +bool ValueTypeNode::is_all_zero(PhaseGVN* gvn, bool flat) const { const TypeInt* tinit = gvn->type(get_null_marker())->isa_int(); if (tinit == nullptr || !tinit->is_con(1)) { return false; // May be null @@ -1430,17 +1430,17 @@ bool InlineTypeNode::is_all_zero(PhaseGVN* gvn, bool flat) const { for (uint i = 0; i < field_count(); ++i) { Node* value = field_value(i); ciField* field = this->field(i); - assert(!field->is_flat() || field->type()->is_inlinetype(), "must be an inline type"); + assert(!field->is_flat() || field->type()->is_value_klass(), "must be a value type"); if (field->is_null_free()) { // Null-free value class field must have the all-zero value. If 'flat' is set, // reject non-flat fields because they need to be initialized with an oop to a buffer. - if (!value->is_InlineType() || !value->as_InlineType()->is_all_zero(gvn) || (flat && !field->is_flat())) { + if (!value->is_ValueType() || !value->as_ValueType()->is_all_zero(gvn) || (flat && !field->is_flat())) { return false; } continue; - } else if (value->is_InlineType()) { + } else if (value->is_ValueType()) { // Nullable value class field must be null - tinit = gvn->type(value->as_InlineType()->get_null_marker())->isa_int(); + tinit = gvn->type(value->as_ValueType()->get_null_marker())->isa_int(); if (tinit != nullptr && tinit->is_con(0)) { continue; } @@ -1452,16 +1452,16 @@ bool InlineTypeNode::is_all_zero(PhaseGVN* gvn, bool flat) const { return true; } -InlineTypeNode* InlineTypeNode::make_from_oop(GraphKit* kit, Node* oop, ciInlineKlass* vk) { +ValueTypeNode* ValueTypeNode::make_from_oop(GraphKit* kit, Node* oop, ciValueKlass* vk) { return make_from_oop_impl(kit, oop, vk); } -InlineTypeNode* InlineTypeNode::make_from_oop_impl(GraphKit* kit, Node* oop, ciInlineKlass* vk) { +ValueTypeNode* ValueTypeNode::make_from_oop_impl(GraphKit* kit, Node* oop, ciValueKlass* vk) { PhaseGVN& gvn = kit->gvn(); - // Create and initialize an InlineTypeNode by loading all field + // Create and initialize an ValueTypeNode by loading all field // values from a heap-allocated version and also save the oop. - InlineTypeNode* vt = oop->isa_InlineType(); + ValueTypeNode* vt = oop->isa_ValueType(); if (vt != nullptr) { return vt; } @@ -1481,14 +1481,14 @@ InlineTypeNode* InlineTypeNode::make_from_oop_impl(GraphKit* kit, Node* oop, ciI kit->record_for_igvn(vt); return vt; } - vt = new InlineTypeNode(vk, not_null_oop, /* null_free= */ false); + vt = new ValueTypeNode(vk, not_null_oop, /* null_free= */ false); vt->set_is_buffered(gvn); vt->set_null_marker(gvn); Node* payload_ptr = kit->basic_plus_adr(not_null_oop, vk->payload_offset()); vt->load(kit, not_null_oop, payload_ptr, true, true, IN_HEAP | MO_UNORDERED); if (null_ctl != kit->top()) { - InlineTypeNode* null_vt = make_null_impl(gvn, vk); + ValueTypeNode* null_vt = make_null_impl(gvn, vk); Node* region = new RegionNode(3); region->init_req(1, kit->control()); region->init_req(2, null_ctl); @@ -1500,24 +1500,24 @@ InlineTypeNode* InlineTypeNode::make_from_oop_impl(GraphKit* kit, Node* oop, ciI } } else { // Oop can never be null - vt = new InlineTypeNode(vk, oop, /* null_free= */ true); + vt = new ValueTypeNode(vk, oop, /* null_free= */ true); vt->set_is_buffered(gvn); vt->set_null_marker(gvn); Node* payload_ptr = kit->basic_plus_adr(oop, vk->payload_offset()); vt->load(kit, oop, payload_ptr, true, true, IN_HEAP | MO_UNORDERED); } - assert(vt->is_allocated(&gvn), "inline type should be allocated"); + assert(vt->is_allocated(&gvn), "value type should be allocated"); kit->record_for_igvn(vt); - return gvn.transform(vt)->as_InlineType(); + return gvn.transform(vt)->as_ValueType(); } -InlineTypeNode* InlineTypeNode::make_from_flat(GraphKit* kit, ciInlineKlass* vk, Node* base, Node* ptr, +ValueTypeNode* ValueTypeNode::make_from_flat(GraphKit* kit, ciValueKlass* vk, Node* base, Node* ptr, bool atomic, bool immutable_memory, bool null_free, DecoratorSet decorators) { return make_from_flat_impl(kit, vk, base, ptr, atomic, immutable_memory, null_free, null_free, decorators); } // GraphKit wrapper for the 'make_from_flat' method -InlineTypeNode* InlineTypeNode::make_from_flat_impl(GraphKit* kit, ciInlineKlass* vk, Node* base, Node* ptr, bool atomic, bool immutable_memory, +ValueTypeNode* ValueTypeNode::make_from_flat_impl(GraphKit* kit, ciValueKlass* vk, Node* base, Node* ptr, bool atomic, bool immutable_memory, bool null_free, bool trust_null_free_oop, DecoratorSet decorators) { assert(null_free || !trust_null_free_oop, "cannot trust null-free oop when the holder object is not null-free"); PhaseGVN& gvn = kit->gvn(); @@ -1532,7 +1532,7 @@ InlineTypeNode* InlineTypeNode::make_from_flat_impl(GraphKit* kit, ciInlineKlass } if (!do_atomic) { - InlineTypeNode* vt = make_uninitialized(kit->gvn(), vk, null_free); + ValueTypeNode* vt = make_uninitialized(kit->gvn(), vk, null_free); if (!null_free) { int nm_offset = vk->null_marker_offset_in_payload(); Node* nm_ptr = kit->basic_plus_adr(base, ptr, nm_offset); @@ -1542,22 +1542,22 @@ InlineTypeNode* InlineTypeNode::make_from_flat_impl(GraphKit* kit, ciInlineKlass } vt->load(kit, base, ptr, immutable_memory, trust_null_free_oop, decorators); - return gvn.transform(vt)->as_InlineType(); + return gvn.transform(vt)->as_ValueType(); } assert(!immutable_memory, "immutable memory does not need explicit atomic access"); return LoadFlatNode::load(kit, vk, base, ptr, null_free, trust_null_free_oop, decorators); } -InlineTypeNode* InlineTypeNode::make_from_flat_array(GraphKit* kit, ciInlineKlass* vk, Node* base, Node* idx) { +ValueTypeNode* ValueTypeNode::make_from_flat_array(GraphKit* kit, ciValueKlass* vk, Node* base, Node* idx) { assert(vk->maybe_flat_in_array(), "element type %s cannot be flat in array", vk->name()->as_utf8()); PhaseGVN& gvn = kit->gvn(); // The flat field loads are dependent on both the array layout checks as well as the range check. DecoratorSet decorators = IN_HEAP | IS_ARRAY | MO_UNORDERED | C2_CONTROL_DEPENDENT_LOAD | C2_UNKNOWN_CONTROL_LOAD; kit->C->set_flat_accesses(); - InlineTypeNode* vt_nullable = nullptr; - InlineTypeNode* vt_null_free = nullptr; - InlineTypeNode* vt_non_atomic = nullptr; + ValueTypeNode* vt_nullable = nullptr; + ValueTypeNode* vt_null_free = nullptr; + ValueTypeNode* vt_non_atomic = nullptr; RegionNode* region = new RegionNode(4); gvn.set_type(region, Type::CONTROL); @@ -1584,7 +1584,7 @@ InlineTypeNode* InlineTypeNode::make_from_flat_array(GraphKit* kit, ciInlineKlas kit->set_all_memory(input_memory_state); Node* cast = kit->cast_to_flat_array_exact(base, vk, false, true); Node* ptr = kit->array_element_address(cast, idx, T_FLAT_ELEMENT); - vt_nullable = InlineTypeNode::make_from_flat(kit, vk, cast, ptr, true, false, false, decorators); + vt_nullable = ValueTypeNode::make_from_flat(kit, vk, cast, ptr, true, false, false, decorators); region->init_req(1, kit->control()); mem->set_req(1, kit->reset_memory()); @@ -1606,7 +1606,7 @@ InlineTypeNode* InlineTypeNode::make_from_flat_array(GraphKit* kit, ciInlineKlas kit->set_all_memory(input_memory_state); Node* cast = kit->cast_to_flat_array_exact(base, vk, true, true); Node* ptr = kit->array_element_address(cast, idx, T_FLAT_ELEMENT); - vt_null_free = InlineTypeNode::make_from_flat(kit, vk, cast, ptr, true, false, true, decorators); + vt_null_free = ValueTypeNode::make_from_flat(kit, vk, cast, ptr, true, false, true, decorators); region->init_req(2, kit->control()); mem->set_req(2, kit->reset_memory()); @@ -1620,7 +1620,7 @@ InlineTypeNode* InlineTypeNode::make_from_flat_array(GraphKit* kit, ciInlineKlas kit->set_all_memory(input_memory_state); Node* cast = kit->cast_to_flat_array_exact(base, vk, true, false); Node* ptr = kit->array_element_address(cast, idx, T_FLAT_ELEMENT); - vt_non_atomic = InlineTypeNode::make_from_flat(kit, vk, cast, ptr, false, false, true, decorators); + vt_non_atomic = ValueTypeNode::make_from_flat(kit, vk, cast, ptr, false, false, true, decorators); region->init_req(3, kit->control()); mem->set_req(3, kit->reset_memory()); @@ -1628,7 +1628,7 @@ InlineTypeNode* InlineTypeNode::make_from_flat_array(GraphKit* kit, ciInlineKlas } } - InlineTypeNode* vt = nullptr; + ValueTypeNode* vt = nullptr; if (vt_nullable == nullptr && vt_null_free == nullptr && vt_non_atomic == nullptr) { // All paths are dead vt = make_null(gvn, vk); @@ -1646,7 +1646,7 @@ InlineTypeNode* InlineTypeNode::make_from_flat_array(GraphKit* kit, ciInlineKlas return vt; } - InlineTypeNode* zero = InlineTypeNode::make_null(gvn, vk); + ValueTypeNode* zero = ValueTypeNode::make_null(gvn, vk); vt = zero->clone_with_phis(&gvn, region); if (vt_nullable != nullptr) { vt = vt->merge_with(&gvn, vt_nullable, 1, false); @@ -1661,13 +1661,13 @@ InlineTypeNode* InlineTypeNode::make_from_flat_array(GraphKit* kit, ciInlineKlas kit->set_control(kit->gvn().transform(region)); kit->set_all_memory(kit->gvn().transform(mem)); kit->set_i_o(kit->gvn().transform(io)); - return gvn.transform(vt)->as_InlineType(); + return gvn.transform(vt)->as_ValueType(); } -InlineTypeNode* InlineTypeNode::make_from_multi(GraphKit* kit, MultiNode* multi, ciInlineKlass* vk, uint& base_input, bool in, bool null_free) { - InlineTypeNode* vt = make_uninitialized(kit->gvn(), vk, null_free); +ValueTypeNode* ValueTypeNode::make_from_multi(GraphKit* kit, MultiNode* multi, ciValueKlass* vk, uint& base_input, bool in, bool null_free) { + ValueTypeNode* vt = make_uninitialized(kit->gvn(), vk, null_free); if (!in || multi->is_Start()) { - // Keep track of the oop. The inline type might already be buffered. + // Keep track of the oop. The value type might already be buffered. Node* oop = nullptr; if (multi->is_Start()) { oop = kit->gvn().transform(new ParmNode(multi->as_Start(), base_input++)); @@ -1680,25 +1680,25 @@ InlineTypeNode* InlineTypeNode::make_from_multi(GraphKit* kit, MultiNode* multi, vt->set_oop(kit->gvn(), oop); } vt->initialize_fields(kit, multi, base_input, in, null_free, nullptr); - return kit->gvn().transform(vt)->as_InlineType(); + return kit->gvn().transform(vt)->as_ValueType(); } -Node* InlineTypeNode::is_loaded(PhaseGVN* phase, ciInlineKlass* vk, Node* base, int holder_offset) const { +Node* ValueTypeNode::is_loaded(PhaseGVN* phase, ciValueKlass* vk, Node* base, int holder_offset) const { if (vk == nullptr) { - vk = inline_klass(); + vk = value_klass(); } for (uint i = 0; i < field_count(); ++i) { ciField* field = this->field(i); int offset = holder_offset + field->offset_in_bytes(); Node* value = field_value(i); - if (value->is_InlineType()) { - assert(!field->is_flat() || field->type()->is_inlinetype(), "must be an inline type"); - InlineTypeNode* vt = value->as_InlineType(); - if (vt->type()->inline_klass()->is_empty()) { + if (value->is_ValueType()) { + assert(!field->is_flat() || field->type()->is_value_klass(), "must be a value type"); + ValueTypeNode* vt = value->as_ValueType(); + if (vt->type()->value_klass()->is_empty()) { continue; - } else if (field->is_flat() && vt->is_InlineType()) { - // Check inline type field load recursively - base = vt->as_InlineType()->is_loaded(phase, vk, base, offset - vt->type()->inline_klass()->payload_offset()); + } else if (field->is_flat() && vt->is_ValueType()) { + // Check value type field load recursively + base = vt->as_ValueType()->is_loaded(phase, vk, base, offset - vt->type()->value_klass()->payload_offset()); if (base == nullptr) { return nullptr; } @@ -1716,7 +1716,7 @@ Node* InlineTypeNode::is_loaded(PhaseGVN* phase, ciInlineKlass* vk, Node* base, value = value->in(1); } if (value->isa_Load()) { - // Check if base and offset of field load matches inline type layout + // Check if base and offset of field load matches value type layout intptr_t loffset = 0; Node* lbase = AddPNode::Ideal_base_and_offset(value->in(MemNode::Address), phase, loffset); if (lbase == nullptr || (lbase != base && base != nullptr) || loffset != offset) { @@ -1736,14 +1736,14 @@ Node* InlineTypeNode::is_loaded(PhaseGVN* phase, ciInlineKlass* vk, Node* base, return base; } -Node* InlineTypeNode::tagged_klass(ciInlineKlass* vk, PhaseGVN& gvn) { +Node* ValueTypeNode::tagged_klass(ciValueKlass* vk, PhaseGVN& gvn) { const TypeKlassPtr* tk = TypeKlassPtr::make(vk); intptr_t bits = tk->get_con(); set_nth_bit(bits, 0); return gvn.longcon((jlong)bits); } -void InlineTypeNode::pass_fields(GraphKit* kit, Node* n, uint& base_input, bool in, bool null_free, bool root) { +void ValueTypeNode::pass_fields(GraphKit* kit, Node* n, uint& base_input, bool in, bool null_free, bool root) { if (root) { if (is_allocated(&kit->gvn())) { // Keep the information that 'this' is buffered @@ -1758,19 +1758,19 @@ void InlineTypeNode::pass_fields(GraphKit* kit, Node* n, uint& base_input, bool for (uint i = 0; i < field_count(); i++) { Node* arg = field_value(i); ciField* field = this->field(i); - assert(!field->is_flat() || field->type()->is_inlinetype(), "must be an inline type"); + assert(!field->is_flat() || field->type()->is_value_klass(), "must be a value type"); if (field->is_flat()) { - // Flat inline type field - arg->as_InlineType()->pass_fields(kit, n, base_input, in); + // Flat value type field + arg->as_ValueType()->pass_fields(kit, n, base_input, in); if (!field->is_null_free()) { assert(field->null_marker_offset() != -1, "inconsistency"); - n->init_req(base_input++, arg->as_InlineType()->get_null_marker()); + n->init_req(base_input++, arg->as_ValueType()->get_null_marker()); } } else { - if (arg->is_InlineType()) { - // Non-flat inline type field - InlineTypeNode* vt = arg->as_InlineType(); - assert(n->Opcode() != Op_Return || vt->is_allocated(&kit->gvn()), "inline type field should be allocated on return"); + if (arg->is_ValueType()) { + // Non-flat value type field + ValueTypeNode* vt = arg->as_ValueType(); + assert(n->Opcode() != Op_Return || vt->is_allocated(&kit->gvn()), "value type field should be allocated on return"); arg = vt->buffer(kit); } // Initialize call/return arguments @@ -1782,11 +1782,11 @@ void InlineTypeNode::pass_fields(GraphKit* kit, Node* n, uint& base_input, bool } } -void InlineTypeNode::initialize_fields(GraphKit* kit, MultiNode* multi, uint& base_input, bool in, bool no_null_marker, Node* null_check_region) { +void ValueTypeNode::initialize_fields(GraphKit* kit, MultiNode* multi, uint& base_input, bool in, bool no_null_marker, Node* null_check_region) { PhaseGVN& gvn = kit->gvn(); Node* null_marker = nullptr; if (!no_null_marker) { - // Nullable inline type + // Nullable value type if (in) { // Set null marker if (multi->is_Start()) { @@ -1819,10 +1819,10 @@ void InlineTypeNode::initialize_fields(GraphKit* kit, MultiNode* multi, uint& ba ciField* field = this->field(i); ciType* type = field->type(); Node* parm = nullptr; - assert(!field->is_flat() || field->type()->is_inlinetype(), "must be an inline type"); + assert(!field->is_flat() || field->type()->is_value_klass(), "must be a value type"); if (field->is_flat()) { - // Flat inline type field - InlineTypeNode* vt = make_uninitialized(gvn, type->as_inline_klass(), field->is_null_free()); + // Flat value type field + ValueTypeNode* vt = make_uninitialized(gvn, type->as_value_klass(), field->is_null_free()); vt->initialize_fields(kit, multi, base_input, in, true, null_check_region); if (!field->is_null_free()) { assert(field->null_marker_offset() != -1, "inconsistency"); @@ -1867,24 +1867,24 @@ void InlineTypeNode::initialize_fields(GraphKit* kit, MultiNode* multi, uint& ba } } -// Search for multiple allocations of this inline type and try to replace them by dominating allocations. -// Equivalent InlineTypeNodes are merged by GVN, so we just need to search for AllocateNode users to find redundant allocations. -void InlineTypeNode::remove_redundant_allocations(PhaseIdealLoop* phase) const { +// Search for multiple allocations of this value type and try to replace them by dominating allocations. +// Equivalent ValueTypeNodes are merged by GVN, so we just need to search for AllocateNode users to find redundant allocations. +void ValueTypeNode::remove_redundant_allocations(PhaseIdealLoop* phase) const { PhaseIterGVN* igvn = &phase->igvn(); - // Search for allocations of this inline type. Ignore scalar replaceable ones, they + // Search for allocations of this value type. Ignore scalar replaceable ones, they // will be removed anyway and changing the memory chain will confuse other optimizations. for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) { AllocateNode* alloc = fast_out(i)->isa_Allocate(); - if (alloc != nullptr && alloc->in(AllocateNode::InlineType) == this && !alloc->_is_scalar_replaceable) { + if (alloc != nullptr && alloc->in(AllocateNode::ValueType) == this && !alloc->_is_scalar_replaceable) { Node* res = alloc->result_cast(); if (res == nullptr || !res->is_CheckCastPP()) { break; // No unique CheckCastPP } - // Search for a dominating allocation of the same inline type + // Search for a dominating allocation of the same value type Node* res_dom = res; for (DUIterator_Fast jmax, j = fast_outs(jmax); j < jmax; j++) { AllocateNode* alloc_other = fast_out(j)->isa_Allocate(); - if (alloc_other != nullptr && alloc_other->in(AllocateNode::InlineType) == this && !alloc_other->_is_scalar_replaceable) { + if (alloc_other != nullptr && alloc_other->in(AllocateNode::ValueType) == this && !alloc_other->_is_scalar_replaceable) { Node* res_other = alloc_other->result_cast(); if (res_other != nullptr && res_other->is_CheckCastPP() && res_other != res_dom && phase->is_dominator(res_other->in(0), res_dom->in(0))) { @@ -1903,12 +1903,12 @@ void InlineTypeNode::remove_redundant_allocations(PhaseIdealLoop* phase) const { } } -InlineTypeNode* InlineTypeNode::make_null(PhaseGVN& gvn, ciInlineKlass* vk, bool transform) { +ValueTypeNode* ValueTypeNode::make_null(PhaseGVN& gvn, ciValueKlass* vk, bool transform) { return make_null_impl(gvn, vk, transform); } -InlineTypeNode* InlineTypeNode::make_null_impl(PhaseGVN& gvn, ciInlineKlass* vk, bool transform) { - InlineTypeNode* vt = new InlineTypeNode(vk, gvn.zerocon(T_OBJECT), /* null_free= */ false); +ValueTypeNode* ValueTypeNode::make_null_impl(PhaseGVN& gvn, ciValueKlass* vk, bool transform) { + ValueTypeNode* vt = new ValueTypeNode(vk, gvn.zerocon(T_OBJECT), /* null_free= */ false); vt->set_is_buffered(gvn); vt->set_null_marker(gvn, gvn.intcon(0)); for (uint i = 0; i < vt->field_count(); i++) { @@ -1916,36 +1916,36 @@ InlineTypeNode* InlineTypeNode::make_null_impl(PhaseGVN& gvn, ciInlineKlass* vk, ciType* ft = field->type(); Node* value; if (field->is_flat()) { - value = make_null_impl(gvn, ft->as_inline_klass()); + value = make_null_impl(gvn, ft->as_value_klass()); } else { value = gvn.zerocon(ft->basic_type()); } vt->set_field_value(i, value); } - return transform ? gvn.transform(vt)->as_InlineType() : vt; + return transform ? gvn.transform(vt)->as_ValueType() : vt; } -InlineTypeNode* InlineTypeNode::clone_if_required(PhaseGVN* gvn, SafePointNode* map, bool safe_for_replace) { +ValueTypeNode* ValueTypeNode::clone_if_required(PhaseGVN* gvn, SafePointNode* map, bool safe_for_replace) { if (!safe_for_replace || (map == nullptr && outcnt() != 0)) { - return clone()->as_InlineType(); + return clone()->as_ValueType(); } for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) { if (fast_out(i) != map) { - return clone()->as_InlineType(); + return clone()->as_ValueType(); } } gvn->hash_delete(this); return this; } -const Type* InlineTypeNode::Value(PhaseGVN* phase) const { +const Type* ValueTypeNode::Value(PhaseGVN* phase) const { Node* oop = get_oop(); const Type* toop = phase->type(oop); #ifdef ASSERT if (oop->is_Con() && toop->is_zero_type() && _type->isa_oopptr()->is_known_instance()) { // We are not allocated (anymore) and should therefore not have an instance id dump(1); - assert(false, "Unbuffered inline type should not have known instance id"); + assert(false, "Unbuffered value type should not have known instance id"); } #endif if (toop == Type::TOP) { @@ -1959,7 +1959,7 @@ const Type* InlineTypeNode::Value(PhaseGVN* phase) const { t = toop->filter_speculative(t); } if (t->singleton()) { - // Don't replace InlineType by a constant + // Don't replace ValueType by a constant t = _type; } const Type* tinit = phase->type(in(NullMarker)); @@ -1972,7 +1972,7 @@ const Type* InlineTypeNode::Value(PhaseGVN* phase) const { return t; } -InlineTypeNode* LoadFlatNode::load(GraphKit* kit, ciInlineKlass* vk, Node* base, Node* ptr, bool null_free, bool trust_null_free_oop, DecoratorSet decorators) { +ValueTypeNode* LoadFlatNode::load(GraphKit* kit, ciValueKlass* vk, Node* base, Node* ptr, bool null_free, bool trust_null_free_oop, DecoratorSet decorators) { int output_type_size = vk->nof_nonstatic_fields() + (null_free ? 0 : 1); const Type** output_types = TypeTuple::fields(output_type_size); collect_field_types(vk, output_types + TypeFunc::Parms, 0, output_type_size, null_free, trust_null_free_oop); @@ -2116,12 +2116,12 @@ void LoadFlatNode::expand_atomic(PhaseIterGVN& igvn) const { expand_projs_atomic(igvn, kit.control(), payload); } -void LoadFlatNode::collect_field_types(ciInlineKlass* vk, const Type** field_types, int idx, int limit, bool null_free, bool trust_null_free_oop) { +void LoadFlatNode::collect_field_types(ciValueKlass* vk, const Type** field_types, int idx, int limit, bool null_free, bool trust_null_free_oop) { assert(null_free || !trust_null_free_oop, "cannot trust null-free oop when the holder object is not null-free"); for (int i = 0; i < vk->nof_declared_nonstatic_fields(); i++) { ciField* field = vk->declared_nonstatic_field_at(i); if (field->is_flat()) { - ciInlineKlass* field_klass = field->type()->as_inline_klass(); + ciValueKlass* field_klass = field->type()->as_value_klass(); collect_field_types(field_klass, field_types, idx, limit, field->is_null_free(), trust_null_free_oop && field->is_null_free()); idx += field_klass->nof_nonstatic_fields() + (field->is_null_free() ? 0 : 1); continue; @@ -2143,16 +2143,16 @@ void LoadFlatNode::collect_field_types(ciInlineKlass* vk, const Type** field_typ } } -// Create an InlineTypeNode from a LoadFlatNode with its fields being extracted from the +// Create an ValueTypeNode from a LoadFlatNode with its fields being extracted from the // LoadFlatNode -InlineTypeNode* LoadFlatNode::collect_projs(GraphKit* kit, ciInlineKlass* vk, int proj_con, bool null_free) { +ValueTypeNode* LoadFlatNode::collect_projs(GraphKit* kit, ciValueKlass* vk, int proj_con, bool null_free) { PhaseGVN& gvn = kit->gvn(); - InlineTypeNode* res = InlineTypeNode::make_uninitialized(gvn, vk, null_free); + ValueTypeNode* res = ValueTypeNode::make_uninitialized(gvn, vk, null_free); for (int i = 0; i < vk->nof_declared_nonstatic_fields(); i++) { ciField* field = vk->declared_nonstatic_field_at(i); Node* field_value; if (field->is_flat()) { - ciInlineKlass* field_klass = field->type()->as_inline_klass(); + ciValueKlass* field_klass = field->type()->as_value_klass(); field_value = collect_projs(kit, field_klass, proj_con, field->is_null_free()); proj_con += field_klass->nof_nonstatic_fields() + (field->is_null_free() ? 0 : 1); } else { @@ -2167,7 +2167,7 @@ InlineTypeNode* LoadFlatNode::collect_projs(GraphKit* kit, ciInlineKlass* vk, in } else { res->set_null_marker(gvn, gvn.transform(new ProjNode(this, proj_con))); } - return gvn.transform(res)->as_InlineType(); + return gvn.transform(res)->as_ValueType(); } // Extract the values of the flattened fields from the loaded payload @@ -2201,8 +2201,13 @@ void LoadFlatNode::expand_projs_atomic(PhaseIterGVN& igvn, Node* ctrl, Node* pay Node* LoadFlatNode::get_payload_value(PhaseIterGVN& igvn, Node* ctrl, BasicType payload_bt, Node* payload, const Type* value_type, BasicType value_bt, int offset) { assert((offset + type2aelembytes(value_bt)) <= type2aelembytes(payload_bt), "Value does not fit into payload"); Node* value = nullptr; - // Shift to the right position in the long value - Node* shift_val = igvn.intcon(offset << LogBitsPerByte); + // Shift the field to the low-order bits of the payload. +#ifdef VM_LITTLE_ENDIAN + int shift = offset << LogBitsPerByte; +#else + int shift = (type2aelembytes(payload_bt) - type2aelembytes(value_bt) - offset) << LogBitsPerByte; +#endif + Node* shift_val = igvn.intcon(shift); if (payload_bt == T_LONG) { value = igvn.transform(new URShiftLNode(payload, shift_val)); value = igvn.transform(new ConvL2INode(value)); @@ -2228,7 +2233,7 @@ Node* LoadFlatNode::get_payload_value(PhaseIterGVN& igvn, Node* ctrl, BasicType } } -void StoreFlatNode::store(GraphKit* kit, Node* base, Node* ptr, InlineTypeNode* value, bool null_free, DecoratorSet decorators) { +void StoreFlatNode::store(GraphKit* kit, Node* base, Node* ptr, ValueTypeNode* value, bool null_free, DecoratorSet decorators) { value = value->allocate_fields(kit); StoreFlatNode* store = new StoreFlatNode(null_free, decorators); store->init_req(TypeFunc::Control, kit->control()); @@ -2258,9 +2263,9 @@ bool StoreFlatNode::expand_non_atomic(PhaseIterGVN& igvn) const { GraphKit kit(this, igvn); Node* base = this->base(); Node* ptr = this->ptr(); - InlineTypeNode* value = this->value(); + ValueTypeNode* value = this->value(); - ciInlineKlass* vk = igvn.type(value)->inline_klass(); + ciValueKlass* vk = igvn.type(value)->value_klass(); for (int i = 0; i < vk->nof_nonstatic_fields(); i++) { ciField* field = vk->nonstatic_field_at(i); Node* field_ptr = kit.basic_plus_adr(base, ptr, field->offset_in_bytes() - vk->payload_offset()); @@ -2300,13 +2305,13 @@ void StoreFlatNode::expand_atomic(PhaseIterGVN& igvn) const { GraphKit kit(this, igvn); Node* base = this->base(); Node* ptr = this->ptr(); - InlineTypeNode* value = this->value(); + ValueTypeNode* value = this->value(); int oop_off_1 = -1; int oop_off_2 = -1; Node* payload = convert_to_payload(igvn, kit.control(), value, _null_free, oop_off_1, oop_off_2); - ciInlineKlass* vk = igvn.type(value)->inline_klass(); + ciValueKlass* vk = igvn.type(value)->value_klass(); assert(oop_off_1 == -1 || oop_off_1 == 0 || oop_off_1 == 4, "invalid layout for %s, first oop at offset %d", vk->name()->as_utf8(), oop_off_1); assert(oop_off_2 == -1 || oop_off_2 == 4, "invalid layout for %s, second oop at offset %d", vk->name()->as_utf8(), oop_off_2); BasicType payload_bt = vk->atomic_size_to_basic_type(_null_free); @@ -2342,8 +2347,8 @@ void StoreFlatNode::expand_atomic(PhaseIterGVN& igvn) const { } // Convert the field values to a payload value of type 'bt' -Node* StoreFlatNode::convert_to_payload(PhaseIterGVN& igvn, Node* ctrl, InlineTypeNode* value, bool null_free, int& oop_off_1, int& oop_off_2) { - ciInlineKlass* vk = igvn.type(value)->inline_klass(); +Node* StoreFlatNode::convert_to_payload(PhaseIterGVN& igvn, Node* ctrl, ValueTypeNode* value, bool null_free, int& oop_off_1, int& oop_off_2) { + ciValueKlass* vk = igvn.type(value)->value_klass(); BasicType payload_bt = vk->atomic_size_to_basic_type(null_free); Node* payload = igvn.zerocon(payload_bt); if (!null_free) { @@ -2369,8 +2374,8 @@ Node* StoreFlatNode::convert_to_payload(PhaseIterGVN& igvn, Node* ctrl, InlineTy } const Type* val_type = Type::get_const_type(field_klass)->make_narrowoop(); - if (field_value->is_InlineType()) { - assert(field_value->as_InlineType()->is_allocated(&igvn), "must be allocated"); + if (field_value->is_ValueType()) { + assert(field_value->as_ValueType()->is_allocated(&igvn), "must be allocated"); } field_value = igvn.transform(new EncodePNode(field_value, val_type)); @@ -2398,7 +2403,12 @@ Node* StoreFlatNode::set_payload_value(PhaseIterGVN& igvn, BasicType payload_bt, assert(val_bt == T_INT, "Unsupported type: %s", type2name(val_bt)); } - Node* shift_val = igvn.intcon(offset << LogBitsPerByte); +#ifdef VM_LITTLE_ENDIAN + int shift = offset << LogBitsPerByte; +#else + int shift = (type2aelembytes(payload_bt) - type2aelembytes(val_bt) - offset) << LogBitsPerByte; +#endif + Node* shift_val = igvn.intcon(shift); if (payload_bt == T_LONG) { // Convert to long and remove the sign bit (the backend will fold this and emit a zero extend i2l) value = igvn.transform(new ConvI2LNode(value)); @@ -2427,7 +2437,7 @@ const Type* StoreFlatNode::Value(PhaseGVN* phase) const { phase->type(base()) == Type::TOP || phase->type(ptr()) == Type::TOP || phase->type(val) == Type::TOP) { return Type::TOP; } - assert(val->is_InlineType(), "must be InlineTypeNode: %s", val->Name()); + assert(val->is_ValueType(), "must be ValueTypeNode: %s", val->Name()); return bottom_type(); } diff --git a/src/hotspot/share/opto/inlinetypenode.hpp b/src/hotspot/share/opto/valuetypenode.hpp similarity index 67% rename from src/hotspot/share/opto/inlinetypenode.hpp rename to src/hotspot/share/opto/valuetypenode.hpp index 1ef4ebd007b0..4d8963dbf10c 100644 --- a/src/hotspot/share/opto/inlinetypenode.hpp +++ b/src/hotspot/share/opto/valuetypenode.hpp @@ -22,10 +22,10 @@ * */ -#ifndef SHARE_VM_OPTO_INLINETYPENODE_HPP -#define SHARE_VM_OPTO_INLINETYPENODE_HPP +#ifndef SHARE_VM_OPTO_VALUETYPENODE_HPP +#define SHARE_VM_OPTO_VALUETYPENODE_HPP -#include "ci/ciInlineKlass.hpp" +#include "ci/ciValueKlass.hpp" #include "oops/accessDecorators.hpp" #include "opto/callnode.hpp" #include "opto/compile.hpp" @@ -34,73 +34,73 @@ class GraphKit; -//------------------------------InlineTypeNode------------------------------------- -// Node representing an inline type in C2 IR -class InlineTypeNode : public TypeNode { +//------------------------------ValueTypeNode------------------------------------- +// Node representing a value type in C2 IR +class ValueTypeNode : public TypeNode { private: - InlineTypeNode(ciInlineKlass* vk, Node* oop, bool null_free) + ValueTypeNode(ciValueKlass* vk, Node* oop, bool null_free) : TypeNode(TypeInstPtr::make(null_free ? TypePtr::NotNull : TypePtr::BotPTR, vk), Values + vk->nof_declared_nonstatic_fields()) { - init_class_id(Class_InlineType); + init_class_id(Class_ValueType); init_req(Oop, oop); - Compile::current()->add_inline_type(this); + Compile::current()->add_value_type(this); } enum { Control, // Control input. Oop, // Oop to heap allocated buffer. - IsBuffered, // True if inline type is heap allocated (or nullptr), false otherwise. + IsBuffered, // True if value type is heap allocated (or nullptr), false otherwise. NullMarker, // Needs to be checked before using the field values. - // 0 => InlineType is null - // 1 => InlineType is non-null + // 0 => ValueType is null + // 1 => ValueType is non-null // Can be dynamic value, not necessarily statically known - Values // Nodes corresponding to values of the inline type's fields. + Values // Nodes corresponding to values of the value type's fields. // Nodes are connected in increasing order of the index of the field they correspond to. }; - // Get the klass defining the field layout of the inline type - ciInlineKlass* inline_klass() const { return type()->inline_klass(); } + // Get the klass defining the field layout of the value type + ciValueKlass* value_klass() const { return type()->value_klass(); } void make_scalar_in_safepoint(PhaseIterGVN* igvn, Unique_Node_List& worklist, SafePointNode* sfpt) const; uint add_fields_to_safepoint(Unique_Node_List& worklist, SafePointNode* sfpt) const; - // Checks if the inline type is loaded from memory and if so returns the oop - Node* is_loaded(PhaseGVN* phase, ciInlineKlass* vk = nullptr, Node* base = nullptr, int holder_offset = 0) const; + // Checks if the value type is loaded from memory and if so returns the oop + Node* is_loaded(PhaseGVN* phase, ciValueKlass* vk = nullptr, Node* base = nullptr, int holder_offset = 0) const; - // Initialize the inline type fields with the inputs or outputs of a MultiNode + // Initialize the value type fields with the inputs or outputs of a MultiNode void initialize_fields(GraphKit* kit, MultiNode* multi, uint& base_input, bool in, bool no_null_marker, Node* null_check_region); - // Initialize the inline type by loading its field values from memory + // Initialize the value type by loading its field values from memory void load(GraphKit* kit, Node* base, Node* ptr, bool immutable_memory, bool trust_null_free_oop, DecoratorSet decorators); // Store the field values to memory void store(GraphKit* kit, Node* base, Node* ptr, bool immutable_memory, DecoratorSet decorators) const; - static InlineTypeNode* make_all_zero_impl(PhaseGVN& gvn, ciInlineKlass* vk); - static InlineTypeNode* make_from_oop_impl(GraphKit* kit, Node* oop, ciInlineKlass* vk); - static InlineTypeNode* make_null_impl(PhaseGVN& gvn, ciInlineKlass* vk, bool transform = true); - static InlineTypeNode* make_from_flat_impl(GraphKit* kit, ciInlineKlass* vk, Node* base, Node* ptr, bool atomic, bool immutable_memory, + static ValueTypeNode* make_all_zero_impl(PhaseGVN& gvn, ciValueKlass* vk); + static ValueTypeNode* make_from_oop_impl(GraphKit* kit, Node* oop, ciValueKlass* vk); + static ValueTypeNode* make_null_impl(PhaseGVN& gvn, ciValueKlass* vk, bool transform = true); + static ValueTypeNode* make_from_flat_impl(GraphKit* kit, ciValueKlass* vk, Node* base, Node* ptr, bool atomic, bool immutable_memory, bool null_free, bool trust_null_free_oop, DecoratorSet decorators); public: // Create with all-zero field values - static InlineTypeNode* make_all_zero(PhaseGVN& gvn, ciInlineKlass* vk); + static ValueTypeNode* make_all_zero(PhaseGVN& gvn, ciValueKlass* vk); // Create uninitialized - static InlineTypeNode* make_uninitialized(PhaseGVN& gvn, ciInlineKlass* vk, bool null_free = true); + static ValueTypeNode* make_uninitialized(PhaseGVN& gvn, ciValueKlass* vk, bool null_free = true); // Create and initialize by loading the field values from an oop - static InlineTypeNode* make_from_oop(GraphKit* kit, Node* oop, ciInlineKlass* vk); + static ValueTypeNode* make_from_oop(GraphKit* kit, Node* oop, ciValueKlass* vk); // Create and initialize by loading the field values from a flat field or array - static InlineTypeNode* make_from_flat(GraphKit* kit, ciInlineKlass* vk, Node* base, Node* ptr, + static ValueTypeNode* make_from_flat(GraphKit* kit, ciValueKlass* vk, Node* base, Node* ptr, bool atomic, bool immutable_memory, bool null_free, DecoratorSet decorators); - static InlineTypeNode* make_from_flat_array(GraphKit* kit, ciInlineKlass* vk, Node* base, Node* idx); + static ValueTypeNode* make_from_flat_array(GraphKit* kit, ciValueKlass* vk, Node* base, Node* idx); // Create and initialize with the inputs or outputs of a MultiNode (method entry or call) - static InlineTypeNode* make_from_multi(GraphKit* kit, MultiNode* multi, ciInlineKlass* vk, uint& base_input, bool in, bool null_free = true); + static ValueTypeNode* make_from_multi(GraphKit* kit, MultiNode* multi, ciValueKlass* vk, uint& base_input, bool in, bool null_free = true); // Create with null field values - static InlineTypeNode* make_null(PhaseGVN& gvn, ciInlineKlass* vk, bool transform = true); + static ValueTypeNode* make_null(PhaseGVN& gvn, ciValueKlass* vk, bool transform = true); // Support for control flow merges bool has_phi_inputs(Node* region) const; - InlineTypeNode* clone_with_phis(PhaseGVN* gvn, Node* region, SafePointNode* map = nullptr, bool is_non_null = false, bool init_with_top = false); - InlineTypeNode* merge_with(PhaseGVN* gvn, const InlineTypeNode* other, int phi_index, bool transform); + ValueTypeNode* clone_with_phis(PhaseGVN* gvn, Node* region, SafePointNode* map = nullptr, bool is_non_null = false, bool init_with_top = false); + ValueTypeNode* merge_with(PhaseGVN* gvn, const ValueTypeNode* other, int phi_index, bool transform); void add_new_path(Node* region) const; - // Get oop for heap allocated inline type (may be TypePtr::NULL_PTR) + // Get oop for heap allocated value type (may be TypePtr::NULL_PTR) Node* get_oop() const { return in(Oop); } void set_oop(PhaseGVN& gvn, Node* oop) { set_req_X(Oop, oop, &gvn); } Node* get_null_marker() const { return in(NullMarker); } @@ -109,10 +109,10 @@ class InlineTypeNode : public TypeNode { Node* get_is_buffered() const { return in(IsBuffered); } void set_is_buffered(PhaseGVN& gvn, bool buffered = true) { set_req_X(IsBuffered, gvn.intcon(buffered ? 1 : 0), &gvn); } - // Checks if the inline type fields are all set to zero + // Checks if the value type fields are all set to zero bool is_all_zero(PhaseGVN* gvn, bool flat = false) const; - // Inline type fields + // Value type fields uint field_count() const { return req() - Values; } ciField* field(uint index) const; Node* field_value(uint index) const; @@ -121,14 +121,14 @@ class InlineTypeNode : public TypeNode { void set_field_value_by_offset(int offset, Node* value); uint field_index(int offset) const; - // Replace InlineTypeNodes in debug info at safepoints with SafePointScalarObjectNodes + // Replace ValueTypeNodes in debug info at safepoints with SafePointScalarObjectNodes [[nodiscard]] bool make_scalar_in_safepoints(PhaseIterGVN* igvn, bool allow_oop = true); // Variant that allows to limit to a single safepoint. If nullptr is given, all safepoint uses will be considered. [[nodiscard]] bool make_scalar_in_safepoints(PhaseIterGVN* igvn, bool allow_oop, SafePointNode* safepoint); - // Store the inline type as a flat (headerless) representation + // Store the value type as a flat (headerless) representation void store_flat(GraphKit* kit, Node* base, Node* ptr, bool atomic, bool immutable_memory, bool null_free, DecoratorSet decorators); - // Store the inline type as a flat (headerless) representation into an array + // Store the value type as a flat (headerless) representation into an array void store_flat_array(GraphKit* kit, Node* base, Node* idx); // Implementation of the substitutability check for acmp @@ -139,28 +139,28 @@ class InlineTypeNode : public TypeNode { static bool can_emit_identity_hash_code(const PhaseIterGVN& igvn, Node* arg, intptr_t& klass_hash); static Node* emit_identity_hash_code(GraphKit* kit, Node* arg, intptr_t klass_hash); - // Allocates the inline type (if not yet allocated) - InlineTypeNode* buffer(GraphKit* kit, bool safe_for_replace = true); + // Allocates the value type (if not yet allocated) + ValueTypeNode* buffer(GraphKit* kit, bool safe_for_replace = true); bool is_allocated(PhaseGVN* phase) const; void replace_call_results(GraphKit* kit, CallNode* call, Compile* C) const; void replace_field_projs(Compile* C, CallNode* call, uint& proj_idx) const; - // Allocate all non-flat inline type fields - InlineTypeNode* allocate_fields(GraphKit* kit); + // Allocate all non-flat value type fields + ValueTypeNode* allocate_fields(GraphKit* kit); Node* tagged_klass(PhaseGVN& gvn) const { - return tagged_klass(inline_klass(), gvn); + return tagged_klass(value_klass(), gvn); } - static Node* tagged_klass(ciInlineKlass* vk, PhaseGVN& gvn); - // Pass inline type as fields at a call or return + static Node* tagged_klass(ciValueKlass* vk, PhaseGVN& gvn); + // Pass value type as fields at a call or return void pass_fields(GraphKit* kit, Node* n, uint& base_input, bool in, bool null_free = true, bool root = false); // Allocation optimizations void remove_redundant_allocations(PhaseIdealLoop* phase) const; - InlineTypeNode* clone_if_required(PhaseGVN* gvn, SafePointNode* map, bool safe_for_replace = true); + ValueTypeNode* clone_if_required(PhaseGVN* gvn, SafePointNode* map, bool safe_for_replace = true); virtual const Type* Value(PhaseGVN* phase) const; virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); @@ -178,7 +178,7 @@ class InlineTypeNode : public TypeNode { // objects with atomic flat fields to be scalar replaced. class LoadFlatNode final : public SafePointNode { private: - ciInlineKlass* _vk; + ciValueKlass* _vk; const TypeTuple* _type; bool _null_free; DecoratorSet _decorators; @@ -186,7 +186,7 @@ class LoadFlatNode final : public SafePointNode { uint size_of() const override { return sizeof(*this); } public: - static InlineTypeNode* load(GraphKit* kit, ciInlineKlass* vk, Node* base, Node* ptr, bool null_free, bool trust_null_free_oop, DecoratorSet decorators); + static ValueTypeNode* load(GraphKit* kit, ciValueKlass* vk, Node* base, Node* ptr, bool null_free, bool trust_null_free_oop, DecoratorSet decorators); Node* base() const { return in(TypeFunc::Parms); } Node* ptr() const { return in(TypeFunc::Parms + 1); } bool expand_constant(PhaseIterGVN& igvn, ciInstance* inst) const; @@ -202,21 +202,21 @@ class LoadFlatNode final : public SafePointNode { bool is_mismatched() const; private: - LoadFlatNode(ciInlineKlass* vk, const TypeTuple* type, bool null_free, DecoratorSet decorators) + LoadFlatNode(ciValueKlass* vk, const TypeTuple* type, bool null_free, DecoratorSet decorators) : SafePointNode(TypeFunc::Parms + 2, nullptr, TypePtr::BOTTOM), _vk(vk), _type(type), _null_free(null_free), _decorators(decorators) { init_class_id(Class_LoadFlat); Compile::current()->add_flat_access(this); } - static void collect_field_types(ciInlineKlass* vk, const Type** field_types, int idx, int limit, bool null_free, bool trust_null_free_oop); - InlineTypeNode* collect_projs(GraphKit* kit, ciInlineKlass* vk, int proj_con, bool null_free); + static void collect_field_types(ciValueKlass* vk, const Type** field_types, int idx, int limit, bool null_free, bool trust_null_free_oop); + ValueTypeNode* collect_projs(GraphKit* kit, ciValueKlass* vk, int proj_con, bool null_free); void expand_projs_atomic(PhaseIterGVN& gvn, Node* ctrl, Node* payload) const; static Node* get_payload_value(PhaseIterGVN& igvn, Node* ctrl, BasicType payload_bt, Node* payload, const Type* value_type, BasicType value_bt, int offset); }; -// Store an InlineTypeNode to a flat element, the store acts as if it is atomic. Similar to +// Store an ValueTypeNode to a flat element, the store acts as if it is atomic. Similar to // LoadFlatNode, this node is expanded to storing a payload created from the field values of the -// InlineTypeNode, and under special circumstances, when there is no racing access to the field, +// ValueTypeNode, and under special circumstances, when there is no racing access to the field, // this node can be expanded to multiple stores to each flattened field. // The purposes of this node complement those of LoadFlatNode. class StoreFlatNode final : public SafePointNode { @@ -227,10 +227,10 @@ class StoreFlatNode final : public SafePointNode { uint size_of() const override { return sizeof(*this); } public: - static void store(GraphKit* kit, Node* base, Node* ptr, InlineTypeNode* value, bool null_free, DecoratorSet decorators); + static void store(GraphKit* kit, Node* base, Node* ptr, ValueTypeNode* value, bool null_free, DecoratorSet decorators); Node* base() const { return in(TypeFunc::Parms); } Node* ptr() const { return in(TypeFunc::Parms + 1); } - InlineTypeNode* value() const { return in(TypeFunc::Parms + 2)->as_InlineType(); } + ValueTypeNode* value() const { return in(TypeFunc::Parms + 2)->as_ValueType(); } bool expand_non_atomic(PhaseIterGVN& igvn) const; void expand_atomic(PhaseIterGVN& igvn) const; @@ -249,8 +249,8 @@ class StoreFlatNode final : public SafePointNode { Compile::current()->add_flat_access(this); } - static Node* convert_to_payload(PhaseIterGVN& igvn, Node* ctrl, InlineTypeNode* value, bool null_free, int& oop_off_1, int& oop_off_2); + static Node* convert_to_payload(PhaseIterGVN& igvn, Node* ctrl, ValueTypeNode* value, bool null_free, int& oop_off_1, int& oop_off_2); static Node* set_payload_value(PhaseIterGVN& igvn, BasicType payload_bt, Node* payload, BasicType val_bt, Node* value, int offset); }; -#endif // SHARE_VM_OPTO_INLINETYPENODE_HPP +#endif // SHARE_VM_OPTO_VALUETYPENODE_HPP diff --git a/src/hotspot/share/opto/vector.cpp b/src/hotspot/share/opto/vector.cpp index 40dc408fe547..7853a2919cec 100644 --- a/src/hotspot/share/opto/vector.cpp +++ b/src/hotspot/share/opto/vector.cpp @@ -209,10 +209,10 @@ void PhaseVector::scalarize_vbox_node(VectorBoxNode* vec_box) { int parm_idx = 0; // The index of the Java parameter: double/long take one slot for (uint i = 0; i < nargs; i++) { // The index of the argument on the JVM stack: double/long take two slots const Type* arg_type = call->tf()->domain_sig()->field_at(TypeFunc::Parms + i); - if (arg_type->is_inlinetypeptr() && !call->method()->mismatch() && call->method()->is_scalarized_arg(parm_idx)) { + if (arg_type->is_valueklassptr() && !call->method()->mismatch() && call->method()->is_scalarized_arg(parm_idx)) { bool nullable = arg_type->maybe_null(); - ciInlineKlass* vk = arg_type->inline_klass(); - InlineTypeNode* it = InlineTypeNode::make_from_multi(&kit, call, vk, in_idx, true, !nullable); + ciValueKlass* vk = arg_type->value_klass(); + ValueTypeNode* it = ValueTypeNode::make_from_multi(&kit, call, vk, in_idx, true, !nullable); kit.push(gvn.transform(it)); } else { kit.push(call->in(in_idx)); diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index 4bc95eec13fc..ae3c3490e369 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -2882,6 +2882,13 @@ Node* XorVNode::Ideal_XorV_to_VectorBitwiseBlend(PhaseGVN* phase, bool can_resha return nullptr; } + // Dead code can leave TOP on the inputs. TOP is a unique node, so the + // identity checks above match it spuriously, and VectorBitwiseBlendNode + // requires all of its inputs to be vectors. + if (a->is_top() || b->is_top() || sel->is_top()) { + return nullptr; + } + Node* blend = new VectorBitwiseBlendNode(a, b, sel, vt); if (!is_masked) { return blend; diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index f989c6b25672..fdbb405cb0b8 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -52,7 +52,6 @@ #include "oops/access.inline.hpp" #include "oops/arrayOop.inline.hpp" #include "oops/flatArrayOop.inline.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/instanceOop.hpp" #include "oops/klass.inline.hpp" @@ -65,6 +64,7 @@ #include "oops/symbol.hpp" #include "oops/typeArrayKlass.hpp" #include "oops/typeArrayOop.inline.hpp" +#include "oops/valueKlass.inline.hpp" #include "oops/valuePayload.inline.hpp" #include "prims/jniCheck.hpp" #include "prims/jniExport.hpp" @@ -183,7 +183,7 @@ extern LONG WINAPI topLevelExceptionFilter(_EXCEPTION_POINTERS* ); // out-of-line helpers for class jfieldIDWorkaround: bool jfieldIDWorkaround::is_valid_jfieldID(Klass* k, jfieldID id) { - if (jfieldIDWorkaround::is_instance_jfieldID(k, id)) { + if (jfieldIDWorkaround::is_instance_jfieldID(id)) { uintptr_t as_uint = (uintptr_t) id; int offset = raw_instance_offset(id); if (is_checked_jfieldID(id)) { @@ -244,7 +244,7 @@ bool jfieldIDWorkaround::klass_hash_ok(Klass* k, jfieldID id) { } void jfieldIDWorkaround::verify_instance_jfieldID(Klass* k, jfieldID id) { - guarantee(jfieldIDWorkaround::is_instance_jfieldID(k, id), "must be an instance field" ); + guarantee(jfieldIDWorkaround::is_instance_jfieldID(id), "must be an instance field" ); uintptr_t as_uint = (uintptr_t) id; int offset = raw_instance_offset(id); if (VerifyJNIFields) { @@ -1925,7 +1925,7 @@ JNI_ENTRY_NO_PRESERVE(void, jni_SetObjectField(JNIEnv *env, jobject obj, jfieldI InstanceKlass *ik = InstanceKlass::cast(k); fieldDescriptor fd; ik->find_field_from_offset(offset, false, &fd); - if (fd.is_null_free_inline_type()) { + if (fd.is_null_free_value_type()) { THROW_MSG(vmSymbols::java_lang_NullPointerException(), "Cannot store null in a null-restricted field"); } } @@ -1937,7 +1937,7 @@ JNI_ENTRY_NO_PRESERVE(void, jni_SetObjectField(JNIEnv *env, jobject obj, jfieldI bool found = ik->find_field_from_offset(offset, false, &fd); assert(found, "Field not found"); FlatFieldPayload payload(instanceOop(o), &fd); - payload.write(inlineOop(JNIHandles::resolve(value)), CHECK); + payload.write(valueOop(JNIHandles::resolve(value)), CHECK); } log_debug_if_final_instance_field(thread, "SetObjectField", InstanceKlass::cast(k), offset); HOTSPOT_JNI_SETOBJECTFIELD_RETURN(); @@ -2225,7 +2225,7 @@ JNI_ENTRY_NO_PRESERVE(const jchar*, jni_GetStringChars( if (s_value != nullptr) { int s_len = java_lang_String::length(s, s_value); bool is_latin1 = java_lang_String::is_latin1(s); - buf = NEW_C_HEAP_ARRAY_RETURN_NULL(jchar, s_len + 1, mtInternal); // add one for zero termination + buf = NEW_C_HEAP_ARRAY_RETURN_NULL(jchar, s_len + 1, mtJNI); // add one for zero termination /* JNI Specification states return null on OOM */ if (buf != nullptr) { if (s_len > 0) { @@ -2304,7 +2304,7 @@ JNI_ENTRY(const char*, jni_GetStringUTFChars(JNIEnv *env, jstring string, jboole size_t length = java_lang_String::utf8_length(java_string, s_value); // JNI Specification states return null on OOM. // The resulting sequence doesn't have to be NUL-terminated but we do. - result = AllocateHeap(length + 1, mtInternal, AllocFailStrategy::RETURN_NULL); + result = AllocateHeap(length + 1, mtJNI, AllocFailStrategy::RETURN_NULL); if (result != nullptr) { java_lang_String::as_utf8_string(java_string, s_value, result, length + 1); if (isCopy != nullptr) { @@ -2469,7 +2469,7 @@ static char* get_bad_address() { static char* bad_address = nullptr; if (bad_address == nullptr) { size_t size = os::vm_allocation_granularity(); - bad_address = os::reserve_memory(size, mtInternal); + bad_address = os::reserve_memory(size, mtJNI); if (bad_address != nullptr) { os::protect_memory(bad_address, size, os::MEM_PROT_READ, /*is_committed*/false); @@ -2500,7 +2500,7 @@ JNI_ENTRY_NO_PRESERVE(ElementType*, \ result = (ElementType*)get_bad_address(); \ } else { \ /* JNI Specification states return null on OOM */ \ - result = NEW_C_HEAP_ARRAY_RETURN_NULL(ElementType, len, mtInternal); \ + result = NEW_C_HEAP_ARRAY_RETURN_NULL(ElementType, len, mtJNI); \ if (result != nullptr) { \ /* copy the array to the c chunk */ \ ArrayAccess<>::arraycopy_to_native(a, typeArrayOopDesc::element_offset(0), \ @@ -2924,7 +2924,7 @@ JNI_ENTRY(const jchar*, jni_GetStringCritical(JNIEnv *env, jstring string, jbool // Inflate latin1 encoded string to UTF16 typeArrayOop s_value = java_lang_String::value(s); int s_len = java_lang_String::length(s, s_value); - ret = NEW_C_HEAP_ARRAY_RETURN_NULL(jchar, s_len + 1, mtInternal); // add one for zero termination + ret = NEW_C_HEAP_ARRAY_RETURN_NULL(jchar, s_len + 1, mtJNI); // add one for zero termination /* JNI Specification states return null on OOM */ if (ret != nullptr) { for (int i = 0; i < s_len; i++) { @@ -2969,7 +2969,7 @@ JNI_ENTRY(jweak, jni_NewWeakGlobalRef(JNIEnv *env, jobject ref)) HOTSPOT_JNI_NEWWEAKGLOBALREF_ENTRY(env, ref); Handle ref_handle(thread, JNIHandles::resolve(ref)); - if (!ref_handle.is_null() && ref_handle->klass()->is_inline_klass()) { + if (!ref_handle.is_null() && ref_handle->klass()->is_value_klass()) { ResourceMark rm(THREAD); stringStream ss; ss.print("%s is not an identity class", ref_handle->klass()->external_name()); @@ -3213,7 +3213,7 @@ JNI_END JNI_ENTRY(jboolean, jni_HasIdentity(JNIEnv* env, jobject obj)) HOTSPOT_JNI_HASIDENTITY_ENTRY(env, obj); oop o = JNIHandles::resolve(obj); - if (o != nullptr && !o->klass()->is_inline_klass()) { + if (o != nullptr && !o->klass()->is_value_klass()) { HOTSPOT_JNI_HASIDENTITY_RETURN(JNI_TRUE); return JNI_TRUE; } else { diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index da92cffe5c7b..794de6c2f30a 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -60,7 +60,6 @@ #include "oops/constantPool.hpp" #include "oops/fieldStreams.inline.hpp" #include "oops/flatArrayKlass.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/instanceKlass.hpp" #include "oops/klass.inline.hpp" #include "oops/method.hpp" @@ -70,6 +69,7 @@ #include "oops/oopCast.inline.hpp" #include "oops/recordComponent.hpp" #include "oops/refArrayOop.inline.hpp" +#include "oops/valueKlass.inline.hpp" #include "oops/valuePayload.inline.hpp" #include "prims/foreignGlobals.hpp" #include "prims/jvm_misc.hpp" @@ -449,7 +449,7 @@ JVM_ENTRY(jarray, JVM_CopyOfSpecialArray(JNIEnv *env, jarray orig, jint from, ji dest = fak->allocate_instance(len, CHECK_NULL); } else { const ArrayProperties props = ArrayProperties::Default().with_null_restricted(ak->is_null_free_array_klass()); - InlineKlass* vk = InlineKlass::cast(ak->element_klass()); + ValueKlass* vk = ValueKlass::cast(ak->element_klass()); dest = oopFactory::new_objArray(vk, len, props, CHECK_NULL); } @@ -481,7 +481,7 @@ static void verify_array_arguments(jclass elmClass, jint len) { assert(elmClass != nullptr, "Null element class"); oop mirror = JNIHandles::resolve_non_null(elmClass); Klass* klass = java_lang_Class::as_Klass(mirror); - assert(klass->is_inline_klass(), "Element class must be an inline class"); + assert(klass->is_value_klass(), "Element class must be a value class"); } #endif // ASSERT @@ -790,7 +790,7 @@ JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle)) return 0; } oop obj = JNIHandles::resolve_non_null(handle); - if (Arguments::is_valhalla_enabled() && obj->klass()->is_inline_klass()) { + if (Arguments::is_valhalla_enabled() && obj->klass()->is_value_klass()) { const intptr_t obj_identity_hash = obj->mark().hash(); // Check if mark word contains hash code already. // It is possible that the generated identity hash is 0, which is not @@ -883,7 +883,7 @@ JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle)) THROW_MSG_NULL(vmSymbols::java_lang_CloneNotSupportedException(), klass->external_name()); } - if (klass->is_inline_klass()) { + if (klass->is_value_klass()) { // Value instances have no identity, so return the current instance instead of allocating a new one // Value classes cannot have finalizers, so the method can return immediately return JNIHandles::make_local(THREAD, obj()); diff --git a/src/hotspot/share/prims/jvmti.xml b/src/hotspot/share/prims/jvmti.xml index dd41d6b38a54..6e6bed1e8495 100644 --- a/src/hotspot/share/prims/jvmti.xml +++ b/src/hotspot/share/prims/jvmti.xml @@ -277,7 +277,7 @@ - + @@ -325,6 +325,9 @@ + + + @@ -3400,8 +3403,18 @@ err = (*jvmti)->Deallocate(jvmti, stack_info); method named <clinit> with a return type of void.

- When preview features are enabled, this function can not be used to return - early from the constructor of a value class. + When preview features are enabled, this function can not be used to force + a return when the current frame is a constructor of a class with + + strictly-initializedPREVIEW instance fields in the + class or any of its superclasses, or the current frame is the class initializer + of a class with strictly-initialized static fields. +

+ API Note: + + Value classesPREVIEW rely upon strict field + initialization. This function can not be used to return from a constructor + of a value class with one or more instance fields. new @@ -3418,8 +3431,11 @@ err = (*jvmti)->Deallocate(jvmti, stack_info); The implementation is unable to force the current frame to return - (e.g. current frame is executing a native method or if preview features - are enabled, the current frame is the constructor for a value class) + (e.g. the current frame is executing a native method or, if preview features + are enabled, either the current frame is a constructor of a class with + strictly-initialized instance fields in its class hierarchy or the current + frame is the class initializer of a class with strictly-initialized static + fields.) The called method has a result type. diff --git a/src/hotspot/share/prims/jvmti.xsl b/src/hotspot/share/prims/jvmti.xsl index 2ea29f8b0244..04fd122803af 100644 --- a/src/hotspot/share/prims/jvmti.xsl +++ b/src/hotspot/share/prims/jvmti.xsl @@ -1003,7 +1003,7 @@ typedef struct { - + @@ -2013,6 +2013,13 @@ typedef struct { + + + + + + + JVM TI diff --git a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp index 753992d20e8a..306ddfcb26e2 100644 --- a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp +++ b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp @@ -568,7 +568,7 @@ void JvmtiClassFileReconstituter::write_inner_classes_attribute(int length) { write_u2(iter.inner_name_index()); u2 flags = iter.inner_access_flags(); // ClassFileParser may add identity to inner class attributes, so remove it. - if (!ik()->supports_inline_types()) { + if (!ik()->supports_value_types()) { flags &= ~JVM_ACC_IDENTITY; } write_u2(flags); diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index 238d2a7c2c17..6f5280d3d5b1 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -3071,8 +3071,8 @@ JvmtiEnv::GetObjectHashCode(jobject object, jint* hash_code_ptr) { NULL_CHECK(mirror, JVMTI_ERROR_INVALID_OBJECT); NULL_CHECK(hash_code_ptr, JVMTI_ERROR_NULL_POINTER); - if (mirror->is_inline_type()) { - // For inline types, use the klass as a hash code. + if (mirror->is_value_type()) { + // For value types, use the klass as a hash code. // TBD to improve this (see also JvmtiTagMapKey::get_hash for similar case). *hash_code_ptr = (jint)((int64_t)mirror->klass() >> 3); } else { diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index 13325523684b..a5763c64a69f 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -2172,10 +2172,15 @@ JvmtiEnvBase::check_top_frame(Thread* current_thread, JavaThread* java_thread, return JVMTI_ERROR_OPAQUE_FRAME; } - // Prevent ForceEarlyReturnVoid from returning early from value class constructor as - // the instance fields are strictly-initialized fields. - if ((tos == vtos) && jvf->method()->is_object_constructor() && jvf->method()->method_holder()->is_inline_klass()) { - return JVMTI_ERROR_OPAQUE_FRAME; + // Prevent ForceEarlyReturnVoid from returning early from the class initializer of a class with + // strictly-initialized static fields, or a constructor of a class with strictly-initialized + // instance fields in the class hierarchy. + if (tos == vtos) { + Method* method = jvf->method(); + if ((method->is_class_initializer() && method->method_holder()->has_strict_static_fields()) || + (method->is_object_constructor() && method->method_holder()->has_strict_instance_fields_in_hierarchy())) { + return JVMTI_ERROR_OPAQUE_FRAME; + } } // If the frame is a compiled one, need to deoptimize it. diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index fd4376601961..6c0b8609a4fb 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -1138,7 +1138,7 @@ class JvmtiObjectAllocEventMark : public JvmtiClassEventMark { jlong _size; public: JvmtiObjectAllocEventMark(JavaThread *thread, oop obj) : JvmtiClassEventMark(thread, oop_to_klass(obj)) { - _jobj = obj->is_inline() ? nullptr : (jobject)to_jobject(obj); // nullptr for non-identity objects + _jobj = obj->is_value() ? nullptr : (jobject)to_jobject(obj); // nullptr for non-identity objects _size = obj->size() * wordSize; }; jobject jni_jobject() { return _jobj; } @@ -2969,7 +2969,7 @@ void JvmtiExport::post_vm_object_alloc(JavaThread *thread, oop object) { if (thread->should_hide_jvmti_events()) { return; } - const bool is_inline = object->is_inline(); + const bool is_inline = object->is_value(); if (is_inline && !JvmtiExport::can_support_value_objects()) { return; } @@ -3011,7 +3011,7 @@ void JvmtiExport::post_sampled_object_alloc(JavaThread *thread, oop object) { if (thread->should_hide_jvmti_events()) { return; } - const bool is_inline = object->is_inline(); + const bool is_inline = object->is_value(); if (is_inline && !JvmtiExport::can_support_value_objects()) { return; } diff --git a/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp b/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp index 1b2237b15b24..9c40dd4a9ae8 100644 --- a/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp +++ b/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp @@ -27,8 +27,8 @@ #include "classfile/javaClasses.hpp" #include "gc/shared/collectedHeap.hpp" #include "memory/universe.hpp" -#include "oops/inlineKlass.hpp" #include "oops/klass.inline.hpp" +#include "oops/valueKlass.hpp" #include "prims/jvmtiGetLoadedClasses.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaThread.hpp" diff --git a/src/hotspot/share/prims/jvmtiImpl.cpp b/src/hotspot/share/prims/jvmtiImpl.cpp index da84650732ab..52e53340558f 100644 --- a/src/hotspot/share/prims/jvmtiImpl.cpp +++ b/src/hotspot/share/prims/jvmtiImpl.cpp @@ -484,15 +484,15 @@ void VM_BaseGetOrSetLocal::check_and_clone_this_value_object() { assert(_type == T_OBJECT, "sanity check"); assert(obj != nullptr, "expected non-null oop"); - assert(obj_h()->is_inline(), "expected inline oop"); + assert(obj_h()->is_value(), "expected inline oop"); assert(_index == 0, "expected slot 0 for THIS object"); - InlineKlass* klass = InlineKlass::cast(obj_h()->klass()); - inlineOop obj_copy = klass->allocate_instance(_calling_thread); + ValueKlass* klass = ValueKlass::cast(obj_h()->klass()); + valueOop obj_copy = klass->allocate_instance(_calling_thread); if (obj_copy == nullptr) { _result = JVMTI_ERROR_OUT_OF_MEMORY; } else { - inlineOop thisObj = inlineOop(obj_h()); + valueOop thisObj = valueOop(obj_h()); // copy object payload into the object snapshot BufferedValuePayload src(thisObj); BufferedValuePayload dst(obj_copy, klass); @@ -642,7 +642,7 @@ void VM_BaseGetOrSetLocal::doit() { if (Arguments::is_valhalla_enabled()) { bool is_ctor = _jvf->method()->is_object_constructor(); - if (is_ctor && _index == 0 && obj != nullptr && obj->is_inline()) { + if (is_ctor && _index == 0 && obj != nullptr && obj->is_value()) { _need_clone = true; // need to allocate an object snapshot in doit_epilogue } } diff --git a/src/hotspot/share/prims/jvmtiTagMap.cpp b/src/hotspot/share/prims/jvmtiTagMap.cpp index d7b029db447f..5ab97765a8b7 100644 --- a/src/hotspot/share/prims/jvmtiTagMap.cpp +++ b/src/hotspot/share/prims/jvmtiTagMap.cpp @@ -39,7 +39,6 @@ #include "oops/constantPool.inline.hpp" #include "oops/fieldStreams.inline.hpp" #include "oops/flatArrayOop.inline.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/instanceMirrorKlass.hpp" #include "oops/klass.inline.hpp" #include "oops/objArrayKlass.hpp" @@ -47,6 +46,7 @@ #include "oops/oop.inline.hpp" #include "oops/oopCast.inline.hpp" #include "oops/typeArrayOop.inline.hpp" +#include "oops/valueKlass.inline.hpp" #include "oops/valuePayload.inline.hpp" #include "prims/jvmtiEventController.inline.hpp" #include "prims/jvmtiExport.hpp" @@ -231,14 +231,14 @@ class JvmtiTagMapFlatEntryConverter: public StackObj { // source flat value object Handle holder; int offset; - InlineKlass* inline_klass; + ValueKlass* value_klass; LayoutKind layout_kind; // converted heap-allocated object Handle dst; - Entry(): holder(), offset(0), inline_klass(nullptr), dst() {} - Entry(Handle holder, int offset, InlineKlass* inline_klass, LayoutKind lk) - : holder(holder), offset(offset), inline_klass(inline_klass), layout_kind(lk), dst() {} + Entry(): holder(), offset(0), value_klass(nullptr), dst() {} + Entry(Handle holder, int offset, ValueKlass* value_klass, LayoutKind lk) + : holder(holder), offset(offset), value_klass(value_klass), layout_kind(lk), dst() {} }; int _batch_size; @@ -264,7 +264,7 @@ class JvmtiTagMapFlatEntryConverter: public StackObj { Importer(GrowableArray& entries, int batch_size): _entries(entries), _batch_size(batch_size) {} bool do_entry(JvmtiFlatTagMapKey& key, jlong& tag) { - Entry entry(Handle(Thread::current(), key.holder()), key.offset(), key.inline_klass(), key.layout_kind()); + Entry entry(Handle(Thread::current(), key.holder()), key.offset(), key.value_klass(), key.layout_kind()); _entries.append(entry); return _entries.length() < _batch_size; @@ -280,7 +280,7 @@ class JvmtiTagMapFlatEntryConverter: public StackObj { EXCEPTION_MARK; Entry& entry = _entries.at(i); FlatValuePayload payload = FlatValuePayload::construct_from_parts( - entry.holder(), entry.offset, entry.inline_klass, entry.layout_kind); + entry.holder(), entry.offset, entry.value_klass, entry.layout_kind); oop obj = payload.read(JavaThread::current()); if (HAS_PENDING_EXCEPTION) { @@ -305,7 +305,7 @@ class JvmtiTagMapFlatEntryConverter: public StackObj { // some error during conversion, skip the entry continue; } - JvmtiHeapwalkObject obj(entry.holder(), entry.offset, entry.inline_klass, entry.layout_kind); + JvmtiHeapwalkObject obj(entry.holder(), entry.offset, entry.value_klass, entry.layout_kind); jlong tag = src_table->remove(obj); if (tag != 0) { // ensure the entry is still in the src_table @@ -440,8 +440,8 @@ class CallbackWrapper : public StackObj { _obj_size = (jlong)o.obj()->size() * wordSize; } else { // flat value object, we know its InstanceKlass - assert(_o.inline_klass() != nullptr, "must be"); - _obj_size = _o.inline_klass()->size() * wordSize; + assert(_o.value_klass() != nullptr, "must be"); + _obj_size = _o.value_klass()->size() * wordSize; } // get object tag @@ -584,7 +584,7 @@ class ClassFieldDescriptor: public CHeapObj { int _field_index; int _field_offset; char _field_type; - InlineKlass* _inline_klass; // nullptr for heap object + ValueKlass* _value_klass; // nullptr for heap object LayoutKind _layout_kind; public: ClassFieldDescriptor(int index, const FieldStreamBase& fld) : @@ -592,19 +592,19 @@ class ClassFieldDescriptor: public CHeapObj { if (fld.is_flat()) { const fieldDescriptor& fd = fld.field_descriptor(); InstanceKlass* holder_klass = fd.field_holder(); - InlineLayoutInfo* layout_info = holder_klass->inline_layout_info_adr(fd.index()); - _inline_klass = layout_info->klass(); + ValueFieldLayoutInfo* layout_info = holder_klass->value_field_layout_info_adr(fd.index()); + _value_klass = layout_info->klass(); _layout_kind = layout_info->kind(); } else { - _inline_klass = nullptr; + _value_klass = nullptr; _layout_kind = LayoutKind::REFERENCE; } } int field_index() const { return _field_index; } char field_type() const { return _field_type; } int field_offset() const { return _field_offset; } - bool is_flat() const { return _inline_klass != nullptr; } - InlineKlass* inline_klass() const { return _inline_klass; } + bool is_flat() const { return _value_klass != nullptr; } + ValueKlass* value_klass() const { return _value_klass; } LayoutKind layout_kind() const { return _layout_kind; } }; @@ -1377,16 +1377,16 @@ void IterateThroughHeapObjectClosure::visit_flat_fields(const JvmtiHeapwalkObjec int field_offset = field->field_offset(); if (obj.is_flat()) { // the object is inlined, its fields are stored without the header - field_offset += obj.offset() - obj.inline_klass()->payload_offset(); + field_offset += obj.offset() - obj.value_klass()->payload_offset(); } // check for possible nulls if (LayoutKindHelper::is_nullable_flat(field->layout_kind())) { address payload = cast_from_oop

(obj.obj()) + field_offset; - if (field->inline_klass()->is_payload_marked_as_null(payload)) { + if (field->value_klass()->is_payload_marked_as_null(payload)) { continue; } } - JvmtiHeapwalkObject field_obj(obj.obj(), field_offset, field->inline_klass(), field->layout_kind()); + JvmtiHeapwalkObject field_obj(obj.obj(), field_offset, field->value_klass(), field->layout_kind()); visit_object(field_obj); @@ -1401,7 +1401,7 @@ void IterateThroughHeapObjectClosure::visit_flat_array_elements(const JvmtiHeapw assert(!obj.is_flat() && obj.obj()->is_flatArray() , "sanity check"); flatArrayOop array = flatArrayOop(obj.obj()); FlatArrayKlass* fak = array->klass(); - InlineKlass* vk = fak->element_klass(); + ValueKlass* vk = fak->element_klass(); bool need_null_check = LayoutKindHelper::is_nullable_flat(fak->layout_kind()); for (int index = 0; index < array->length(); index++) { @@ -2890,7 +2890,7 @@ inline bool VM_HeapWalkOperation::iterate_over_flat_array(const JvmtiHeapwalkObj assert(!o.is_flat(), "Array object cannot be flattened"); flatArrayOop array = flatArrayOop(o.obj()); FlatArrayKlass* fak = array->klass(); - InlineKlass* vk = fak->element_klass(); + ValueKlass* vk = fak->element_klass(); bool need_null_check = LayoutKindHelper::is_nullable_flat(fak->layout_kind()); // array reference to its class @@ -3110,18 +3110,18 @@ inline bool VM_HeapWalkOperation::iterate_over_object(const JvmtiHeapwalkObject& int field_offset = field->field_offset(); if (o.is_flat()) { // the object is inlined, its fields are stored without the header - field_offset += o.offset() - o.inline_klass()->payload_offset(); + field_offset += o.offset() - o.value_klass()->payload_offset(); } if (!is_primitive_field_type(type)) { if (field->is_flat()) { // check for possible nulls if (LayoutKindHelper::is_nullable_flat(field->layout_kind())) { address payload = cast_from_oop
(o.obj()) + field_offset; - if (field->inline_klass()->is_payload_marked_as_null(payload)) { + if (field->value_klass()->is_payload_marked_as_null(payload)) { continue; } } - JvmtiHeapwalkObject field_obj(o.obj(), field_offset, field->inline_klass(), field->layout_kind()); + JvmtiHeapwalkObject field_obj(o.obj(), field_offset, field->value_klass(), field->layout_kind()); if (!CallbackInvoker::report_field_reference(o, field_obj, slot)) { return false; } diff --git a/src/hotspot/share/prims/jvmtiTagMapTable.cpp b/src/hotspot/share/prims/jvmtiTagMapTable.cpp index c1992e308ce8..9bdf5a575f1a 100644 --- a/src/hotspot/share/prims/jvmtiTagMapTable.cpp +++ b/src/hotspot/share/prims/jvmtiTagMapTable.cpp @@ -25,23 +25,23 @@ #include "memory/allocation.hpp" #include "memory/universe.hpp" #include "oops/fieldStreams.inline.hpp" -#include "oops/inlineKlass.hpp" #include "oops/oop.inline.hpp" +#include "oops/valueKlass.hpp" #include "oops/weakHandle.inline.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiTagMapTable.hpp" static unsigned get_value_object_hash(oop holder, int offset, Klass* klass) { - assert(klass->is_inline_klass(), "Must be InlineKlass"); - // For inline types, use the klass as a hash code and let the equals match the obj. + assert(klass->is_value_klass(), "Must be ValueKlass"); + // For value types, use the klass as a hash code and let the equals match the obj. // It might have a long bucket but TBD to improve this if a customer situation arises. return (unsigned)((int64_t)klass >> 3); } static unsigned get_value_object_hash(const JvmtiHeapwalkObject & obj) { assert(obj.is_value(), "Must be value class"); - return get_value_object_hash(obj.obj(), obj.offset(), obj.inline_klass()); + return get_value_object_hash(obj.obj(), obj.offset(), obj.value_klass()); } static bool equal_oops(oop obj1, oop obj2); // forward declaration @@ -71,14 +71,14 @@ static bool equal_fields(char type, oop obj1, int offset1, oop obj2, int offset2 ShouldNotReachHere(); } -static bool is_null_flat_field(oop obj, int offset, InlineKlass* klass) { +static bool is_null_flat_field(oop obj, int offset, ValueKlass* klass) { return klass->is_payload_marked_as_null(cast_from_oop
(obj) + offset); } // For heap-allocated objects offset is 0 and 'klass' is obj1->klass() (== obj2->klass()). -// For flattened objects offset is the offset in the holder object, 'klass' is inlined object class. +// For flattened objects offset is the offset in the holder object, 'klass' is value object class. // The object must be prechecked for non-null values. -static bool equal_value_objects(oop obj1, int offset1, oop obj2, int offset2, InlineKlass* klass) { +static bool equal_value_objects(oop obj1, int offset1, oop obj2, int offset2, ValueKlass* klass) { for (JavaFieldStream fld(klass); !fld.done(); fld.next()) { // ignore static fields if (fld.access_flags().is_static()) { @@ -88,8 +88,8 @@ static bool equal_value_objects(oop obj1, int offset1, oop obj2, int offset2, In int field_offset2 = offset2 + fld.offset() - (offset2 > 0 ? klass->payload_offset() : 0); if (fld.is_flat()) { // flat value field InstanceKlass* holder_klass = fld.field_holder(); - InlineKlass* field_klass = holder_klass->get_inline_type_field_klass(fld.index()); - if (!fld.is_null_free_inline_type()) { + ValueKlass* field_klass = holder_klass->get_value_type_field_klass(fld.index()); + if (!fld.is_null_free_value_type()) { bool field1_is_null = is_null_flat_field(obj1, field_offset1, field_klass); bool field2_is_null = is_null_flat_field(obj2, field_offset2, field_klass); if (field1_is_null != field2_is_null) { @@ -118,21 +118,21 @@ static bool equal_oops(oop obj1, oop obj2) { return true; } - if (obj1 != nullptr && obj2 != nullptr && obj1->klass() == obj2->klass() && obj1->is_inline_type()) { - InlineKlass* vk = InlineKlass::cast(obj1->klass()); + if (obj1 != nullptr && obj2 != nullptr && obj1->klass() == obj2->klass() && obj1->is_value_type()) { + ValueKlass* vk = ValueKlass::cast(obj1->klass()); return equal_value_objects(obj1, 0, obj2, 0, vk); } return false; } bool JvmtiHeapwalkObject::equals(const JvmtiHeapwalkObject& obj1, const JvmtiHeapwalkObject& obj2) { - if (obj1 == obj2) { // the same oop/offset/inline_klass + if (obj1 == obj2) { // the same oop/offset/value_klass return true; } - if (obj1.is_value() && obj1.inline_klass() == obj2.inline_klass()) { + if (obj1.is_value() && obj1.value_klass() == obj2.value_klass()) { // instances of the same value class - return equal_value_objects(obj1.obj(), obj1.offset(), obj2.obj(), obj2.offset(), obj1.inline_klass()); + return equal_value_objects(obj1.obj(), obj1.offset(), obj2.obj(), obj2.offset(), obj1.value_klass()); } return false; } @@ -178,7 +178,7 @@ void JvmtiTagMapKey::release_handle() { JvmtiHeapwalkObject JvmtiTagMapKey::heapwalk_object() const { if (_obj != nullptr) { - return JvmtiHeapwalkObject(_obj->obj(), _obj->offset(), _obj->inline_klass(), _obj->layout_kind()); + return JvmtiHeapwalkObject(_obj->obj(), _obj->offset(), _obj->value_klass(), _obj->layout_kind()); } oop obj = object_no_keepalive(); if (obj == nullptr) { @@ -245,7 +245,7 @@ jlong* JvmtiTagMapTable::lookup(const JvmtiHeapwalkObject& obj) const { } if (!obj.is_value() && !obj.obj()->has_identity_hash()) { - // Objects in the table all have a hashcode, unless inlined types. + // Objects in the table all have a hashcode, unless value types. return nullptr; } JvmtiTagMapKey entry(&obj); @@ -319,7 +319,7 @@ void JvmtiTagMapTable::remove_dead_entries(GrowableArray* objects) { } JvmtiFlatTagMapKey::JvmtiFlatTagMapKey(const JvmtiHeapwalkObject& obj) - : _holder(obj.obj()), _offset(obj.offset()), _inline_klass(obj.inline_klass()), _layout_kind(obj.layout_kind()) { + : _holder(obj.obj()), _offset(obj.offset()), _value_klass(obj.value_klass()), _layout_kind(obj.layout_kind()) { } JvmtiFlatTagMapKey::JvmtiFlatTagMapKey(const JvmtiFlatTagMapKey& src) : _h() { @@ -335,12 +335,12 @@ JvmtiFlatTagMapKey::JvmtiFlatTagMapKey(const JvmtiFlatTagMapKey& src) : _h() { // holder object is always null after a copy. _holder = nullptr; _offset = src._offset; - _inline_klass = src._inline_klass; + _value_klass = src._value_klass; _layout_kind = src._layout_kind; } JvmtiHeapwalkObject JvmtiFlatTagMapKey::heapwalk_object() const { - return JvmtiHeapwalkObject(_holder != nullptr ? _holder : holder_no_keepalive(), _offset, _inline_klass, _layout_kind); + return JvmtiHeapwalkObject(_holder != nullptr ? _holder : holder_no_keepalive(), _offset, _value_klass, _layout_kind); } oop JvmtiFlatTagMapKey::holder() const { @@ -359,14 +359,14 @@ void JvmtiFlatTagMapKey::release_handle() { } unsigned JvmtiFlatTagMapKey::get_hash(const JvmtiFlatTagMapKey& entry) { - return get_value_object_hash(entry._holder, entry._offset, entry._inline_klass); + return get_value_object_hash(entry._holder, entry._offset, entry._value_klass); } bool JvmtiFlatTagMapKey::equals(const JvmtiFlatTagMapKey& lhs, const JvmtiFlatTagMapKey& rhs) { - if (lhs._inline_klass == rhs._inline_klass) { + if (lhs._value_klass == rhs._value_klass) { oop lhs_obj = lhs._holder != nullptr ? lhs._holder : lhs._h.peek(); oop rhs_obj = rhs._holder != nullptr ? rhs._holder : rhs._h.peek(); - return equal_value_objects(lhs_obj, lhs._offset, rhs_obj, rhs._offset, lhs._inline_klass); + return equal_value_objects(lhs_obj, lhs._offset, rhs_obj, rhs._offset, lhs._value_klass); } return false; } diff --git a/src/hotspot/share/prims/jvmtiTagMapTable.hpp b/src/hotspot/share/prims/jvmtiTagMapTable.hpp index e1b5a2e9f558..6f39cb3c1934 100644 --- a/src/hotspot/share/prims/jvmtiTagMapTable.hpp +++ b/src/hotspot/share/prims/jvmtiTagMapTable.hpp @@ -34,40 +34,40 @@ class JvmtiEnv; // Describes an object which can be tagged during heap walk operation. -// - generic heap object: _obj: oop, offset == 0, _inline_klass == nullptr; -// - value heap object: _obj: oop, offset == 0, _inline_klass == _obj.klass(); -// - flat value object: _obj: holder object, offset == offset in the holder, _inline_klass == klass of the flattened object; +// - generic heap object: _obj: oop, offset == 0, _value_klass == nullptr; +// - value heap object: _obj: oop, offset == 0, _value_klass == _obj.klass(); +// - flat value object: _obj: holder object, offset == offset in the holder, _value_klass == klass of the flattened object; class JvmtiHeapwalkObject { - oop _obj; // for flattened value object this is holder object - int _offset; // == 0 for heap objects - InlineKlass* _inline_klass; // for value object, nullptr otherwise - LayoutKind _layout_kind; // layout kind in holder object, used only for flat->heap conversion + oop _obj; // for flattened value object this is holder object + int _offset; // == 0 for heap objects + ValueKlass* _value_klass; // for value object, nullptr otherwise + LayoutKind _layout_kind; // layout kind in holder object, used only for flat->heap conversion - static InlineKlass* inline_klass_or_null(oop obj) { + static ValueKlass* value_klass_or_null(oop obj) { Klass* k = obj->klass(); - return k->is_inline_klass() ? InlineKlass::cast(k) : nullptr; + return k->is_value_klass() ? ValueKlass::cast(k) : nullptr; } public: - JvmtiHeapwalkObject(): _obj(nullptr), _offset(0), _inline_klass(nullptr), _layout_kind(LayoutKind::UNKNOWN) {} - JvmtiHeapwalkObject(oop obj): _obj(obj), _offset(0), _inline_klass(inline_klass_or_null(obj)), _layout_kind(LayoutKind::REFERENCE) {} - JvmtiHeapwalkObject(oop obj, int offset, InlineKlass* ik, LayoutKind lk): _obj(obj), _offset(offset), _inline_klass(ik), _layout_kind(lk) {} + JvmtiHeapwalkObject(): _obj(nullptr), _offset(0), _value_klass(nullptr), _layout_kind(LayoutKind::UNKNOWN) {} + JvmtiHeapwalkObject(oop obj): _obj(obj), _offset(0), _value_klass(value_klass_or_null(obj)), _layout_kind(LayoutKind::REFERENCE) {} + JvmtiHeapwalkObject(oop obj, int offset, ValueKlass* vk, LayoutKind lk): _obj(obj), _offset(offset), _value_klass(vk), _layout_kind(lk) {} inline bool is_empty() const { return _obj == nullptr; } - inline bool is_value() const { return _inline_klass != nullptr; } + inline bool is_value() const { return _value_klass != nullptr; } inline bool is_flat() const { return _offset != 0; } inline oop obj() const { return _obj; } inline int offset() const { return _offset; } - inline InlineKlass* inline_klass() const { return _inline_klass; } + inline ValueKlass* value_klass() const { return _value_klass; } inline LayoutKind layout_kind() const { return _layout_kind; } - inline Klass* klass() const { return is_value() ? _inline_klass : obj()->klass(); } + inline Klass* klass() const { return is_value() ? _value_klass : obj()->klass(); } static bool equals(const JvmtiHeapwalkObject& obj1, const JvmtiHeapwalkObject& obj2); bool operator==(const JvmtiHeapwalkObject& other) const { - // need to compare inline_klass too to handle the case when flat object has flat field at offset 0 - return _obj == other._obj && _offset == other._offset && _inline_klass == other._inline_klass; + // need to compare value_klass too to handle the case when flat object has flat field at offset 0 + return _obj == other._obj && _offset == other._offset && _value_klass == other._value_klass; } bool operator!=(const JvmtiHeapwalkObject& other) const { return !(*this == other); @@ -166,7 +166,7 @@ class JvmtiFlatTagMapKey: public CHeapObj { // temporarily holds holder object while searching oop _holder; int _offset; - InlineKlass* _inline_klass; + ValueKlass* _value_klass; LayoutKind _layout_kind; public: JvmtiFlatTagMapKey(const JvmtiHeapwalkObject& obj); @@ -180,7 +180,7 @@ class JvmtiFlatTagMapKey: public CHeapObj { oop holder() const; oop holder_no_keepalive() const; int offset() const { return _offset; } - InlineKlass* inline_klass() const { return _inline_klass; } + ValueKlass* value_klass() const { return _value_klass; } LayoutKind layout_kind() const { return _layout_kind; } void release_handle(); diff --git a/src/hotspot/share/prims/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp index 27c6bda8126e..e1278930e8ec 100644 --- a/src/hotspot/share/prims/methodHandles.cpp +++ b/src/hotspot/share/prims/methodHandles.cpp @@ -375,7 +375,7 @@ oop MethodHandles::init_field_MemberName(Handle mname, fieldDescriptor& fd, bool assert((layout_kind & LAYOUT_MASK) == layout_kind, "Layout information loss"); flags |= layout_kind << LAYOUT_SHIFT; } - if (fd.is_null_free_inline_type()) flags |= NULL_RESTRICTED; + if (fd.is_null_free_value_type()) flags |= NULL_RESTRICTED; if (is_setter) flags += ((JVM_REF_putField - JVM_REF_getField) << REFERENCE_KIND_SHIFT); int vmindex = fd.offset(); // determines the field uniquely when combined with static bit @@ -667,6 +667,7 @@ void MethodHandles::print_as_basic_type_signature_on(outputStream* st, } else { st->put(cp[0]); } + prev_type = true; } } diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index 6bdcc1267eda..f14d2d6592a6 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -40,13 +40,13 @@ #include "oops/fieldStreams.inline.hpp" #include "oops/flatArrayKlass.hpp" #include "oops/flatArrayOop.inline.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/klass.inline.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/oopCast.inline.hpp" #include "oops/typeArrayOop.inline.hpp" +#include "oops/valueKlass.inline.hpp" #include "oops/valuePayload.hpp" #include "prims/jvmtiExport.hpp" #include "prims/unsafe.hpp" @@ -223,7 +223,7 @@ class MemoryAccess : StackObj { ATTRIBUTE_NO_UBSAN void put(T x) { GuardUnsafeAccess guard(_thread); - assert(_obj == nullptr || !_obj->is_inline_type(), "receiver cannot be an instance of a value class because they are immutable"); + assert(_obj == nullptr || !_obj->is_value_type(), "receiver cannot be an instance of a value class because they are immutable"); *addr() = normalize(x); } @@ -240,7 +240,7 @@ class MemoryAccess : StackObj { } }; -static void log_unsafe_value_access(oop p, jlong offset, InlineKlass* vk) { +static void log_unsafe_value_access(oop p, jlong offset, ValueKlass* vk) { Klass* k = p->klass(); if (log_is_enabled(Trace, valuetypes)) { ResourceMark rm; @@ -278,13 +278,13 @@ UNSAFE_ENTRY(void, Unsafe_PutReference(JNIEnv *env, jobject unsafe, jobject obj, oop x = JNIHandles::resolve(x_h); oop p = JNIHandles::resolve(obj); assert_field_offset_sane(p, offset); - assert(!p->is_inline_type(), "receiver cannot be an instance of a value class because they are immutable"); + assert(!p->is_value_type(), "receiver cannot be an instance of a value class because they are immutable"); HeapAccess::oop_store_at(p, offset, x); } UNSAFE_END UNSAFE_ENTRY(jlong, Unsafe_ValueHeaderSize(JNIEnv *env, jobject unsafe, jclass c)) { Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(c)); - InlineKlass* vk = InlineKlass::cast(k); + ValueKlass* vk = ValueKlass::cast(k); return vk->payload_offset(); } UNSAFE_END @@ -336,7 +336,7 @@ UNSAFE_ENTRY(jint, Unsafe_FieldLayout(JNIEnv *env, jobject unsafe, jobject field } else { InstanceKlass* ik = InstanceKlass::cast(k); if (ik->field_is_flat(slot)) { - return (jint)ik->inline_layout_info(slot).kind(); + return (jint)ik->value_field_layout_info(slot).kind(); } else { return (jint)LayoutKind::REFERENCE; } @@ -359,7 +359,7 @@ UNSAFE_ENTRY(jarray, Unsafe_NewSpecialArray(JNIEnv *env, jobject unsafe, jclass if (lk <= LayoutKind::REFERENCE || lk == LayoutKind::NULLABLE_NON_ATOMIC_FLAT || lk >= LayoutKind::UNKNOWN) { THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Invalid layout kind"); } - InlineKlass* vk = InlineKlass::cast(klass); + ValueKlass* vk = ValueKlass::cast(klass); // WARNING: test below will need modifications when flat layouts supported for fields // but not for arrays are introduce (NULLABLE_NON_ATOMIC_FLAT for instance) if (!UseArrayFlattening || !vk->is_layout_supported(lk)) { @@ -378,7 +378,7 @@ UNSAFE_ENTRY(jobject, Unsafe_GetFlatValue(JNIEnv *env, jobject unsafe, jobject o THROW_NULL(vmSymbols::java_lang_NullPointerException()); } Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(vc)); - InlineKlass* vk = InlineKlass::cast(k); + ValueKlass* vk = ValueKlass::cast(k); log_unsafe_value_access(base, offset, vk); LayoutKind lk = (LayoutKind)layoutKind; FlatValuePayload payload = FlatValuePayload::construct_from_parts(base, offset, vk, lk); @@ -394,11 +394,11 @@ UNSAFE_ENTRY(void, Unsafe_PutFlatValue(JNIEnv *env, jobject unsafe, jobject obj, THROW(vmSymbols::java_lang_NullPointerException()); } - InlineKlass* vk = InlineKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(vc))); + ValueKlass* vk = ValueKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(vc))); log_unsafe_value_access(base, offset, vk); LayoutKind lk = (LayoutKind)layoutKind; FlatValuePayload payload = FlatValuePayload::construct_from_parts(base, offset, vk, lk); - payload.write(inlineOop(JNIHandles::resolve(value)), CHECK); + payload.write(valueOop(JNIHandles::resolve(value)), CHECK); } UNSAFE_END UNSAFE_ENTRY(jobject, Unsafe_GetReferenceVolatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) { @@ -842,10 +842,10 @@ UNSAFE_ENTRY(jarray, Unsafe_GetFieldMap0(JNIEnv* env, jobject unsafe, jclass cla oop mirror = JNIHandles::resolve_non_null(clazz); Klass* k = java_lang_Class::as_Klass(mirror); - if (!k->is_inline_klass()) { + if (!k->is_value_klass()) { THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Argument is not a concrete value class"); } - InlineKlass* vk = InlineKlass::cast(k); + ValueKlass* vk = ValueKlass::cast(k); oop map = mirror->obj_field(vk->acmp_maps_offset()); return (jarray) JNIHandles::make_local(THREAD, map); } UNSAFE_END diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index a4578cf46f03..f58d3cb3281e 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -2045,7 +2045,7 @@ class CollectObjectOops : public BasicOopIterateClosure { void add_oop(oop o) { Handle oh = Handle(Thread::current(), o); - if (oh != nullptr && oh->is_inline_type()) { + if (oh != nullptr && oh->is_value_type()) { oh->oop_iterate(this); } else { _array->append(oh); @@ -2191,8 +2191,8 @@ WB_ENTRY(jint, WB_GetMarkWordOffset(JNIEnv* env, jobject o)) return oopDesc::mark_offset_in_bytes(); WB_END -WB_ENTRY(jlong, WB_GetInlineTypePattern(JNIEnv* env, jobject o)) - return markWord::inline_type_pattern; +WB_ENTRY(jlong, WB_GetValueTypePattern(JNIEnv* env, jobject o)) + return markWord::value_type_pattern; WB_END WB_ENTRY(jlong, WB_GetNullFreeArrayBitInPlace(JNIEnv* env, jobject o)) @@ -3120,7 +3120,7 @@ static JNINativeMethod methods[] = { {CC"printClasses0", CC"(Ljava/lang/String;I)Ljava/lang/String;", (void*)&WB_printClasses}, {CC"printMethods0", CC"(Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;", (void*)&WB_printMethods}, {CC"getMarkWordOffset", CC"()I", (void*)&WB_GetMarkWordOffset}, - {CC"getInlineTypePattern", CC"()J", (void*)&WB_GetInlineTypePattern}, + {CC"getValueTypePattern", CC"()J", (void*)&WB_GetValueTypePattern}, {CC"getNullFreeArrayBitInPlace", CC"()J", (void*)&WB_GetNullFreeArrayBitInPlace}, {CC"getFlatArrayBitInPlace", CC"()J", (void*)&WB_GetFlatArrayBitInPlace}, {CC"getMethodBooleanOption", diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index cff14087d75c..f687627de710 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -3513,8 +3513,8 @@ jint Arguments::apply_ergo() { WARN_IF_NOT_DEFAULT_FLAG(flag) \ FLAG_SET_DEFAULT(flag, false); - DISABLE_FLAG_AND_WARN_IF_NOT_DEFAULT(InlineTypePassFieldsAsArgs); - DISABLE_FLAG_AND_WARN_IF_NOT_DEFAULT(InlineTypeReturnedAsFields); + DISABLE_FLAG_AND_WARN_IF_NOT_DEFAULT(ValueTypePassFieldsAsArgs); + DISABLE_FLAG_AND_WARN_IF_NOT_DEFAULT(ValueTypeReturnedAsFields); DISABLE_FLAG_AND_WARN_IF_NOT_DEFAULT(UseArrayFlattening); DISABLE_FLAG_AND_WARN_IF_NOT_DEFAULT(UseFieldFlattening); DISABLE_FLAG_AND_WARN_IF_NOT_DEFAULT(UseNullFreeNonAtomicValueFlattening); @@ -3523,15 +3523,14 @@ jint Arguments::apply_ergo() { DISABLE_FLAG_AND_WARN_IF_NOT_DEFAULT(UseNullableNonAtomicValueFlattening); DISABLE_FLAG_AND_WARN_IF_NOT_DEFAULT(UseAcmpFastPath); DISABLE_FLAG_AND_WARN_IF_NOT_DEFAULT(UseHashcodeFastPath); - DISABLE_FLAG_AND_WARN_IF_NOT_DEFAULT(PrintInlineLayout); + DISABLE_FLAG_AND_WARN_IF_NOT_DEFAULT(PrintValueLayout); DISABLE_FLAG_AND_WARN_IF_NOT_DEFAULT(PrintFlatArrayLayout); - DISABLE_FLAG_AND_WARN_IF_NOT_DEFAULT(IgnoreAssertUnsetFields); WARN_IF_NOT_DEFAULT_FLAG(FlatArrayElementMaxOops); WARN_IF_NOT_DEFAULT_FLAG(ForceNonTearable); #ifdef ASSERT DISABLE_FLAG_AND_WARN_IF_NOT_DEFAULT(StressCallingConvention); DISABLE_FLAG_AND_WARN_IF_NOT_DEFAULT(PreloadClasses); - WARN_IF_NOT_DEFAULT_FLAG(PrintInlineKlassFields); + WARN_IF_NOT_DEFAULT_FLAG(PrintValueKlassFields); #endif #ifdef COMPILER1 DEBUG_ONLY(DISABLE_FLAG_AND_WARN_IF_NOT_DEFAULT(C1UseDelayedFlattenedFieldReads);) @@ -3557,11 +3556,11 @@ jint Arguments::apply_ergo() { DISABLE_FLAG_AND_WARN_IF_NO_FLATTENING(FlatteningBudget, 0); #undef DISABLE_FLAG_AND_WARN_IF_NO_FLATTENING if (is_interpreter_only() && !CDSConfig::is_dumping_archive() && !UseSharedSpaces) { - // Disable calling convention optimizations if inline types are not supported. + // Disable calling convention optimizations if value types are not supported. // Also these aren't useful in -Xint. However, don't disable them when dumping or using // the CDS archive, as the values must match between dumptime and runtime. - FLAG_SET_DEFAULT(InlineTypePassFieldsAsArgs, false); - FLAG_SET_DEFAULT(InlineTypeReturnedAsFields, false); + FLAG_SET_DEFAULT(ValueTypePassFieldsAsArgs, false); + FLAG_SET_DEFAULT(ValueTypeReturnedAsFields, false); } if (!UseNullFreeNonAtomicValueFlattening && !UseNullableAtomicValueFlattening && diff --git a/src/hotspot/share/runtime/basicLock.cpp b/src/hotspot/share/runtime/basicLock.cpp index 03d576ae5729..50cf52a93b1b 100644 --- a/src/hotspot/share/runtime/basicLock.cpp +++ b/src/hotspot/share/runtime/basicLock.cpp @@ -34,38 +34,3 @@ void BasicLock::print_on(outputStream* st, oop owner) const { mon->print_on(st); } } - -void BasicLock::move_to(oop obj, BasicLock* dest) { - // Check to see if we need to inflate the lock. This is only needed - // if an object is locked using "this" lightweight monitor. In that - // case, the displaced_header() is lock-neutral, because the - // displaced_header() contains the header for the originally unlocked - // object. However the lock could have already been inflated. But it - // does not matter, this inflation will just be a no-op. For other cases, - // the displaced header will be either 0x0 or 0x3, which are location - // independent, therefore the BasicLock is free to move. - // - // During OSR we may need to relocate a BasicLock (which contains a - // displaced word) from a location in an interpreter frame to a - // new location in a compiled frame. "this" refers to the source - // BasicLock in the interpreter frame. "dest" refers to the destination - // BasicLock in the new compiled frame. We *always* inflate in move_to() - // when the object is locked using "this" lightweight monitor. - // - // The always-Inflate policy works properly, but it depends on the - // inflated fast-path operations in fast_lock and fast_unlock to avoid - // performance problems. See x86/macroAssembler_x86.cpp: fast_lock() - // and fast_unlock() for examples. - // - // Note that there is a way to safely swing the object's markword from - // one stack location to another. This avoids inflation. Obviously, - // we need to ensure that both locations refer to the current thread's stack. - // There are some subtle concurrency issues, however, and since the benefit is - // small (given the support for inflated fast-path locking in the fast_lock, etc) - // we'll leave that optimization for another time. - - // Preserve the ObjectMonitor*, the cache is cleared when a box is reused - // and only read while the lock is held, so no stale ObjectMonitor* is - // encountered. - dest->set_object_monitor_cache(object_monitor_cache()); -} diff --git a/src/hotspot/share/runtime/basicLock.hpp b/src/hotspot/share/runtime/basicLock.hpp index ed580510aaf2..279910c87144 100644 --- a/src/hotspot/share/runtime/basicLock.hpp +++ b/src/hotspot/share/runtime/basicLock.hpp @@ -47,17 +47,12 @@ class BasicLock { public: BasicLock() : _monitor(nullptr) {} - void set_bad_monitor_deopt() { set_monitor(reinterpret_cast(badDispHeaderDeopt)); } - inline ObjectMonitor* object_monitor_cache() const; inline void clear_object_monitor_cache(); inline void set_object_monitor_cache(ObjectMonitor* mon); static int object_monitor_cache_offset_in_bytes() { return monitor_offset_in_bytes(); } void print_on(outputStream* st, oop owner) const; - - // move a basic lock (used during deoptimization) - void move_to(oop obj, BasicLock* dest); }; // A BasicObjectLock associates a specific Java object with a BasicLock. diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index e633d12278b8..d83b56f5ef4f 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -53,12 +53,12 @@ #include "oops/fieldStreams.inline.hpp" #include "oops/flatArrayKlass.hpp" #include "oops/flatArrayOop.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/method.hpp" #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" +#include "oops/valueKlass.inline.hpp" #include "oops/verifyOopClosure.hpp" #include "prims/jvmtiDeferredUpdates.hpp" #include "prims/jvmtiExport.hpp" @@ -379,9 +379,9 @@ static bool rematerialize_objects(JavaThread* current, int exec_mode, nmethod* c // In case of the return of multiple values, we must take care // of all oop return values. GrowableArray return_oops; - InlineKlass* vk = nullptr; + ValueKlass* vk = nullptr; if (save_oop_result && scope->return_scalarized()) { - vk = InlineKlass::returned_inline_klass(map); + vk = ValueKlass::returned_value_klass(map); if (vk != nullptr) { vk->save_oop_fields(map, return_oops); save_oop_result = false; @@ -402,7 +402,7 @@ static bool rematerialize_objects(JavaThread* current, int exec_mode, nmethod* c JavaThread* THREAD = current; // For exception macros. // Clear pending OOM if reallocation fails and return true indicating allocation failure if (vk != nullptr) { - realloc_failures = Deoptimization::realloc_inline_type_result(vk, map, return_oops, CHECK_AND_CLEAR_(true)); + realloc_failures = Deoptimization::realloc_value_type_result(vk, map, return_oops, CHECK_AND_CLEAR_(true)); } if (objects != nullptr) { realloc_failures = realloc_failures || Deoptimization::realloc_objects(current, &deoptee, &map, objects, CHECK_AND_CLEAR_(true)); @@ -413,7 +413,7 @@ static bool rematerialize_objects(JavaThread* current, int exec_mode, nmethod* c } else { JRT_BLOCK if (vk != nullptr) { - realloc_failures = Deoptimization::realloc_inline_type_result(vk, map, return_oops, THREAD); + realloc_failures = Deoptimization::realloc_value_type_result(vk, map, return_oops, THREAD); } if (objects != nullptr) { realloc_failures = realloc_failures || Deoptimization::realloc_objects(current, &deoptee, &map, objects, THREAD); @@ -428,7 +428,7 @@ static bool rematerialize_objects(JavaThread* current, int exec_mode, nmethod* c } if (save_oop_result || vk != nullptr) { // Restore result. - assert(return_oops.length() == 1, "no inline type"); + assert(return_oops.length() == 1, "no value type"); deoptee.set_saved_oop_result(&map, return_oops.pop()()); } return realloc_failures; @@ -1116,7 +1116,7 @@ bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, RegisterMap* // Check if the object may be null and has an additional null_marker input that needs // to be checked before using the field values. Skip re-allocation if it is null. - if (k->is_inline_klass() && sv->has_properties()) { + if (k->is_value_klass() && sv->has_properties()) { jint null_marker = StackValue::create_stack_value(fr, reg_map, sv->properties())->get_jint(); if (null_marker == 0) { continue; @@ -1137,7 +1137,7 @@ bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, RegisterMap* } } else if (k->is_flatArray_klass()) { FlatArrayKlass* ak = FlatArrayKlass::cast(k); - // Inline type array must be zeroed because not all memory is reassigned + // Value type array must be zeroed because not all memory is reassigned InternalOOMEMark iom(THREAD); obj = ak->allocate_instance(sv->field_size(), THREAD); } else if (k->is_typeArray_klass()) { @@ -1171,11 +1171,11 @@ bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, RegisterMap* return failures; } -// We're deoptimizing at the return of a call, inline type fields are +// We're deoptimizing at the return of a call, value type fields are // in registers. When we go back to the interpreter, it will expect a -// reference to an inline type instance. Allocate and initialize it from +// reference to a value type instance. Allocate and initialize it from // the register values here. -bool Deoptimization::realloc_inline_type_result(InlineKlass* vk, const RegisterMap& map, GrowableArray& return_oops, TRAPS) { +bool Deoptimization::realloc_value_type_result(ValueKlass* vk, const RegisterMap& map, GrowableArray& return_oops, TRAPS) { oop new_vt = vk->realloc_result(map, return_oops, THREAD); if (new_vt == nullptr) { CLEAR_PENDING_EXCEPTION; @@ -1274,9 +1274,9 @@ static GrowableArray* get_reassigned_fields(InstanceKlass* klas field._type = Signature::basic_type(fs.signature()); if (fs.is_flat()) { field._is_flat = true; - field._is_null_free = fs.is_null_free_inline_type(); - // Resolve klass of flat inline type field - field._klass = InlineKlass::cast(klass->get_inline_type_field_klass(fs.index())); + field._is_null_free = fs.is_null_free_value_type(); + // Resolve klass of flat value type field + field._klass = ValueKlass::cast(klass->get_value_type_field_klass(fs.index())); } fields->append(field); } @@ -1291,17 +1291,17 @@ static int reassign_fields_by_klass(InstanceKlass* klass, frame* fr, RegisterMap for (int i = 0; i < fields->length(); i++) { BasicType type = fields->at(i)._type; int offset = base_offset + fields->at(i)._offset; - // Check for flat inline type field before accessing the ScopeValue because it might not have any fields + // Check for flat value type field before accessing the ScopeValue because it might not have any fields if (fields->at(i)._is_flat) { - // Recursively re-assign flat inline type fields + // Recursively re-assign flat value type fields InstanceKlass* vk = fields->at(i)._klass; assert(vk != nullptr, "must be resolved"); - offset -= InlineKlass::cast(vk)->payload_offset(); // Adjust offset to omit oop header + offset -= ValueKlass::cast(vk)->payload_offset(); // Adjust offset to omit oop header svIndex = reassign_fields_by_klass(vk, fr, reg_map, sv, svIndex, obj, offset, CHECK_0); if (!fields->at(i)._is_null_free) { ScopeValue* scope_field = sv->field_at(svIndex); StackValue* value = StackValue::create_stack_value(fr, reg_map, scope_field); - int nm_offset = offset + InlineKlass::cast(vk)->null_marker_offset(); + int nm_offset = offset + ValueKlass::cast(vk)->null_marker_offset(); obj->bool_field_put(nm_offset, value->get_jint() & 1); svIndex++; } @@ -1385,13 +1385,13 @@ static int reassign_fields_by_klass(InstanceKlass* klass, frame* fr, RegisterMap return svIndex; } -// restore fields of an eliminated inline type array +// restore fields of an eliminated value type array void Deoptimization::reassign_flat_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, flatArrayOop obj, FlatArrayKlass* vak, TRAPS) { - InlineKlass* vk = vak->element_klass(); - assert(vk->maybe_flat_in_array(), "should only be used for flat inline type arrays"); + ValueKlass* vk = vak->element_klass(); + assert(vk->maybe_flat_in_array(), "should only be used for flat value type arrays"); // Adjust offset to omit oop header int base_offset = arrayOopDesc::base_offset_in_bytes(T_FLAT_ELEMENT) - vk->payload_offset(); - // Initialize all elements of the flat inline type array + // Initialize all elements of the flat value type array for (int i = 0; i < sv->field_size(); i++) { ObjectValue* val = sv->field_at(i)->as_ObjectValue(); int offset = base_offset + (i << Klass::layout_helper_log2_element_size(vak->layout_helper())); diff --git a/src/hotspot/share/runtime/deoptimization.hpp b/src/hotspot/share/runtime/deoptimization.hpp index 8338248517d4..68e56268b3ed 100644 --- a/src/hotspot/share/runtime/deoptimization.hpp +++ b/src/hotspot/share/runtime/deoptimization.hpp @@ -175,7 +175,7 @@ class Deoptimization : AllStatic { // Support for restoring non-escaping objects static bool realloc_objects(JavaThread* thread, frame* fr, RegisterMap* reg_map, GrowableArray* objects, TRAPS); - static bool realloc_inline_type_result(InlineKlass* vk, const RegisterMap& map, GrowableArray& return_oops, TRAPS); + static bool realloc_value_type_result(ValueKlass* vk, const RegisterMap& map, GrowableArray& return_oops, TRAPS); static void reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type); static void reassign_object_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, objArrayOop obj); static void reassign_flat_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, flatArrayOop obj, FlatArrayKlass* vak, TRAPS); diff --git a/src/hotspot/share/runtime/fieldDescriptor.cpp b/src/hotspot/share/runtime/fieldDescriptor.cpp index aa3bbb76c7f9..e4ed18c1c485 100644 --- a/src/hotspot/share/runtime/fieldDescriptor.cpp +++ b/src/hotspot/share/runtime/fieldDescriptor.cpp @@ -27,10 +27,10 @@ #include "oops/annotations.hpp" #include "oops/constantPool.hpp" #include "oops/fieldStreams.inline.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/instanceKlass.hpp" #include "oops/klass.inline.hpp" #include "oops/oop.inline.hpp" +#include "oops/valueKlass.inline.hpp" #include "runtime/arguments.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/handles.inline.hpp" @@ -45,7 +45,7 @@ Symbol* fieldDescriptor::generic_signature() const { bool fieldDescriptor::is_trusted_final() const { InstanceKlass* ik = field_holder(); - return is_final() && (is_static() || ik->is_hidden() || ik->is_record() || ik->is_inline_klass() + return is_final() && (is_static() || ik->is_hidden() || ik->is_record() || ik->is_value_klass() || (ik->is_abstract() && !ik->is_identity_class() && !ik->is_interface())); } @@ -191,24 +191,24 @@ void fieldDescriptor::print_on_for(outputStream* st, oop obj, int indent, int ba break; case T_ARRAY: case T_OBJECT: - if (is_flat()) { // only some inline types can be flat + if (is_flat()) { // only some value types can be flat bool is_null = false; - InlineKlass* vk = InlineKlass::cast(field_holder()->get_inline_type_field_klass(index())); + ValueKlass* vk = ValueKlass::cast(field_holder()->get_value_type_field_klass(index())); int field_offset = offset() - vk->payload_offset(); int nm_offset = 0; - if (!is_null_free_inline_type()) { + if (!is_null_free_value_type()) { assert(has_null_marker(), "should have null marker"); - InlineLayoutInfo* li = field_holder()->inline_layout_info_adr(index()); + ValueFieldLayoutInfo* li = field_holder()->value_field_layout_info_adr(index()); nm_offset = li->null_marker_offset(); - st->print("Flat inline type field '%s':", vk->name()->as_C_string()); + st->print("Flat value type field '%s':", vk->name()->as_C_string()); if (obj->byte_field_acquire(nm_offset) == 0) { st->print(" null"); is_null = true; } st->cr(); } else { - st->print_cr("Flat inline null-free type field '%s':", vk->name()->as_C_string()); + st->print_cr("Flat value null-free type field '%s':", vk->name()->as_C_string()); } // Print fields of flat field (recursively) is not null @@ -227,7 +227,7 @@ void fieldDescriptor::print_on_for(outputStream* st, oop obj, int indent, int ba } return; // Do not print underlying representation } - // Not flat inline type field, fall through + // Not flat value type field, fall through if (obj->obj_field(offset()) != nullptr) { obj->obj_field(offset())->print_value_on(st); } else { diff --git a/src/hotspot/share/runtime/fieldDescriptor.hpp b/src/hotspot/share/runtime/fieldDescriptor.hpp index b3ea827deba6..710b2a7410c1 100644 --- a/src/hotspot/share/runtime/fieldDescriptor.hpp +++ b/src/hotspot/share/runtime/fieldDescriptor.hpp @@ -93,7 +93,7 @@ class fieldDescriptor { bool is_transient() const { return access_flags().is_transient(); } bool is_strict() const { return access_flags().is_strict(); } inline bool is_flat() const; - inline bool is_null_free_inline_type() const; + inline bool is_null_free_value_type() const; inline bool has_null_marker() const; bool is_synthetic() const { return access_flags().is_synthetic(); } diff --git a/src/hotspot/share/runtime/fieldDescriptor.inline.hpp b/src/hotspot/share/runtime/fieldDescriptor.inline.hpp index bb146cd63953..b93f639bd83a 100644 --- a/src/hotspot/share/runtime/fieldDescriptor.inline.hpp +++ b/src/hotspot/share/runtime/fieldDescriptor.inline.hpp @@ -72,7 +72,7 @@ inline BasicType fieldDescriptor::field_type() const { } inline bool fieldDescriptor::is_flat() const { return field().field_flags().is_flat(); } -inline bool fieldDescriptor::is_null_free_inline_type() const { return field().field_flags().is_null_free_inline_type(); } +inline bool fieldDescriptor::is_null_free_value_type() const { return field().field_flags().is_null_free_value_type(); } inline bool fieldDescriptor::has_null_marker() const { return field().field_flags().has_null_marker(); } #endif // SHARE_RUNTIME_FIELDDESCRIPTOR_INLINE_HPP diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index e185c33c1af8..2d1191e8eb00 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -35,12 +35,12 @@ #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" -#include "oops/inlineKlass.hpp" #include "oops/markWord.hpp" #include "oops/method.inline.hpp" #include "oops/methodData.hpp" #include "oops/oop.inline.hpp" #include "oops/stackChunkOop.inline.hpp" +#include "oops/valueKlass.hpp" #include "oops/verifyOopClosure.hpp" #include "prims/methodHandles.hpp" #include "runtime/continuation.hpp" @@ -368,7 +368,7 @@ void frame::deoptimize(JavaThread* thread) { #ifdef COMPILER1 if (nm->is_compiled_by_c1() && nm->method()->has_scalarized_args() && - pc() < nm->verified_inline_entry_point()) { + pc() < nm->verified_value_entry_point()) { // The VEP and VIEP(RO) of C1-compiled methods call into the runtime to buffer scalarized value // type args. We can't deoptimize at that point because the buffers have not yet been initialized. // Also, if the method is synchronized, we first need to acquire the lock. @@ -377,8 +377,8 @@ void frame::deoptimize(JavaThread* thread) { #if defined ASSERT && !defined AARCH64 // Stub call site does not look like NativeCall on AArch64 NativeCall* call = nativeCall_before(this->pc()); address dest = call->destination(); - assert(dest == Runtime1::entry_for(StubId::c1_buffer_inline_args_no_receiver_id) || - dest == Runtime1::entry_for(StubId::c1_buffer_inline_args_id), "unexpected safepoint in entry point"); + assert(dest == Runtime1::entry_for(StubId::c1_buffer_value_args_no_receiver_id) || + dest == Runtime1::entry_for(StubId::c1_buffer_value_args_id), "unexpected safepoint in entry point"); #endif return; } diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 5288c6584b4b..99af89050fdb 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -806,7 +806,7 @@ const int ObjectAlignmentInBytes = 8; product(bool, PrintFieldLayout, false, DIAGNOSTIC, \ "Print field layout for each class") \ \ - product(bool, PrintInlineLayout, false, DIAGNOSTIC, \ + product(bool, PrintValueLayout, false, DIAGNOSTIC, \ "Print field layout for each value class or class containing " \ "inlined value fields") \ \ @@ -840,8 +840,9 @@ const int ObjectAlignmentInBytes = 8; product(uint, FlatteningBudget, 1024, EXPERIMENTAL, \ "Maximum size (in bytes) dedicated to flat fields in an instance")\ range(0, 1024 * 1024) \ - develop(ccstrlist, PrintInlineKlassFields, "", \ - "Print fields collected by InlineKlass::collect_fields") \ + \ + develop(ccstrlist, PrintValueKlassFields, "", \ + "Print fields collected by ValueKlass::collect_fields") \ \ /* Need to limit the extent of the padding to reasonable size. */\ /* 8K is well beyond the reasonable HW cache line size, even with */\ @@ -1782,8 +1783,6 @@ const int ObjectAlignmentInBytes = 8; product(bool, VerifyMethodHandles, trueInDebug, DIAGNOSTIC, \ "perform extra checks when constructing method handles") \ \ - product(bool, IgnoreAssertUnsetFields, false, DIAGNOSTIC, \ - "Ignore assert_unset_fields") \ \ product(bool, ShowHiddenFrames, false, DIAGNOSTIC, \ "show method handle implementation frames (usually hidden)") \ @@ -1956,11 +1955,11 @@ const int ObjectAlignmentInBytes = 8; product(bool, UseFastUnorderedTimeStamps, false, EXPERIMENTAL, \ "Use platform unstable time where supported for timestamps only") \ \ - product_pd(bool, InlineTypePassFieldsAsArgs, DIAGNOSTIC, \ - "Pass each inline type field as an argument at calls") \ + product_pd(bool, ValueTypePassFieldsAsArgs, DIAGNOSTIC, \ + "Pass each value type field as an argument at calls") \ \ - product_pd(bool, InlineTypeReturnedAsFields, DIAGNOSTIC, \ - "Return fields instead of an inline type reference") \ + product_pd(bool, ValueTypeReturnedAsFields, DIAGNOSTIC, \ + "Return fields instead of a value type reference") \ \ develop(bool, StressCallingConvention, false, \ "Stress the scalarized calling convention.") \ @@ -1969,7 +1968,7 @@ const int ObjectAlignmentInBytes = 8; "Preloading all classes from the LoadableDescriptors attribute") \ \ product(ccstrlist, ForceNonTearable, "", DIAGNOSTIC, \ - "List of inline classes which are forced to be atomic " \ + "List of value classes which are forced to be atomic " \ "(whitespace and commas separate names, " \ "and leading and trailing stars '*' are wildcards)") \ \ diff --git a/src/hotspot/share/runtime/handles.cpp b/src/hotspot/share/runtime/handles.cpp index 613b635ebc11..7d126831c612 100644 --- a/src/hotspot/share/runtime/handles.cpp +++ b/src/hotspot/share/runtime/handles.cpp @@ -24,9 +24,9 @@ #include "memory/allocation.inline.hpp" #include "oops/constantPool.hpp" -#include "oops/inlineKlass.hpp" #include "oops/method.hpp" #include "oops/oop.inline.hpp" +#include "oops/valueKlass.hpp" #include "runtime/atomicAccess.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaThread.hpp" diff --git a/src/hotspot/share/runtime/handles.hpp b/src/hotspot/share/runtime/handles.hpp index 4f36785b8f26..3729574b5db7 100644 --- a/src/hotspot/share/runtime/handles.hpp +++ b/src/hotspot/share/runtime/handles.hpp @@ -29,9 +29,9 @@ #include "oops/oop.hpp" #include "oops/oopsHierarchy.hpp" -class InlineKlass; class InstanceKlass; class Klass; +class ValueKlass; class Thread; //------------------------------------------------------------------------------------------------------------------------ diff --git a/src/hotspot/share/runtime/javaCalls.cpp b/src/hotspot/share/runtime/javaCalls.cpp index c836c99b7a22..498e85c236f6 100644 --- a/src/hotspot/share/runtime/javaCalls.cpp +++ b/src/hotspot/share/runtime/javaCalls.cpp @@ -30,9 +30,9 @@ #include "interpreter/interpreter.hpp" #include "interpreter/linkResolver.hpp" #include "memory/universe.hpp" -#include "oops/inlineKlass.hpp" #include "oops/method.inline.hpp" #include "oops/oop.inline.hpp" +#include "oops/valueKlass.hpp" #include "prims/jniCheck.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/handles.inline.hpp" @@ -373,10 +373,10 @@ void JavaCalls::call_helper(JavaValue* result, const methodHandle& method, JavaC } jobject value_buffer = nullptr; - if (InlineTypeReturnedAsFields && (result->get_type() == T_OBJECT)) { - // Pre allocate a buffered inline type in case the result is returned + if (ValueTypeReturnedAsFields && (result->get_type() == T_OBJECT)) { + // Pre allocate a buffered value type in case the result is returned // flattened by compiled code - InlineKlass* vk = method->returns_inline_type(); + ValueKlass* vk = method->returns_value_type(); if (vk != nullptr && vk->can_be_returned_as_fields()) { oop instance = vk->allocate_instance(CHECK); value_buffer = JNIHandles::make_local(thread, instance); diff --git a/src/hotspot/share/runtime/jfieldIDWorkaround.hpp b/src/hotspot/share/runtime/jfieldIDWorkaround.hpp index 9919b85183a8..f27598b2ce15 100644 --- a/src/hotspot/share/runtime/jfieldIDWorkaround.hpp +++ b/src/hotspot/share/runtime/jfieldIDWorkaround.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, 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 @@ -108,7 +108,7 @@ class jfieldIDWorkaround: AllStatic { public: static bool is_valid_jfieldID(Klass* k, jfieldID id); - static bool is_instance_jfieldID(Klass* k, jfieldID id) { + static bool is_instance_jfieldID(jfieldID id) { uintptr_t as_uint = (uintptr_t) id; return ((as_uint & instance_mask_in_place) != 0); } diff --git a/src/hotspot/share/runtime/jniHandles.cpp b/src/hotspot/share/runtime/jniHandles.cpp index 9568cbf7e79a..e54e75688d68 100644 --- a/src/hotspot/share/runtime/jniHandles.cpp +++ b/src/hotspot/share/runtime/jniHandles.cpp @@ -53,8 +53,8 @@ OopStorage* JNIHandles::_global_handles = nullptr; OopStorage* JNIHandles::_weak_global_handles = nullptr; void jni_handles_init() { - JNIHandles::_global_handles = OopStorageSet::create_strong("JNI Global", mtInternal); - JNIHandles::_weak_global_handles = OopStorageSet::create_weak("JNI Weak", mtInternal); + JNIHandles::_global_handles = OopStorageSet::create_strong("JNI Global", mtJNI); + JNIHandles::_weak_global_handles = OopStorageSet::create_weak("JNI Weak", mtJNI); } jobject JNIHandles::make_local(oop obj) { @@ -293,8 +293,8 @@ bool JNIHandles::is_same_object(jobject handle1, jobject handle2) { if (!ret && Arguments::is_valhalla_enabled()) { if (obj1 != nullptr && obj2 != nullptr && - obj1->klass() == obj2->klass() && obj1->klass()->is_inline_klass()) { - // The two references are different, they are not null and they are both inline types, + obj1->klass() == obj2->klass() && obj1->klass()->is_value_klass()) { + // The two references are different, they are not null and they are both value types, // a full substitutability test is required, calling ValueObjectMethods.isSubstitutable() // (similarly to InterpreterRuntime::is_substitutable). // The jobjects must be re-resolved as the no-keepalive variants are not safe to use diff --git a/src/hotspot/share/runtime/jniHandles.hpp b/src/hotspot/share/runtime/jniHandles.hpp index 230a3f5ca428..d29a4d1628b4 100644 --- a/src/hotspot/share/runtime/jniHandles.hpp +++ b/src/hotspot/share/runtime/jniHandles.hpp @@ -134,7 +134,7 @@ class JNIHandles : AllStatic { // JNI handle blocks holding local/global JNI handles -class JNIHandleBlock : public CHeapObj { +class JNIHandleBlock : public CHeapObj { friend class VMStructs; friend class ZeroInterpreter; diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index ee74afcaf1ff..00f0e4356b19 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -286,7 +286,6 @@ static void check_object_context() { } ObjectMonitor::ObjectMonitor(oop object) : - _metadata(0), _object(_oop_storage, object), _owner(NO_OWNER), _previous_owner_tid(0), @@ -2586,16 +2585,10 @@ void ObjectMonitor::print() const { print_on(tty); } // Print the ObjectMonitor like a debugger would: // // (ObjectMonitor) 0x00007fdfb6012e40 = { -// _metadata = 0x0000000000000001 // _object = 0x000000070ff45fd0 -// _pad_buf0 = { -// [0] = '\0' -// ... -// [43] = '\0' -// } // _owner = 0x0000000000000000 // _previous_owner_tid = 0 -// _pad_buf1 = { +// _pad_buf0 = { // [0] = '\0' // ... // [47] = '\0' @@ -2614,19 +2607,13 @@ void ObjectMonitor::print() const { print_on(tty); } // void ObjectMonitor::print_debug_style_on(outputStream* st) const { st->print_cr("(ObjectMonitor*) " INTPTR_FORMAT " = {", p2i(this)); - st->print_cr(" _metadata = " INTPTR_FORMAT, _metadata); st->print_cr(" _object = " INTPTR_FORMAT, p2i(object_peek())); - st->print_cr(" _pad_buf0 = {"); - st->print_cr(" [0] = '\\0'"); - st->print_cr(" ..."); - st->print_cr(" [%d] = '\\0'", (int)sizeof(_pad_buf0) - 1); - st->print_cr(" }"); st->print_cr(" _owner = " INT64_FORMAT, owner_raw()); st->print_cr(" _previous_owner_tid = " UINT64_FORMAT, _previous_owner_tid); - st->print_cr(" _pad_buf1 = {"); + st->print_cr(" _pad_buf0 = {"); st->print_cr(" [0] = '\\0'"); st->print_cr(" ..."); - st->print_cr(" [%d] = '\\0'", (int)sizeof(_pad_buf1) - 1); + st->print_cr(" [%d] = '\\0'", (int)sizeof(_pad_buf0) - 1); st->print_cr(" }"); st->print_cr(" _next_om = " INTPTR_FORMAT, p2i(next_om())); st->print_cr(" _recursions = %zd", _recursions); diff --git a/src/hotspot/share/runtime/objectMonitor.hpp b/src/hotspot/share/runtime/objectMonitor.hpp index 52bbebec88d5..06d604de3e32 100644 --- a/src/hotspot/share/runtime/objectMonitor.hpp +++ b/src/hotspot/share/runtime/objectMonitor.hpp @@ -27,7 +27,6 @@ #include "memory/allocation.hpp" #include "memory/padded.hpp" -#include "oops/markWord.hpp" #include "oops/oopHandle.hpp" #include "oops/weakHandle.hpp" #include "runtime/javaThread.hpp" @@ -97,16 +96,8 @@ class ObjectWaiter : public CHeapObj { // // ObjectMonitor Layout Overview/Highlights/Restrictions: // -// - For performance reasons we ensure the _metadata field is located at offset 0, -// which in turn means that ObjectMonitor can't inherit from any other class nor use -// any virtual member functions. -// - The _metadata and _owner fields should be separated by enough space -// to avoid false sharing due to parallel access by different threads. -// This is an advisory recommendation. // - The general layout of the fields in ObjectMonitor is: -// _metadata -// -// +// _object // _owner // // @@ -154,16 +145,7 @@ class ObjectMonitor : public CHeapObj { // ParkEvent of unblocker thread. static ParkEvent* _vthread_unparker_ParkEvent; - // Because of frequent access, the _metadata field is at offset zero (0), - // which is enforced by a STATIC_ASSERT() in metadata_addr(). - volatile uintptr_t _metadata; // contains the _object's hashCode WeakHandle _object; // backward object pointer - // Separate _metadata and _owner on different cache lines since both can - // have busy multi-threaded access. _metadata and _object are set at initial - // inflation. The _object does not change, so it is a good choice to share - // its cache line with _metadata. - DEFINE_PAD_MINUS_SIZE(0, OM_CACHE_LINE_SIZE, sizeof(_metadata) + - sizeof(WeakHandle)); static const int64_t NO_OWNER = 0; static const int64_t ANONYMOUS_OWNER = 1; @@ -175,7 +157,7 @@ class ObjectMonitor : public CHeapObj { // both can have busy multi-threaded access. _previous_owner_tid is only // changed by ObjectMonitor::exit() so it is a good choice to share the // cache line with _owner. - DEFINE_PAD_MINUS_SIZE(1, OM_CACHE_LINE_SIZE, sizeof(void* volatile) + + DEFINE_PAD_MINUS_SIZE(0, OM_CACHE_LINE_SIZE, sizeof(int64_t volatile) + sizeof(volatile uint64_t)); ObjectMonitor* _next_om; // Next ObjectMonitor* linkage volatile intx _recursions; // recursion count, 0 for first entry @@ -211,19 +193,11 @@ class ObjectMonitor : public CHeapObj { static int Knob_SpinLimit; static ByteSize object_offset() { return byte_offset_of(ObjectMonitor, _object); } - static ByteSize metadata_offset() { return byte_offset_of(ObjectMonitor, _metadata); } static ByteSize owner_offset() { return byte_offset_of(ObjectMonitor, _owner); } static ByteSize recursions_offset() { return byte_offset_of(ObjectMonitor, _recursions); } static ByteSize succ_offset() { return byte_offset_of(ObjectMonitor, _succ); } static ByteSize entry_list_offset() { return byte_offset_of(ObjectMonitor, _entry_list); } - uintptr_t metadata() const; - void set_metadata(uintptr_t value); - volatile uintptr_t* metadata_addr(); - - intptr_t hash() const; - void set_hash(intptr_t hash); - bool is_busy() const { // TODO-FIXME: assert _owner == NO_OWNER implies _recursions = 0 intptr_t ret_code = intptr_t(_waiters) | intptr_t(_entry_list); diff --git a/src/hotspot/share/runtime/objectMonitor.inline.hpp b/src/hotspot/share/runtime/objectMonitor.inline.hpp index 238c035c4b46..bc4b861fc6b2 100644 --- a/src/hotspot/share/runtime/objectMonitor.inline.hpp +++ b/src/hotspot/share/runtime/objectMonitor.inline.hpp @@ -30,7 +30,6 @@ #include "classfile/vmSymbols.hpp" #include "logging/log.hpp" #include "oops/access.inline.hpp" -#include "oops/markWord.hpp" #include "runtime/atomicAccess.hpp" #include "runtime/globals.hpp" #include "runtime/javaThread.inline.hpp" @@ -60,28 +59,6 @@ inline bool ObjectMonitor::is_entered(JavaThread* current) const { return false; } -inline uintptr_t ObjectMonitor::metadata() const { - return AtomicAccess::load(&_metadata); -} - -inline void ObjectMonitor::set_metadata(uintptr_t value) { - AtomicAccess::store(&_metadata, value); -} - -inline volatile uintptr_t* ObjectMonitor::metadata_addr() { - STATIC_ASSERT(std::is_standard_layout::value); - STATIC_ASSERT(offsetof(ObjectMonitor, _metadata) == 0); - return &_metadata; -} - -inline intptr_t ObjectMonitor::hash() const { - return metadata(); -} - -inline void ObjectMonitor::set_hash(intptr_t hash) { - set_metadata(hash); -} - inline int ObjectMonitor::waiters() const { return _waiters; } diff --git a/src/hotspot/share/runtime/objectMonitorTable.cpp b/src/hotspot/share/runtime/objectMonitorTable.cpp index 9f087ad5dee0..44bc939240ab 100644 --- a/src/hotspot/share/runtime/objectMonitorTable.cpp +++ b/src/hotspot/share/runtime/objectMonitorTable.cpp @@ -565,7 +565,9 @@ ObjectMonitorTable::Table* ObjectMonitorTable::grow_table(Table* curr) { } ObjectMonitor* ObjectMonitorTable::monitor_put_get(ObjectMonitor* monitor, oop obj) { - const intptr_t hash = obj->mark().hash(); + const markWord mark = obj->mark(); + assert(mark.has_hash(), "must have"); + const intptr_t hash = mark.hash(); Table* curr = _curr.load_acquire(); for (;;) { diff --git a/src/hotspot/share/runtime/reflection.cpp b/src/hotspot/share/runtime/reflection.cpp index ffcba6bb13fc..6da4d30be881 100644 --- a/src/hotspot/share/runtime/reflection.cpp +++ b/src/hotspot/share/runtime/reflection.cpp @@ -37,13 +37,13 @@ #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/arrayOop.inline.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/klass.inline.hpp" #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" +#include "oops/valueKlass.inline.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/handles.inline.hpp" @@ -874,7 +874,7 @@ oop Reflection::new_field(fieldDescriptor* fd, TRAPS) { if (fd->is_trusted_final()) { flags |= TRUSTED_FINAL; } - if (fd->is_null_free_inline_type()) { + if (fd->is_null_free_value_type()) { flags |= NULL_RESTRICTED; } java_lang_reflect_Field::set_flags(rh(), flags); diff --git a/src/hotspot/share/runtime/safepoint.cpp b/src/hotspot/share/runtime/safepoint.cpp index 85ae8b800f5e..7327deff2999 100644 --- a/src/hotspot/share/runtime/safepoint.cpp +++ b/src/hotspot/share/runtime/safepoint.cpp @@ -38,9 +38,9 @@ #include "logging/logStream.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" -#include "oops/inlineKlass.hpp" #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" +#include "oops/valueKlass.hpp" #include "runtime/atomicAccess.hpp" #include "runtime/deoptimization.hpp" #include "runtime/frame.inline.hpp" @@ -803,10 +803,10 @@ void ThreadSafepointState::handle_polling_page_exception() { bool return_oop = method->is_returning_oop(); HandleMark hm(self); GrowableArray return_values; - InlineKlass* vk = nullptr; - if (InlineTypeReturnedAsFields && return_oop) { - // Check if an inline type is returned as fields - vk = InlineKlass::returned_inline_klass(map, &return_oop, method); + ValueKlass* vk = nullptr; + if (ValueTypeReturnedAsFields && return_oop) { + // Check if a value type is returned as fields + vk = ValueKlass::returned_value_klass(map, &return_oop, method); if (vk != nullptr) { // We're at a safepoint at the return of a method that returns // multiple values. We must make sure we preserve the oop values diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index e00dd3213e19..491d193eb95a 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -54,12 +54,12 @@ #include "metaprogramming/primitiveConversions.hpp" #include "oops/access.hpp" #include "oops/fieldStreams.inline.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/klass.hpp" #include "oops/method.inline.hpp" #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" +#include "oops/valueKlass.inline.hpp" #include "prims/forte.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiThreadState.hpp" @@ -122,9 +122,9 @@ void SharedRuntime::generate_initial_stubs() { generate_throw_exception(StubId::shared_throw_StackOverflowError_id, CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError)); - if (InlineTypeReturnedAsFields) { - _store_inline_type_fields_to_buf_blob = - generate_return_value_stub(CAST_FROM_FN_PTR(address, SharedRuntime::store_inline_type_fields_to_buf)); + if (ValueTypeReturnedAsFields) { + _store_value_type_fields_to_buf_blob = + generate_return_value_stub(CAST_FROM_FN_PTR(address, SharedRuntime::store_value_type_fields_to_buf)); } } @@ -1284,9 +1284,9 @@ Handle SharedRuntime::find_callee_info_helper(vframeStream& vfst, Bytecodes::Cod } bool caller_is_c1 = callerFrame.is_compiled_frame() && callerFrame.cb()->as_nmethod()->is_compiled_by_c1(); if (!caller_is_c1 && callee->is_scalarized_arg(0)) { - // If the receiver is an inline type that is passed as fields, no oop is available + // If the receiver is a value type that is passed as fields, no oop is available // Resolve the call without receiver null checking. - assert(!callee->mismatch(), "calls with inline type receivers should never mismatch"); + assert(!callee->mismatch(), "calls with value type receivers should never mismatch"); assert(attached_method.not_null() && !attached_method->is_abstract(), "must have non-abstract attached method"); if (bc == Bytecodes::_invokeinterface) { bc = Bytecodes::_invokevirtual; // C2 optimistically replaces interface calls by virtual calls @@ -1539,7 +1539,7 @@ JRT_BLOCK_ENTRY(address, SharedRuntime::handle_wrong_method(JavaThread* current) return callee->get_c2i_no_clinit_check_entry(); } else { if (caller_frame.is_interpreted_frame()) { - return callee->get_c2i_inline_entry(); + return callee->get_c2i_value_entry(); } else { return callee->get_c2i_entry(); } @@ -1605,10 +1605,10 @@ address SharedRuntime::get_resolved_entry(JavaThread* current, methodHandle call if (caller_does_not_scalarize) { if (go_to_interpreter) { - return callee_method->get_c2i_inline_entry(); + return callee_method->get_c2i_value_entry(); } - assert(callee_method->verified_inline_code_entry() != nullptr, "Jump to zero!"); - return callee_method->verified_inline_code_entry(); + assert(callee_method->verified_value_code_entry() != nullptr, "Jump to zero!"); + return callee_method->verified_value_code_entry(); } else if (is_static_call || is_optimized) { if (go_to_interpreter) { return callee_method->get_c2i_entry(); @@ -1617,10 +1617,10 @@ address SharedRuntime::get_resolved_entry(JavaThread* current, methodHandle call return callee_method->verified_code_entry(); } else { if (go_to_interpreter) { - return callee_method->get_c2i_inline_ro_entry(); + return callee_method->get_c2i_value_ro_entry(); } - assert(callee_method->verified_inline_ro_code_entry() != nullptr, "Jump to zero!"); - return callee_method->verified_inline_ro_code_entry(); + assert(callee_method->verified_value_ro_code_entry() != nullptr, "Jump to zero!"); + return callee_method->verified_value_ro_code_entry(); } } @@ -1748,7 +1748,7 @@ methodHandle SharedRuntime::reresolve_call_site(bool& is_optimized, bool& caller // If the frame isn't a live compiled frame (i.e. deoptimized by the time we get here), no IC clearing must be done // for the caller. However, when the caller is C2 compiled and the callee a C1 or C2 compiled method, then we still - // need to figure out whether it was an optimized virtual call with an inline type receiver. Otherwise, we end up + // need to figure out whether it was an optimized virtual call with a value type receiver. Otherwise, we end up // using the wrong method entry point and accidentally skip the buffering of the receiver. methodHandle callee_method = find_callee_method(caller_does_not_scalarize, CHECK_(methodHandle())); const bool caller_is_compiled_and_not_deoptimized = caller.is_compiled_frame() && !caller.is_deoptimized_frame(); @@ -2034,7 +2034,7 @@ char* SharedRuntime::generate_class_cast_message( } char* SharedRuntime::generate_identity_exception_message(JavaThread* current, Klass* klass) { - assert(klass->is_inline_klass(), "Must be a concrete value class"); + assert(klass->is_value_klass(), "Must be a concrete value class"); const char* desc = "Cannot synchronize on an instance of value class "; const char* className = klass->external_name(); size_t msglen = strlen(desc) + strlen(className) + 1; @@ -2330,16 +2330,16 @@ class AdapterFingerPrint : public MetaspaceObj { const SigEntry& sig_entry = sig->at(index); BasicType bt = sig_entry._bt; if (bt == T_METADATA) { - // Found start of inline type in signature - assert(InlineTypePassFieldsAsArgs, "unexpected start of inline type"); + // Found start of value type in signature + assert(ValueTypePassFieldsAsArgs, "unexpected start of value type"); vt_count++; } else if (bt == T_VOID && prev_bt != T_LONG && prev_bt != T_DOUBLE) { - // Found end of inline type in signature - assert(InlineTypePassFieldsAsArgs, "unexpected end of inline type"); + // Found end of value type in signature + assert(ValueTypePassFieldsAsArgs, "unexpected end of value type"); vt_count--; assert(vt_count >= 0, "invalid vt_count"); } else if (vt_count == 0) { - // Widen fields that are not part of a scalarized inline type argument + // Widen fields that are not part of a scalarized value type argument assert(sig_entry._offset == -1, "invalid offset for argument that is not a flattened field %d", sig_entry._offset); bt = adapter_encoding(bt); } @@ -2700,16 +2700,16 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_simple_adapter(const methodHandl return _no_arg_handler; } else if (total_args_passed == 1) { if (!method->is_static()) { - if (InlineTypePassFieldsAsArgs && method->method_holder()->is_inline_klass()) { + if (ValueTypePassFieldsAsArgs && method->method_holder()->is_value_klass()) { return nullptr; } return _obj_arg_handler; } switch (method->signature()->char_at(1)) { case JVM_SIGNATURE_CLASS: { - if (InlineTypePassFieldsAsArgs) { + if (ValueTypePassFieldsAsArgs) { SignatureStream ss(method->signature()); - InlineKlass* vk = ss.as_inline_klass(method->method_holder()); + ValueKlass* vk = ss.as_value_klass(method->method_holder()); if (vk != nullptr) { return nullptr; } @@ -2726,12 +2726,12 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_simple_adapter(const methodHandl return _int_arg_handler; } } else if (total_args_passed == 2 && - !method->is_static() && (!InlineTypePassFieldsAsArgs || !method->method_holder()->is_inline_klass())) { + !method->is_static() && (!ValueTypePassFieldsAsArgs || !method->method_holder()->is_value_klass())) { switch (method->signature()->char_at(1)) { case JVM_SIGNATURE_CLASS: { - if (InlineTypePassFieldsAsArgs) { + if (ValueTypePassFieldsAsArgs) { SignatureStream ss(method->signature()); - InlineKlass* vk = ss.as_inline_klass(method->method_holder()); + ValueKlass* vk = ss.as_value_klass(method->method_holder()); if (vk != nullptr) { return nullptr; } @@ -2752,7 +2752,7 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_simple_adapter(const methodHandl } CompiledEntrySignature::CompiledEntrySignature(Method* method) : - _method(method), _num_inline_args(0), _has_inline_recv(false), + _method(method), _num_value_args(0), _has_value_recv(false), _regs(nullptr), _regs_cc(nullptr), _regs_cc_ro(nullptr), _args_on_stack(0), _args_on_stack_cc(0), _args_on_stack_cc_ro(0), _needs_stack_repair(false), _supers(nullptr) { @@ -2763,7 +2763,7 @@ CompiledEntrySignature::CompiledEntrySignature(Method* method) : // See if we can save space by sharing the same entry for VIEP and VIEP(RO), // or the same entry for VEP and VIEP(RO). -CodeOffsets::Entries CompiledEntrySignature::c1_inline_ro_entry_type() const { +CodeOffsets::Entries CompiledEntrySignature::c1_value_ro_entry_type() const { if (!has_scalarized_args()) { // VEP/VIEP/VIEP(RO) all share the same entry. There's no packing. return CodeOffsets::Verified_Entry; @@ -2773,27 +2773,27 @@ CodeOffsets::Entries CompiledEntrySignature::c1_inline_ro_entry_type() const { return CodeOffsets::Verified_Entry; } - if (has_inline_recv()) { - if (num_inline_args() == 1) { + if (has_value_recv()) { + if (num_value_args() == 1) { // Share same entry for VIEP and VIEP(RO). - // This is quite common: we have an instance method in an InlineKlass that has - // no inline type args other than . - return CodeOffsets::Verified_Inline_Entry; + // This is quite common: we have an instance method in an ValueKlass that has + // no value type args other than . + return CodeOffsets::Verified_Value_Entry; } else { - assert(num_inline_args() > 1, "must be"); + assert(num_value_args() > 1, "must be"); // No sharing: // VIEP(RO) -- is passed as object // VEP -- is passed as fields - return CodeOffsets::Verified_Inline_Entry_RO; + return CodeOffsets::Verified_Value_Entry_RO; } } - // Either a static method, or is not an inline type + // Either a static method, or is not a value type if (args_on_stack_cc() != args_on_stack_cc_ro()) { // No sharing: // Some arguments are passed on the stack, and we have inserted reserved entries // into the VEP, but we never insert reserved entries into the VIEP(RO). - return CodeOffsets::Verified_Inline_Entry_RO; + return CodeOffsets::Verified_Value_Entry_RO; } else { // Share same entry for VEP and VIEP(RO). return CodeOffsets::Verified_Entry; @@ -2905,13 +2905,13 @@ void CompiledEntrySignature::compute_calling_conventions(bool link_time) { int arg_num = 0; if (!_method->is_static()) { // We shouldn't scalarize 'this' in a value class constructor - if (holder->is_inline_klass() && InlineKlass::cast(holder)->can_be_passed_as_fields() && + if (holder->is_value_klass() && ValueKlass::cast(holder)->can_be_passed_as_fields() && !_method->is_object_constructor() && (link_time || _method->is_scalarized_arg(arg_num))) { - _sig_cc->appendAll(InlineKlass::cast(holder)->extended_sig()); + _sig_cc->appendAll(ValueKlass::cast(holder)->extended_sig()); _sig_cc->insert_before(1, SigEntry(T_OBJECT, 0, nullptr, false, true)); // buffer argument has_scalarized = true; - _has_inline_recv = true; - _num_inline_args++; + _has_value_recv = true; + _num_value_args++; } else { SigEntry::add_entry(_sig_cc, T_OBJECT, holder->name()); } @@ -2921,8 +2921,8 @@ void CompiledEntrySignature::compute_calling_conventions(bool link_time) { } for (SignatureStream ss(_method->signature()); !ss.at_return_type(); ss.next()) { const BasicType bt = ss.type(); - if (InlineTypePassFieldsAsArgs && bt == T_OBJECT) { - InlineKlass* vk = ss.as_inline_klass(holder); + if (ValueTypePassFieldsAsArgs && bt == T_OBJECT) { + ValueKlass* vk = ss.as_value_klass(holder); if (vk != nullptr && vk->can_be_passed_as_fields() && (link_time || _method->is_scalarized_arg(arg_num))) { // Check for a calling convention mismatch with super method(s) if (link_time && check_supers_and_deoptimize(arg_num)) { @@ -2930,7 +2930,7 @@ void CompiledEntrySignature::compute_calling_conventions(bool link_time) { SigEntry::add_entry(_sig_cc, T_OBJECT, ss.as_symbol()); SigEntry::add_entry(_sig_cc_ro, T_OBJECT, ss.as_symbol()); } else { - _num_inline_args++; + _num_value_args++; has_scalarized = true; int last = _sig_cc->length(); int last_ro = _sig_cc_ro->length(); @@ -2939,7 +2939,7 @@ void CompiledEntrySignature::compute_calling_conventions(bool link_time) { // buffer argument _sig_cc->insert_before(last + 1, SigEntry(T_OBJECT, 0, nullptr, false, true)); _sig_cc_ro->insert_before(last_ro + 1, SigEntry(T_OBJECT, 0, nullptr, false, true)); - // Insert InlineTypeNode::NullMarker field right after T_METADATA delimiter + // Insert ValueTypeNode::NullMarker field right after T_METADATA delimiter _sig_cc->insert_before(last + 2, SigEntry(T_BOOLEAN, -1, nullptr, true, false)); _sig_cc_ro->insert_before(last_ro + 2, SigEntry(T_BOOLEAN, -1, nullptr, true, false)); } @@ -2962,7 +2962,7 @@ void CompiledEntrySignature::compute_calling_conventions(bool link_time) { _regs = NEW_RESOURCE_ARRAY(VMRegPair, _sig->length()); _args_on_stack = SharedRuntime::java_calling_convention(_sig, _regs); - // Compute the scalarized calling conventions if there are scalarized inline types in the signature + // Compute the scalarized calling conventions if there are scalarized value types in the signature if (has_scalarized && !_method->is_native()) { _regs_cc = NEW_RESOURCE_ARRAY(VMRegPair, _sig_cc->length()); _args_on_stack_cc = SharedRuntime::java_calling_convention(_sig_cc, _regs_cc); @@ -2984,12 +2984,12 @@ void CompiledEntrySignature::compute_calling_conventions(bool link_time) { // receiver would help. If so, use the receiver-as-oop convention for the // method body but keep scalarizing the other arguments. This also preserves // the convention used by calls through super methods. - if (_has_inline_recv && _args_on_stack_cc_ro <= max_stack_slots && _num_inline_args > 1) { + if (_has_value_recv && _args_on_stack_cc_ro <= max_stack_slots && _num_value_args > 1) { _sig_cc = _sig_cc_ro; _args_on_stack_cc = SharedRuntime::java_calling_convention(_sig_cc, _regs_cc); assert(_args_on_stack_cc == _args_on_stack_cc_ro, "calling conventions must match"); - _has_inline_recv = false; - _num_inline_args--; + _has_value_recv = false; + _num_value_args--; _needs_stack_repair = _args_on_stack_cc > _args_on_stack; return; // Success } @@ -3017,7 +3017,7 @@ void CompiledEntrySignature::compute_calling_conventions(bool link_time) { } void CompiledEntrySignature::initialize_from_fingerprint(AdapterFingerPrint* fingerprint) { - _has_inline_recv = fingerprint->has_ro_adapter(); + _has_value_recv = fingerprint->has_ro_adapter(); int value_object_count = 0; BasicType prev_bt = T_ILLEGAL; @@ -3052,7 +3052,7 @@ void CompiledEntrySignature::initialize_from_fingerprint(AdapterFingerPrint* fin switch (bt) { case T_VOID: if (prev_bt != T_LONG && prev_bt != T_DOUBLE) { - assert(InlineTypePassFieldsAsArgs, "unexpected end of inline type"); + assert(ValueTypePassFieldsAsArgs, "unexpected end of value type"); value_object_count--; SigEntry::add_entry(_sig_cc, T_VOID, nullptr, offset); if (!skipping_inline_recv) { @@ -3094,13 +3094,13 @@ void CompiledEntrySignature::initialize_from_fingerprint(AdapterFingerPrint* fin } break; case T_METADATA: - assert(InlineTypePassFieldsAsArgs, "unexpected start of inline type"); + assert(ValueTypePassFieldsAsArgs, "unexpected start of value type"); if (value_object_count == 0) { SigEntry::add_entry(_sig, T_OBJECT); } SigEntry::add_entry(_sig_cc, T_METADATA, nullptr, offset); if (!skipping_inline_recv) { - if (!receiver_handled && _has_inline_recv && value_object_count == 0) { + if (!receiver_handled && _has_value_recv && value_object_count == 0) { SigEntry::add_entry(_sig_cc_ro, T_OBJECT); skipping_inline_recv = true; receiver_handled = true; @@ -3127,7 +3127,7 @@ void CompiledEntrySignature::initialize_from_fingerprint(AdapterFingerPrint* fin assert(value_object_count == 0, "invalid value object count"); #ifdef ASSERT - if (_has_inline_recv) { + if (_has_value_recv) { // In RO signatures, inline receivers must be represented as a single T_OBJECT assert(_sig_cc_ro->length() >= 1, "sig_cc_ro must include receiver"); assert(_sig_cc_ro->at(0)._bt == T_OBJECT, @@ -3140,7 +3140,7 @@ void CompiledEntrySignature::initialize_from_fingerprint(AdapterFingerPrint* fin _regs = NEW_RESOURCE_ARRAY(VMRegPair, _sig->length()); _args_on_stack = SharedRuntime::java_calling_convention(_sig, _regs); - // Compute the scalarized calling conventions if there are scalarized inline types in the signature + // Compute the scalarized calling conventions if there are scalarized value types in the signature if (has_scalarized_arguments) { _regs_cc = NEW_RESOURCE_ARRAY(VMRegPair, _sig_cc->length()); _args_on_stack_cc = SharedRuntime::java_calling_convention(_sig_cc, _regs_cc); @@ -3163,7 +3163,7 @@ void CompiledEntrySignature::initialize_from_fingerprint(AdapterFingerPrint* fin #ifdef ASSERT { - AdapterFingerPrint* compare_fp = AdapterFingerPrint::allocate(_sig_cc, _has_inline_recv); + AdapterFingerPrint* compare_fp = AdapterFingerPrint::allocate(_sig_cc, _has_value_recv); assert(fingerprint->equals(compare_fp), "%s - %s", fingerprint->as_string(), compare_fp->as_string()); AdapterFingerPrint::deallocate(compare_fp); } @@ -3188,7 +3188,7 @@ void AdapterHandlerLibrary::verify_adapter_sharing(CompiledEntrySignature& ces, #endif /* ASSERT*/ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& method) { - assert(!method->is_abstract() || InlineTypePassFieldsAsArgs, "abstract methods do not have adapters"); + assert(!method->is_abstract() || ValueTypePassFieldsAsArgs, "abstract methods do not have adapters"); // Use customized signature handler. Need to lock around updates to // the _adapter_handler_table (it is not safe for concurrent readers // and a single writer: this could be fixed if it becomes a @@ -3218,7 +3218,7 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& meth MutexLocker mu(AdapterHandlerLibrary_lock); // Lookup method signature's fingerprint - entry = lookup(ces.sig_cc(), ces.has_inline_recv()); + entry = lookup(ces.sig_cc(), ces.has_value_recv()); if (entry != nullptr) { #ifndef ZERO @@ -3285,10 +3285,10 @@ void AdapterHandlerLibrary::address_to_offset(address entry_address[AdapterBlob: int entry_offset[AdapterBlob::ENTRY_COUNT]) { entry_offset[AdapterBlob::I2C] = 0; entry_offset[AdapterBlob::C2I] = entry_address[AdapterBlob::C2I] - entry_address[AdapterBlob::I2C]; - entry_offset[AdapterBlob::C2I_Inline] = entry_address[AdapterBlob::C2I_Inline] - entry_address[AdapterBlob::I2C]; - entry_offset[AdapterBlob::C2I_Inline_RO] = entry_address[AdapterBlob::C2I_Inline_RO] - entry_address[AdapterBlob::I2C]; + entry_offset[AdapterBlob::C2I_Value] = entry_address[AdapterBlob::C2I_Value] - entry_address[AdapterBlob::I2C]; + entry_offset[AdapterBlob::C2I_Value_RO] = entry_address[AdapterBlob::C2I_Value_RO] - entry_address[AdapterBlob::I2C]; entry_offset[AdapterBlob::C2I_Unverified] = entry_address[AdapterBlob::C2I_Unverified] - entry_address[AdapterBlob::I2C]; - entry_offset[AdapterBlob::C2I_Unverified_Inline] = entry_address[AdapterBlob::C2I_Unverified_Inline] - entry_address[AdapterBlob::I2C]; + entry_offset[AdapterBlob::C2I_Unverified_Value] = entry_address[AdapterBlob::C2I_Unverified_Value] - entry_address[AdapterBlob::I2C]; if (entry_address[AdapterBlob::C2I_No_Clinit_Check] == nullptr) { entry_offset[AdapterBlob::C2I_No_Clinit_Check] = -1; } else { @@ -3381,7 +3381,7 @@ bool AdapterHandlerLibrary::generate_adapter_code(AdapterHandlerEntry* handler, AdapterHandlerEntry* AdapterHandlerLibrary::create_adapter(CompiledEntrySignature& ces, bool allocate_code_blob, bool is_transient) { - AdapterFingerPrint* fp = AdapterFingerPrint::allocate(ces.sig_cc(), ces.has_inline_recv()); + AdapterFingerPrint* fp = AdapterFingerPrint::allocate(ces.sig_cc(), ces.has_value_recv()); #ifdef ASSERT // Verify that we can successfully restore the compiled entry signature object. CompiledEntrySignature ces_verify; @@ -3533,29 +3533,29 @@ void AdapterHandlerLibrary::lookup_simple_adapters() { ResourceMark rm; CompiledEntrySignature no_args; no_args.compute_calling_conventions(); - _no_arg_handler = lookup(no_args.sig_cc(), no_args.has_inline_recv()); + _no_arg_handler = lookup(no_args.sig_cc(), no_args.has_value_recv()); CompiledEntrySignature obj_args; SigEntry::add_entry(obj_args.sig(), T_OBJECT); obj_args.compute_calling_conventions(); - _obj_arg_handler = lookup(obj_args.sig_cc(), obj_args.has_inline_recv()); + _obj_arg_handler = lookup(obj_args.sig_cc(), obj_args.has_value_recv()); CompiledEntrySignature int_args; SigEntry::add_entry(int_args.sig(), T_INT); int_args.compute_calling_conventions(); - _int_arg_handler = lookup(int_args.sig_cc(), int_args.has_inline_recv()); + _int_arg_handler = lookup(int_args.sig_cc(), int_args.has_value_recv()); CompiledEntrySignature obj_int_args; SigEntry::add_entry(obj_int_args.sig(), T_OBJECT); SigEntry::add_entry(obj_int_args.sig(), T_INT); obj_int_args.compute_calling_conventions(); - _obj_int_arg_handler = lookup(obj_int_args.sig_cc(), obj_int_args.has_inline_recv()); + _obj_int_arg_handler = lookup(obj_int_args.sig_cc(), obj_int_args.has_value_recv()); CompiledEntrySignature obj_obj_args; SigEntry::add_entry(obj_obj_args.sig(), T_OBJECT); SigEntry::add_entry(obj_obj_args.sig(), T_OBJECT); obj_obj_args.compute_calling_conventions(); - _obj_obj_arg_handler = lookup(obj_obj_args.sig_cc(), obj_obj_args.has_inline_recv()); + _obj_obj_arg_handler = lookup(obj_obj_args.sig_cc(), obj_obj_args.has_value_recv()); assert(_no_arg_handler != nullptr && _obj_arg_handler != nullptr && @@ -3805,13 +3805,12 @@ VMRegPair *SharedRuntime::find_callee_arguments(Symbol* sig, bool has_receiver, // // This code is used convert interpreter frames into compiled frames. It is // called from very start of a compiled OSR nmethod. A temp array is -// allocated to hold the interesting bits of the interpreter frame. All -// active locks are inflated to allow them to move. The displaced headers and -// active interpreter locals are copied into the temp buffer. Then we return -// back to the compiled code. The compiled code then pops the current -// interpreter frame off the stack and pushes a new compiled frame. Then it -// copies the interpreter locals and displaced headers where it wants. -// Finally it calls back to free the temp buffer. +// allocated to hold the interesting bits of the interpreter frame. The active +// object monitor oops and caches, and active interpreter locals are copied into +// the temp buffer. Then we return back to the compiled code. The compiled +// code then pops the current interpreter frame off the stack and pushes a new +// compiled frame. Then it copies the object monitor oops and caches, and +// interpreter locals where it wants. Finally it calls back to free the temp buffer. // // All of this is done NOT at any Safepoint, nor is any safepoint or GC allowed. @@ -3861,7 +3860,7 @@ JRT_LEAF(intptr_t*, SharedRuntime::OSR_migration_begin( JavaThread *current) ) (HeapWord*)&buf[0], max_locals); - // Inflate locks. Copy the displaced headers. Be careful, there can be holes. + // Copy the object monitor oops and caches. Be careful, there can be holes. int i = max_locals; for (BasicObjectLock *kptr2 = fr.interpreter_frame_monitor_end(); kptr2 < fr.interpreter_frame_monitor_begin(); @@ -3937,10 +3936,10 @@ void AdapterHandlerEntry::print_adapter_on(outputStream* st) const { if (adapter_blob() != nullptr) { st->print(" i2c: " INTPTR_FORMAT, p2i(get_i2c_entry())); st->print(" c2i: " INTPTR_FORMAT, p2i(get_c2i_entry())); - st->print(" c2iVE: " INTPTR_FORMAT, p2i(get_c2i_inline_entry())); - st->print(" c2iVROE: " INTPTR_FORMAT, p2i(get_c2i_inline_ro_entry())); + st->print(" c2iVE: " INTPTR_FORMAT, p2i(get_c2i_value_entry())); + st->print(" c2iVROE: " INTPTR_FORMAT, p2i(get_c2i_value_ro_entry())); st->print(" c2iUE: " INTPTR_FORMAT, p2i(get_c2i_unverified_entry())); - st->print(" c2iUVE: " INTPTR_FORMAT, p2i(get_c2i_unverified_inline_entry())); + st->print(" c2iUVE: " INTPTR_FORMAT, p2i(get_c2i_unverified_value_entry())); if (get_c2i_no_clinit_check_entry() != nullptr) { st->print(" c2iNCI: " INTPTR_FORMAT, p2i(get_c2i_no_clinit_check_entry())); } @@ -4029,11 +4028,11 @@ void SharedRuntime::on_slowpath_allocation_exit(JavaThread* current) { } // We are at a compiled code to interpreter call. We need backing -// buffers for all inline type arguments. Allocate an object array to +// buffers for all value type arguments. Allocate an object array to // hold them (convenient because once we're done with it we don't have // to worry about freeing it). -oop SharedRuntime::allocate_inline_types_impl(JavaThread* current, methodHandle callee, bool allocate_receiver, bool from_c1, TRAPS) { - assert(InlineTypePassFieldsAsArgs, "no reason to call this"); +oop SharedRuntime::allocate_value_types_impl(JavaThread* current, methodHandle callee, bool allocate_receiver, bool from_c1, TRAPS) { + assert(ValueTypePassFieldsAsArgs, "no reason to call this"); ResourceMark rm; // Retrieve arguments passed at the call @@ -4054,7 +4053,7 @@ oop SharedRuntime::allocate_inline_types_impl(JavaThread* current, methodHandle int nb_slots = 0; InstanceKlass* holder = callee->method_holder(); - allocate_receiver &= !callee->is_static() && holder->is_inline_klass() && callee->is_scalarized_arg(0); + allocate_receiver &= !callee->is_static() && holder->is_value_klass() && callee->is_scalarized_arg(0); if (allocate_receiver) { nb_slots++; } @@ -4087,7 +4086,7 @@ oop SharedRuntime::allocate_inline_types_impl(JavaThread* current, methodHandle oop* buffer = callerFrame.oopmapreg_to_oop_location(reg_pair.first(), ®_map2); guarantee(buffer != nullptr, "bad register save location"); instanceHandle h_buffer(THREAD, (instanceOop)*buffer); - InlineKlass* vk = InlineKlass::cast(holder); + ValueKlass* vk = ValueKlass::cast(holder); if (h_buffer.not_null()) { assert(h_buffer->klass() == vk, "buffer not of expected class"); } else { @@ -4126,7 +4125,7 @@ oop SharedRuntime::allocate_inline_types_impl(JavaThread* current, methodHandle oop* buffer = callerFrame.oopmapreg_to_oop_location(reg_pair.first(), ®_map2); guarantee(buffer != nullptr, "bad register save location"); instanceHandle h_buffer(THREAD, (instanceOop)*buffer); - InlineKlass* vk = ss.as_inline_klass(holder); + ValueKlass* vk = ss.as_value_klass(holder); assert(vk != nullptr, "Unexpected klass"); if (h_buffer.not_null()) { assert(h_buffer->klass() == vk, "buffer not of expected class"); @@ -4148,20 +4147,20 @@ oop SharedRuntime::allocate_inline_types_impl(JavaThread* current, methodHandle return array(); } -JRT_ENTRY(void, SharedRuntime::allocate_inline_types(JavaThread* current, Method* callee_method, bool allocate_receiver)) +JRT_ENTRY(void, SharedRuntime::allocate_value_types(JavaThread* current, Method* callee_method, bool allocate_receiver)) methodHandle callee(current, callee_method); - oop array = SharedRuntime::allocate_inline_types_impl(current, callee, allocate_receiver, false, CHECK); + oop array = SharedRuntime::allocate_value_types_impl(current, callee, allocate_receiver, false, CHECK); current->set_vm_result_oop(array); JRT_END // We've returned to an interpreted method, the interpreter needs a -// reference to an inline type instance. Allocate it and initialize it +// reference to a value type instance. Allocate it and initialize it // from field's values in registers. -JRT_BLOCK_ENTRY(void, SharedRuntime::store_inline_type_fields_to_buf(JavaThread* current, intptr_t res)) +JRT_BLOCK_ENTRY(void, SharedRuntime::store_value_type_fields_to_buf(JavaThread* current, intptr_t res)) { if (!is_set_nth_bit(res, 0)) { - // We're not returning with inline type fields in registers (the - // calling convention didn't allow it for this inline klass) + // We're not returning with value type fields in registers (the + // calling convention didn't allow it for this value klass) assert(!Metaspace::contains((void*)res), "should be oop or pointer in buffer area"); current->set_vm_result_oop((oopDesc*)res); current->set_vm_result_metadata(nullptr); @@ -4169,7 +4168,7 @@ JRT_BLOCK_ENTRY(void, SharedRuntime::store_inline_type_fields_to_buf(JavaThread* } clear_nth_bit(res, 0); - InlineKlass* vk = (InlineKlass*)res; + ValueKlass* vk = (ValueKlass*)res; assert(Metaspace::contains((void*)res), "should be klass"); if (!vk->contains_oops()) { @@ -4194,7 +4193,7 @@ JRT_BLOCK_ENTRY(void, SharedRuntime::store_inline_type_fields_to_buf(JavaThread* frame stubFrame = current->last_frame(); stubFrame.sender(®_map); - assert(vk == InlineKlass::returned_inline_klass(reg_map), "broken calling convention"); + assert(vk == ValueKlass::returned_value_klass(reg_map), "broken calling convention"); // Allocate handles for every oop field so they are safe in case of // a safepoint when allocating diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index c0139870df90..b9430f9076e6 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -302,9 +302,9 @@ class SharedRuntime: AllStatic { } // Value types - static address store_inline_type_fields_to_buf_entry() { - assert(_store_inline_type_fields_to_buf_blob != nullptr, ""); - return _store_inline_type_fields_to_buf_blob->entry_point(); + static address store_value_type_fields_to_buf_entry() { + assert(_store_value_type_fields_to_buf_blob != nullptr, ""); + return _store_value_type_fields_to_buf_blob->entry_point(); } #if INCLUDE_JFR @@ -573,8 +573,8 @@ class SharedRuntime: AllStatic { static address resolve_virtual_call_C (JavaThread* current); static address resolve_opt_virtual_call_C(JavaThread* current); - static void load_inline_type_fields_in_regs(JavaThread* current, oopDesc* res); - static void store_inline_type_fields_to_buf(JavaThread* current, intptr_t res); + static void load_value_type_fields_in_regs(JavaThread* current, oopDesc* res); + static void store_value_type_fields_to_buf(JavaThread* current, intptr_t res); // arraycopy, the non-leaf version. (See StubRoutines for all the leaf calls.) static void slow_arraycopy_C(oopDesc* src, jint src_pos, @@ -586,12 +586,12 @@ class SharedRuntime: AllStatic { static address handle_wrong_method(JavaThread* current); static address handle_wrong_method_abstract(JavaThread* current); static address handle_wrong_method_ic_miss(JavaThread* current); - static void allocate_inline_types(JavaThread* current, Method* callee, bool allocate_receiver); - static oop allocate_inline_types_impl(JavaThread* current, methodHandle callee, bool allocate_receiver, bool from_c1, TRAPS); + static void allocate_value_types(JavaThread* current, Method* callee, bool allocate_receiver); + static oop allocate_value_types_impl(JavaThread* current, methodHandle callee, bool allocate_receiver, bool from_c1, TRAPS); static address handle_unsafe_access(JavaThread* thread, address next_pc); - static BufferedInlineTypeBlob* generate_buffered_inline_type_adapter(const InlineKlass* vk); + static BufferedValueTypeBlob* generate_buffered_value_type_adapter(const ValueKlass* vk); #ifndef PRODUCT // Collect and print inline cache miss statistics @@ -744,7 +744,7 @@ class AdapterHandlerEntry : public MetaspaceObj { static const char *_entry_names[]; - // Support for scalarized inline type calling convention + // Support for scalarized value type calling convention GrowableArray* _sig_cc; GrowableArray* _sig_cc_ro; @@ -812,19 +812,19 @@ class AdapterHandlerEntry : public MetaspaceObj { #endif // ZERO } - address get_c2i_inline_entry() const { + address get_c2i_value_entry() const { #ifndef ZERO assert(_adapter_blob != nullptr, "must be"); - return _adapter_blob->c2i_inline_entry(); + return _adapter_blob->c2i_value_entry(); #else return nullptr; #endif // ZERO } - address get_c2i_inline_ro_entry() const { + address get_c2i_value_ro_entry() const { #ifndef ZERO assert(_adapter_blob != nullptr, "must be"); - return _adapter_blob->c2i_inline_ro_entry(); + return _adapter_blob->c2i_value_ro_entry(); #else return nullptr; #endif // ZERO @@ -839,10 +839,10 @@ class AdapterHandlerEntry : public MetaspaceObj { #endif // ZERO } - address get_c2i_unverified_inline_entry() const { + address get_c2i_unverified_value_entry() const { #ifndef ZERO assert(_adapter_blob != nullptr, "must be"); - return _adapter_blob->c2i_unverified_inline_entry(); + return _adapter_blob->c2i_unverified_value_entry(); #else return nullptr; #endif // ZERO @@ -860,7 +860,7 @@ class AdapterHandlerEntry : public MetaspaceObj { AdapterBlob* adapter_blob() const { return _adapter_blob; } bool is_linked() const { return _linked; } - // Support for scalarized inline type calling convention + // Support for scalarized value type calling convention void set_sig_cc(GrowableArray* sig) { assert(_sig_cc == nullptr, "Already initialized"); _sig_cc = sig; @@ -955,14 +955,14 @@ class AdapterHandlerLibrary: public AllStatic { // Utility class for computing the calling convention of the 3 types // of compiled method entries: -// Method::_from_compiled_entry - sig_cc -// Method::_from_compiled_inline_ro_entry - sig_cc_ro -// Method::_from_compiled_inline_entry - sig +// Method::_from_compiled_entry - sig_cc +// Method::_from_compiled_value_ro_entry - sig_cc_ro +// Method::_from_compiled_value_entry - sig class CompiledEntrySignature : public StackObj { private: Method* _method; - int _num_inline_args; - bool _has_inline_recv; + int _num_value_args; + bool _has_value_recv; GrowableArray* _sig; GrowableArray* _sig_cc; GrowableArray* _sig_cc_ro; @@ -983,13 +983,13 @@ class CompiledEntrySignature : public StackObj { public: Method* method() const { return _method; } - // Used by Method::_from_compiled_inline_entry + // Used by Method::_from_compiled_value_entry GrowableArray* sig() const { return _sig; } // Used by Method::_from_compiled_entry GrowableArray* sig_cc() const { return _sig_cc; } - // Used by Method::_from_compiled_inline_ro_entry + // Used by Method::_from_compiled_value_ro_entry GrowableArray* sig_cc_ro() const { return _sig_cc_ro; } VMRegPair* regs() const { return _regs; } @@ -1000,12 +1000,12 @@ class CompiledEntrySignature : public StackObj { int args_on_stack_cc() const { return _args_on_stack_cc; } int args_on_stack_cc_ro() const { return _args_on_stack_cc_ro; } - int num_inline_args() const { return _num_inline_args; } - bool has_inline_recv() const { return _has_inline_recv; } + int num_value_args() const { return _num_value_args; } + bool has_value_recv() const { return _has_value_recv; } bool has_scalarized_args() const { return _sig != _sig_cc; } bool needs_stack_repair() const { return _needs_stack_repair; } - CodeOffsets::Entries c1_inline_ro_entry_type() const; + CodeOffsets::Entries c1_value_ro_entry_type() const; CompiledEntrySignature(Method* method = nullptr); void compute_calling_conventions(bool link_time = true); diff --git a/src/hotspot/share/runtime/signature.cpp b/src/hotspot/share/runtime/signature.cpp index bdf6b678cdd1..3c1a1e44d162 100644 --- a/src/hotspot/share/runtime/signature.cpp +++ b/src/hotspot/share/runtime/signature.cpp @@ -29,12 +29,12 @@ #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" -#include "oops/inlineKlass.inline.hpp" #include "oops/instanceKlass.hpp" #include "oops/klass.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "oops/typeArrayKlass.hpp" +#include "oops/valueKlass.inline.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" @@ -501,16 +501,16 @@ Symbol* SignatureStream::find_symbol() { return name; } -InlineKlass* SignatureStream::as_inline_klass(InstanceKlass* holder) { - assert(InlineTypePassFieldsAsArgs || InlineTypeReturnedAsFields, "Not needed"); +ValueKlass* SignatureStream::as_value_klass(InstanceKlass* holder) { + assert(ValueTypePassFieldsAsArgs || ValueTypeReturnedAsFields, "Not needed"); ThreadInVMfromUnknown tiv; JavaThread* THREAD = JavaThread::current(); HandleMark hm(THREAD); Handle class_loader(THREAD, holder->class_loader()); Klass* k = as_klass(class_loader, SignatureStream::CachedOrNull, THREAD); assert(!HAS_PENDING_EXCEPTION, "Should never throw"); - if (k != nullptr && k->is_inline_klass()) { - return InlineKlass::cast(k); + if (k != nullptr && k->is_value_klass()) { + return ValueKlass::cast(k); } else { return nullptr; } @@ -691,7 +691,7 @@ void SigEntry::add_null_marker(GrowableArray* sig, Symbol* name, int o sig->append(SigEntry(T_BOOLEAN, offset, name, true, false)); } -// Returns true if the argument at index 'i' is not an inline type delimiter +// Returns true if the argument at index 'i' is not a value type delimiter bool SigEntry::skip_value_delimiters(const GrowableArray* sig, int i) { return (sig->at(i)._bt != T_METADATA && (sig->at(i)._bt != T_VOID || sig->at(i-1)._bt == T_LONG || sig->at(i-1)._bt == T_DOUBLE)); diff --git a/src/hotspot/share/runtime/signature.hpp b/src/hotspot/share/runtime/signature.hpp index c082d00ca35d..f5a0ae58c9de 100644 --- a/src/hotspot/share/runtime/signature.hpp +++ b/src/hotspot/share/runtime/signature.hpp @@ -426,7 +426,7 @@ class NativeSignatureIterator: public SignatureIterator { bool is_static() const { return method()->is_static(); } virtual void pass_int() = 0; virtual void pass_long() = 0; - virtual void pass_object() = 0; // objects, arrays, inlines + virtual void pass_object() = 0; // objects, arrays, values virtual void pass_float() = 0; virtual void pass_byte() { pass_int(); }; virtual void pass_short() { pass_int(); }; @@ -567,7 +567,7 @@ class SignatureStream : public StackObj { // free-standing lookups (bring your own CL/PD pair) enum FailureMode { ReturnNull, NCDFError, CachedOrNull }; Klass* as_klass(Handle class_loader, FailureMode failure_mode, TRAPS); - InlineKlass* as_inline_klass(InstanceKlass* holder); + ValueKlass* as_value_klass(InstanceKlass* holder); oop as_java_mirror(Handle class_loader, FailureMode failure_mode, TRAPS); }; @@ -576,8 +576,8 @@ class SigEntryFilter; typedef GrowableArrayFilterIterator ExtendedSignature; // Used for adapter generation. One SigEntry is used per element of -// the signature of the method. Inline type arguments are treated -// specially. See comment for InlineKlass::collect_fields(). +// the signature of the method. Value type arguments are treated +// specially. See comment for ValueKlass::collect_fields(). class SigEntry { public: BasicType _bt; // Basic type of the argument diff --git a/src/hotspot/share/runtime/signature_cc.hpp b/src/hotspot/share/runtime/signature_cc.hpp index 5e511dff30dc..cbf0f233ee8d 100644 --- a/src/hotspot/share/runtime/signature_cc.hpp +++ b/src/hotspot/share/runtime/signature_cc.hpp @@ -28,7 +28,7 @@ #include "runtime/signature.hpp" // Stream that iterates over a scalarized signature -class ScalarizedInlineArgsStream : public StackObj { +class ScalarizedValueArgsStream : public StackObj { const GrowableArray* _sig; int _sig_idx; const VMRegPair* _regs; @@ -39,7 +39,7 @@ class ScalarizedInlineArgsStream : public StackObj { DEBUG_ONLY(bool _finished); public: - ScalarizedInlineArgsStream(const GrowableArray* sig, int sig_idx, VMRegPair* regs, int regs_count, int regs_idx, bool reverse = false) + ScalarizedValueArgsStream(const GrowableArray* sig, int sig_idx, VMRegPair* regs, int regs_count, int regs_idx, bool reverse = false) : _sig(sig), _sig_idx(sig_idx), _regs(regs), _regs_count(regs_count), _regs_idx(regs_idx), _step(reverse ? -1 : 1) { reset(sig_idx, regs_idx); } @@ -75,7 +75,7 @@ class ScalarizedInlineArgsStream : public StackObj { void reset(int sig_idx, int regs_idx) { _sig_idx = sig_idx; _regs_idx = regs_idx; - assert(_sig->at(_sig_idx)._bt == ((_step > 0) ? T_METADATA : T_VOID), "should be at inline type delimiter"); + assert(_sig->at(_sig_idx)._bt == ((_step > 0) ? T_METADATA : T_VOID), "should be at value type delimiter"); _depth = 1; DEBUG_ONLY(_finished = false); } diff --git a/src/hotspot/share/runtime/stackValue.cpp b/src/hotspot/share/runtime/stackValue.cpp index fb91eb7e4c83..012fd1b7d8ff 100644 --- a/src/hotspot/share/runtime/stackValue.cpp +++ b/src/hotspot/share/runtime/stackValue.cpp @@ -247,7 +247,7 @@ StackValue* StackValue::create_stack_value(const frame* fr, const RegisterMapT* if (ov->has_properties()) { Klass* k = java_lang_Class::as_Klass(ov->klass()->as_ConstantOopReadValue()->value()()); if (!k->is_array_klass()) { - // Don't treat inline type as scalar replaced if it is null + // Don't treat value type as scalar replaced if it is null jint null_marker = StackValue::create_stack_value(fr, reg_map, ov->properties())->get_jint(); scalar_replaced &= (null_marker != 0); } diff --git a/src/hotspot/share/runtime/stubDeclarations.hpp b/src/hotspot/share/runtime/stubDeclarations.hpp index c70adf819cac..cc7f81309826 100644 --- a/src/hotspot/share/runtime/stubDeclarations.hpp +++ b/src/hotspot/share/runtime/stubDeclarations.hpp @@ -108,7 +108,7 @@ do_blob(throw_StackOverflowError, RuntimeStub) \ do_blob(throw_delayed_StackOverflowError, RuntimeStub) \ /* value types stub */ \ - do_blob(store_inline_type_fields_to_buf, RuntimeStub) \ + do_blob(store_value_type_fields_to_buf, RuntimeStub) \ /* other stubs */ \ SHARED_JFR_STUBS_DO(do_blob) \ @@ -142,8 +142,8 @@ do_blob(load_flat_array) \ do_blob(store_flat_array) \ do_blob(substitutability_check) \ - do_blob(buffer_inline_args) \ - do_blob(buffer_inline_args_no_receiver) \ + do_blob(buffer_value_args) \ + do_blob(buffer_value_args_no_receiver) \ do_blob(handle_exception_nofpu) /* optimized version that does not preserve fpu registers */ \ do_blob(handle_exception) \ do_blob(handle_exception_from_callee) \ @@ -239,8 +239,8 @@ do_stub(rethrow, 2, true, true) \ do_stub(slow_arraycopy, 0, false, false) \ do_stub(register_finalizer, 0, false, false) \ - do_stub(load_unknown_inline, 0, true, false) \ - do_stub(store_unknown_inline, 0, true, false) \ + do_stub(load_unknown_value, 0, true, false) \ + do_stub(store_unknown_value, 0, true, false) \ do_stub(vthread_end_first_transition, 0, false, false) \ do_stub(vthread_start_final_transition, 0, false, false) \ do_stub(vthread_start_transition, 0, false, false) \ diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index da60b586b8df..f1ffe48be88e 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -316,9 +316,9 @@ static uintx _no_progress_cnt = 0; static bool _no_progress_skip_increment = false; // These checks are required for wait, notify and exit to avoid inflating the monitor to -// find out this inline type object cannot be locked. +// find out this value type object cannot be locked. #define CHECK_THROW_NOSYNC_IMSE(obj) \ - if ((obj)->mark().is_inline_type()) { \ + if ((obj)->mark().is_value_type()) { \ /* * A value object can never be synchronized upon. The error message we use * here is (accurate and) consistent with the one we use for identity objects @@ -328,7 +328,7 @@ static bool _no_progress_skip_increment = false; } #define CHECK_THROW_NOSYNC_IMSE_0(obj) \ - if ((obj)->mark().is_inline_type()) { \ + if ((obj)->mark().is_value_type()) { \ /* * A value object can never be synchronized upon. The error message we use * here is (accurate and) consistent with the one we use for identity objects @@ -363,7 +363,7 @@ bool ObjectSynchronizer::quick_notify(oopDesc* obj, JavaThread* current, bool al assert(current->thread_state() == _thread_in_Java, "invariant"); NoSafepointVerifier nsv; if (obj == nullptr) return false; // slow-path for invalid obj - assert(!obj->klass()->is_inline_klass(), "monitor op on inline type"); + assert(!obj->klass()->is_value_klass(), "monitor op on value type"); const markWord mark = obj->mark(); if (mark.is_fast_locked() && current->lock_stack().contains(cast_to_oop(obj))) { @@ -460,7 +460,7 @@ void ObjectSynchronizer::jni_enter(Handle obj, JavaThread* current) { handle_sync_on_value_based_class(obj, current); } - if (obj->klass()->is_inline_klass()) { + if (obj->klass()->is_value_klass()) { ResourceMark rm(THREAD); stringStream ss; ss.print("Cannot synchronize on an instance of value class %s", @@ -677,7 +677,7 @@ intptr_t ObjectSynchronizer::get_next_hash(Thread* current, oop obj) { bool ObjectSynchronizer::current_thread_holds_lock(JavaThread* current, Handle h_obj) { - if (h_obj->mark().is_inline_type()) { + if (h_obj->mark().is_value_type()) { return false; } assert(current == JavaThread::current(), "Can only be called on current thread"); @@ -1336,19 +1336,20 @@ void ObjectSynchronizer::chk_in_use_entry(ObjectMonitor* n, outputStream* out, return; } - - if (n->metadata() == 0) { - out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use monitor must " - "have non-null _metadata (header/hash) field.", p2i(n)); - *error_cnt_p = *error_cnt_p + 1; - } - const oop obj = n->object_peek(); if (obj == nullptr) { return; } const markWord mark = obj->mark(); + if (!mark.has_hash()) { + out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use monitor's " + "object must have a non-zero hash code: obj=" + INTPTR_FORMAT ", mark=" INTPTR_FORMAT, + p2i(n), p2i(obj), mark.value()); + *error_cnt_p = *error_cnt_p + 1; + } + ObjectMonitor* const obj_mon = read_monitor(obj); if (n != obj_mon) { out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use monitor's " @@ -1359,17 +1360,17 @@ void ObjectSynchronizer::chk_in_use_entry(ObjectMonitor* n, outputStream* out, } } -// Log details about ObjectMonitors on the in_use_list. The 'BHL' +// Log details about ObjectMonitors on the in_use_list. The 'BL' // flags indicate why the entry is in-use, 'object' and 'object type' // indicate the associated object and its type. void ObjectSynchronizer::log_in_use_monitor_details(outputStream* out, bool log_all) { if (_in_use_list.count() > 0) { stringStream ss; out->print_cr("In-use monitor info%s:", log_all ? "" : " (eliding idle monitors)"); - out->print_cr("(B -> is_busy, H -> has hash code, L -> lock status)"); + out->print_cr("(B -> is_busy, L -> lock status)"); out->print_cr("%18s %s %18s %18s", - "monitor", "BHL", "object", "object type"); - out->print_cr("================== === ================== =================="); + "monitor", "BL", "object", "object type"); + out->print_cr("================== == ================== =================="); auto is_interesting = [&](ObjectMonitor* monitor) { return log_all || monitor->has_owner() || monitor->is_busy(); @@ -1378,10 +1379,9 @@ void ObjectSynchronizer::log_in_use_monitor_details(outputStream* out, bool log_ monitors_iterate([&](ObjectMonitor* monitor) { if (is_interesting(monitor)) { const oop obj = monitor->object_peek(); - const intptr_t hash = monitor->hash(); ResourceMark rm; - out->print(INTPTR_FORMAT " %d%d%d " INTPTR_FORMAT " %s", p2i(monitor), - monitor->is_busy(), hash != 0, monitor->has_owner(), + out->print(INTPTR_FORMAT " %d%d " INTPTR_FORMAT " %s", p2i(monitor), + monitor->is_busy(), monitor->has_owner(), p2i(obj), obj == nullptr ? "" : obj->klass()->external_name()); if (monitor->is_busy()) { out->print(" (%s)", monitor->is_busy_to_string(&ss)); @@ -1459,14 +1459,10 @@ ObjectMonitor* ObjectSynchronizer::get_or_insert_monitor(oop object, JavaThread* return monitor; } -// Add the hashcode to the monitor to match the object and put it in the hashtable. +// Add the monitor to the ObjectMonitorTable. ObjectMonitor* ObjectSynchronizer::add_monitor(ObjectMonitor* monitor, oop obj) { assert(obj == monitor->object(), "must be"); - intptr_t hash = obj->mark().hash(); - assert(hash != 0, "must be set when claiming the object monitor"); - monitor->set_hash(hash); - return ObjectMonitorTable::monitor_put_get(monitor, obj); } diff --git a/src/hotspot/share/runtime/vframeArray.cpp b/src/hotspot/share/runtime/vframeArray.cpp index 66af4db24aab..dcf421f171a1 100644 --- a/src/hotspot/share/runtime/vframeArray.cpp +++ b/src/hotspot/share/runtime/vframeArray.cpp @@ -34,6 +34,7 @@ #include "oops/oop.inline.hpp" #include "prims/jvmtiThreadState.hpp" #include "prims/methodHandles.hpp" +#include "runtime/basicLock.inline.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/monitorChunk.hpp" @@ -94,13 +95,7 @@ void vframeArrayElement::fill_in(compiledVFrame* vf, bool realloc_failures) { } else { assert(monitor->owner() != nullptr, "monitor owner must not be null"); dest->set_obj(monitor->owner()); - assert(ObjectSynchronizer::current_thread_holds_lock(current_thread, Handle(current_thread, dest->obj())), - "should be held, before move_to"); - - monitor->lock()->move_to(monitor->owner(), dest->lock()); - - assert(ObjectSynchronizer::current_thread_holds_lock(current_thread, Handle(current_thread, dest->obj())), - "should be held, after move_to"); + dest->lock()->set_object_monitor_cache(monitor->lock()->object_monitor_cache()); } } } @@ -390,11 +385,7 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, top = iframe()->previous_monitor_in_interpreter_frame(top); BasicObjectLock* src = _monitors->at(index); top->set_obj(src->obj()); - assert(src->obj() != nullptr || ObjectSynchronizer::current_thread_holds_lock(thread, Handle(thread, src->obj())), - "should be held, before move_to"); - src->lock()->move_to(src->obj(), top->lock()); - assert(src->obj() != nullptr || ObjectSynchronizer::current_thread_holds_lock(thread, Handle(thread, src->obj())), - "should be held, after move_to"); + top->lock()->set_object_monitor_cache(src->lock()->object_monitor_cache()); } iframe()->interpreter_frame_set_bcp(bcp); if (ProfileInterpreter) { diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 789699368823..00974a1a1940 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -61,7 +61,6 @@ #include "oops/cpCache.hpp" #include "oops/fieldInfo.hpp" #include "oops/flatArrayKlass.hpp" -#include "oops/inlineKlass.hpp" #include "oops/instanceKlass.hpp" #include "oops/instanceOop.hpp" #include "oops/klass.hpp" @@ -80,6 +79,7 @@ #include "oops/symbol.hpp" #include "oops/typeArrayKlass.hpp" #include "oops/typeArrayOop.hpp" +#include "oops/valueKlass.hpp" #include "prims/jvmtiAgentThread.hpp" #include "runtime/arguments.hpp" #include "runtime/atomic.hpp" @@ -220,6 +220,7 @@ nonstatic_field(InstanceKlass, _method_ordering, Array*) \ nonstatic_field(InstanceKlass, _default_vtable_indices, Array*) \ nonstatic_field(InstanceKlass, _access_flags, AccessFlags) \ + nonstatic_field(Klass, _kind, const Klass::KlassKind) \ nonstatic_field(Klass, _super_check_offset, juint) \ nonstatic_field(Klass, _secondary_super_cache, Klass*) \ nonstatic_field(Klass, _secondary_supers, Array*) \ @@ -661,7 +662,6 @@ /* Monitors */ \ /************/ \ \ - volatile_nonstatic_field(ObjectMonitor, _metadata, uintptr_t) \ unchecked_nonstatic_field(ObjectMonitor, _object, sizeof(void *)) /* NOTE: no type */ \ volatile_nonstatic_field(ObjectMonitor, _owner, int64_t) \ volatile_nonstatic_field(ObjectMonitor, _next_om, ObjectMonitor*) \ @@ -935,7 +935,7 @@ declare_type(FlatArrayKlass, ArrayKlass) \ declare_type(RefArrayKlass, ArrayKlass) \ declare_type(InstanceKlass, Klass) \ - declare_type(InlineKlass, InstanceKlass) \ + declare_type(ValueKlass, InstanceKlass) \ declare_type(InstanceClassLoaderKlass, InstanceKlass) \ declare_type(InstanceMirrorKlass, InstanceKlass) \ declare_type(InstanceRefKlass, InstanceKlass) \ @@ -1190,6 +1190,7 @@ declare_integer_type(AOTCompressedPointers::narrowPtr) \ declare_integer_type(Bytecodes::Code) \ declare_integer_type(InstanceKlass::ClassState) \ + declare_integer_type(Klass::KlassKind) \ declare_integer_type(JavaThreadState) \ declare_integer_type(ThreadState) \ declare_integer_type(Location::Type) \ @@ -1481,6 +1482,22 @@ declare_constant(InstanceKlass::fully_initialized) \ declare_constant(InstanceKlass::initialization_error) \ \ + /************************/ \ + /* Klass KlassKind enum */ \ + /************************/ \ + \ + declare_constant(Klass::KlassKind::InstanceKlassKind) \ + declare_constant(Klass::KlassKind::ValueKlassKind) \ + declare_constant(Klass::KlassKind::InstanceRefKlassKind) \ + declare_constant(Klass::KlassKind::InstanceMirrorKlassKind) \ + declare_constant(Klass::KlassKind::InstanceClassLoaderKlassKind) \ + declare_constant(Klass::KlassKind::InstanceStackChunkKlassKind) \ + declare_constant(Klass::KlassKind::TypeArrayKlassKind) \ + declare_constant(Klass::KlassKind::ObjArrayKlassKind) \ + declare_constant(Klass::KlassKind::RefArrayKlassKind) \ + declare_constant(Klass::KlassKind::FlatArrayKlassKind) \ + declare_constant(Klass::KlassKind::UnknownKlassKind) \ + \ /*********************************/ \ /* Symbol* - symbol max length */ \ /*********************************/ \ @@ -1519,7 +1536,7 @@ declare_constant(FieldInfo::FieldFlags::_ff_generic) \ declare_constant(FieldInfo::FieldFlags::_ff_stable) \ declare_constant(FieldInfo::FieldFlags::_ff_contended) \ - declare_constant(FieldInfo::FieldFlags::_ff_null_free_inline_type) \ + declare_constant(FieldInfo::FieldFlags::_ff_null_free_value_type) \ declare_constant(FieldInfo::FieldFlags::_ff_flat) \ declare_constant(FieldInfo::FieldFlags::_ff_null_marker) \ \ diff --git a/src/hotspot/share/services/attachListener.cpp b/src/hotspot/share/services/attachListener.cpp index 04f1f38d73d1..4edf0a8ec5d8 100644 --- a/src/hotspot/share/services/attachListener.cpp +++ b/src/hotspot/share/services/attachListener.cpp @@ -879,12 +879,15 @@ bool AttachOperation::RequestReader::read_request(AttachOperation* op, ReplyWrit // read size of the data buffer_size = read_uint(); if (buffer_size < 0) { - log_error(attach)("Failed to read request: negative request size (%d)", buffer_size); - return false; + return false; // error already logged } log_debug(attach)("v2 request, data size = %d", buffer_size); - // Sanity check: max request size is 256K. + // Sanity checks: not empty, max request size is 256K. + if (buffer_size < 1) { + log_error(attach)("Failed to read request: empty"); + return false; + } if (buffer_size > 256 * 1024) { log_error(attach)("Failed to read request: too big"); return false; diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index e2364e1f4b00..b9921c1e09ab 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -841,10 +841,10 @@ class DumperClassCacheTableEntry : public CHeapObj { private: char _sigs_start; int _offset; - InlineKlass* _inline_klass; // nullptr for heap object + ValueKlass* _value_klass; // nullptr for heap object LayoutKind _layout_kind; public: - FieldDescriptor(): _sigs_start(0), _offset(0), _inline_klass(nullptr), _layout_kind(LayoutKind::UNKNOWN) {} + FieldDescriptor(): _sigs_start(0), _offset(0), _value_klass(nullptr), _layout_kind(LayoutKind::UNKNOWN) {} template FieldDescriptor(const FieldStreamType& field) @@ -853,19 +853,19 @@ class DumperClassCacheTableEntry : public CHeapObj { if (field.is_flat()) { const fieldDescriptor& fd = field.field_descriptor(); InstanceKlass* holder_klass = fd.field_holder(); - InlineLayoutInfo* layout_info = holder_klass->inline_layout_info_adr(fd.index()); - _inline_klass = layout_info->klass(); + ValueFieldLayoutInfo* layout_info = holder_klass->value_field_layout_info_adr(fd.index()); + _value_klass = layout_info->klass(); _layout_kind = layout_info->kind(); } else { - _inline_klass = nullptr; + _value_klass = nullptr; _layout_kind = LayoutKind::REFERENCE; } } char sig_start() const { return _sigs_start; } int offset() const { return _offset; } - bool is_flat() const { return _inline_klass != nullptr; } - InlineKlass* inline_klass() const { return _inline_klass; } + bool is_flat() const { return _value_klass != nullptr; } + ValueKlass* value_klass() const { return _value_klass; } LayoutKind layout_kind() const { return _layout_kind; } bool is_flat_nullable() const { return LayoutKindHelper::is_nullable_flat(_layout_kind); } }; @@ -972,16 +972,16 @@ class DumperFlatObject: public CHeapObj { const uintptr_t _id; // object id const int _offset; - InlineKlass* const _inline_klass; + ValueKlass* const _value_klass; public: - DumperFlatObject(uintptr_t id, int offset, InlineKlass* inline_klass) - : _next(nullptr), _id(id), _offset(offset), _inline_klass(inline_klass) { + DumperFlatObject(uintptr_t id, int offset, ValueKlass* value_klass) + : _next(nullptr), _id(id), _offset(offset), _value_klass(value_klass) { } uintptr_t object_id() const { return _id; } int offset() const { return _offset; } - InlineKlass* inline_klass() const { return _inline_klass; } + ValueKlass* value_klass() const { return _value_klass; } }; class FlatObjectIdProvider { @@ -1011,9 +1011,9 @@ class DumperFlatObjectList { bool is_empty() const { return _head == nullptr; } - uintptr_t push(int offset, InlineKlass* inline_klass) { + uintptr_t push(int offset, ValueKlass* value_klass) { uintptr_t id = _id_provider->get_id(); - DumperFlatObject* obj = new DumperFlatObject(id, offset, inline_klass); + DumperFlatObject* obj = new DumperFlatObject(id, offset, value_klass); push(obj); return id; } @@ -1274,12 +1274,12 @@ void DumperSupport::dump_instance_fields(AbstractDumpWriter* writer, oop o, int // check for possible nulls if (field.is_flat_nullable()) { address payload = cast_from_oop
(o) + field_offset; - if (field.inline_klass()->is_payload_marked_as_null(payload)) { + if (field.value_klass()->is_payload_marked_as_null(payload)) { writer->write_objectID(nullptr); continue; } } - uintptr_t object_id = flat_fields->push(field_offset, field.inline_klass()); + uintptr_t object_id = flat_fields->push(field_offset, field.value_klass()); writer->write_objectID(object_id); } else { dump_field_value(writer, field.sig_start(), o, field_offset); @@ -1334,8 +1334,8 @@ void DumperSupport::dump_instance(AbstractDumpWriter* writer, uintptr_t id, oop // field values if (offset != 0) { // the object itself if flattened, so all fields are stored without headers - InlineKlass* inline_klass = InlineKlass::cast(ik); - offset -= inline_klass->payload_offset(); + ValueKlass* value_klass = ValueKlass::cast(ik); + offset -= value_klass->payload_offset(); } dump_instance_fields(writer, o, offset, cache_entry, flat_fields); @@ -1481,7 +1481,7 @@ void DumperSupport::dump_object_array(AbstractDumpWriter* writer, objArrayOop ar flatArrayOop farray = flatArrayOop(array); FlatArrayKlass* fak = farray->klass(); - InlineKlass* vk = fak->element_klass(); + ValueKlass* vk = fak->element_klass(); bool need_null_check = LayoutKindHelper::is_nullable_flat(fak->layout_kind()); for (int index = 0; index < length; index++) { @@ -2160,7 +2160,7 @@ void FlatObjectDumper::dump_flat_objects(AbstractDumpWriter* writer, oop holder, // DumperSupport::dump_instance can add entries to flat_objects while (!flat_objects->is_empty()) { DumperFlatObject* obj = flat_objects->pop(); - DumperSupport::dump_instance(writer, obj->object_id(), holder, obj->offset(), obj->inline_klass(), class_cache, flat_objects); + DumperSupport::dump_instance(writer, obj->object_id(), holder, obj->offset(), obj->value_klass(), class_cache, flat_objects); delete obj; } } diff --git a/src/hotspot/share/services/memoryPool.hpp b/src/hotspot/share/services/memoryPool.hpp index f0a4ba216590..8061e99edd6c 100644 --- a/src/hotspot/share/services/memoryPool.hpp +++ b/src/hotspot/share/services/memoryPool.hpp @@ -27,6 +27,7 @@ #include "memory/heap.hpp" #include "oops/oop.hpp" +#include "oops/oopHandle.hpp" #include "services/memoryUsage.hpp" #include "utilities/macros.hpp" diff --git a/src/hotspot/share/utilities/bitMap.cpp b/src/hotspot/share/utilities/bitMap.cpp index b36460847767..7fc280f2de3e 100644 --- a/src/hotspot/share/utilities/bitMap.cpp +++ b/src/hotspot/share/utilities/bitMap.cpp @@ -195,6 +195,13 @@ bm_word_t* CHeapBitMap::reallocate(bm_word_t* map, size_t old_size_in_words, siz return MallocArrayAllocator::reallocate(map, new_size_in_words, _mem_tag); } +void CHeapBitMap::move(CHeapBitMap &other) { + free(map(), size_in_words()); + update(other.map(), other.size()); + other.update(nullptr, 0); +} + + #ifdef ASSERT void BitMap::verify_index(idx_t bit) const { assert(bit < _size, diff --git a/src/hotspot/share/utilities/bitMap.hpp b/src/hotspot/share/utilities/bitMap.hpp index 17bf437ecaea..1aae97abdff3 100644 --- a/src/hotspot/share/utilities/bitMap.hpp +++ b/src/hotspot/share/utilities/bitMap.hpp @@ -654,6 +654,9 @@ class CHeapBitMap : public GrowableBitMap { bm_word_t* allocate(idx_t size_in_words) const; bm_word_t* reallocate(bm_word_t* old_map, size_t old_size_in_words, size_t new_size_in_words) const; void free(bm_word_t* map, idx_t size_in_words) const; + + // Move other's map into this, invalidating other. + void move(CHeapBitMap& other); }; // Convenience class wrapping BitMap which provides multiple bits per slot. diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 6d3421bd2cf8..067d3e5ed1bc 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -1045,8 +1045,6 @@ const jubyte heapPaddingByteVal = 0xBD; // value used to zap const juint badHeapWordVal = 0xBAADBABE; // value used to zap heap after GC const int badCodeHeapNewVal = 0xCC; // value used to zap Code heap at allocation const int badCodeHeapFreeVal = 0xDD; // value used to zap Code heap at deallocation -const intptr_t badDispHeaderDeopt = 0xDE0BD000; // value to fill unused displaced header during deoptimization -const intptr_t badDispHeaderOSR = 0xDEAD05A0; // value to fill unused displaced header during OSR const juint badRegWordVal = 0xDEADDA7A; // value used to zap registers // (These must be implemented as #defines because C++ compilers are diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 6fb2cb96a029..477155e75a7d 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -2100,9 +2100,9 @@ bool VMError::check_timeout() { // exceptions to this (printing a callstack from debug information located on a slow file system, or // printing a memory map of an extremely fragmented process). To give those rare slow steps enough // breathing space while still allowing us to skip any hanging steps, we use a per-step timeout of - // /4, or 5 seconds, whichever is smaller. + // /4, or 15 seconds, whichever is smaller. const jlong step_timeout_nanos = ((jlong)ErrorLogTimeout * SECONDS_TO_NANOS_FACTOR) / 4; - const jlong max_step_timeout_nanos = 5LL * SECONDS_TO_NANOS_FACTOR; + const jlong max_step_timeout_nanos = 15LL * SECONDS_TO_NANOS_FACTOR; const jlong timeout_duration = MIN2(max_step_timeout_nanos, step_timeout_nanos); const jlong end = step_start_time + timeout_duration; if (end <= now && !_step_did_timeout.load_relaxed()) { diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index a4562c1b5a62..59945dbdf8f7 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -2363,6 +2363,17 @@ public boolean bytesCompatible(String string, Charset charset, int srcIndex, int public void finishInit(StackTraceElement[] stackTrace) { StackTraceElement.finishInit(stackTrace); } + + @Override + public long[] getConfinedMemoryPools(Thread thread) { + return thread.confinedMemoryPools(); + } + + @Override + public long[] getOrCreateConfinedMemoryPools(Thread thread, int poolSlots) { + return thread.getOrCreateConfinedMemoryPools(poolSlots); + } + }); } } diff --git a/src/java.base/share/classes/java/lang/Thread.java b/src/java.base/share/classes/java/lang/Thread.java index 4890c1af45ba..089581b2789d 100644 --- a/src/java.base/share/classes/java/lang/Thread.java +++ b/src/java.base/share/classes/java/lang/Thread.java @@ -34,6 +34,7 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.StructureViolationException; import java.util.concurrent.locks.LockSupport; +import jdk.internal.foreign.ConfinedSegmentPool; import jdk.internal.event.ThreadSleepEvent; import jdk.internal.misc.TerminatingThreadLocal; import jdk.internal.misc.Unsafe; @@ -277,7 +278,8 @@ public class Thread implements Runnable { private volatile ClassLoader contextClassLoader; // Additional fields for platform threads. - // All fields, except task and terminatingThreadLocals, are accessed directly by the VM. + // All fields, except task, terminatingThreadLocals, and confinedMemoryPools, + // are accessed directly by the VM. private static class FieldHolder { final ThreadGroup group; final Runnable task; @@ -292,6 +294,12 @@ private static class FieldHolder { // This map is maintained by the ThreadLocal class ThreadLocal.ThreadLocalMap terminatingThreadLocals; + /** + * Lazily initialized cache storage managed by {@link ConfinedSegmentPool}. + * Access is confined to this platform thread, directly or as a carrier. + */ + long[] confinedMemoryPools; + FieldHolder(ThreadGroup group, Runnable task, long stackSize, @@ -368,6 +376,23 @@ static void setScopedValueBindings(Object bindings) { currentThread().scopedValueBindings = bindings; } + long[] confinedMemoryPools() { + return holder.confinedMemoryPools; + } + + void setConfinedMemoryPools(long[] confinedMemoryPools) { + holder.confinedMemoryPools = confinedMemoryPools; + } + + long[] getOrCreateConfinedMemoryPools(int poolSlots) { + long[] confinedMemoryPools = holder.confinedMemoryPools; + if (confinedMemoryPools == null) { + confinedMemoryPools = new long[poolSlots]; + setConfinedMemoryPools(confinedMemoryPools); + } + return confinedMemoryPools; + } + /** * Search the stack for the most recent scoped-value bindings. */ @@ -1571,13 +1596,26 @@ private void exit() { } } - try { - if (terminatingThreadLocals() != null) { + if (terminatingThreadLocals() != null) { + try { TerminatingThreadLocal.threadTerminated(); - } - } finally { - clearReferences(); + } catch (Throwable _) { } + setTerminatingThreadLocals(null); } + + // Must run after terminating-thread-local callbacks, as these callbacks + // may use confined arenas and return pools to this thread's cache. + // ConfinedSegmentPool.threadTerminated must remain leaf cleanup: it + // must not invoke user code or access/register thread-local variables. + long[] confinedMemoryPools = confinedMemoryPools(); + if (confinedMemoryPools != null) { + try { + ConfinedSegmentPool.threadTerminated(confinedMemoryPools); + } catch (Throwable _) { } + setConfinedMemoryPools(null); + } + + clearReferences(); } /** diff --git a/src/java.base/share/classes/java/lang/foreign/Linker.java b/src/java.base/share/classes/java/lang/foreign/Linker.java index 61f85cf463ae..5c3821a14ded 100644 --- a/src/java.base/share/classes/java/lang/foreign/Linker.java +++ b/src/java.base/share/classes/java/lang/foreign/Linker.java @@ -632,11 +632,8 @@ MethodHandle downcallHandle(MemorySegment address, *
  • The invocation occurs in a thread {@code T} such that * {@code A.isAccessibleBy(T) == true}. * Otherwise, the invocation throws {@link WrongThreadException}; and
  • - *
  • {@code A} is kept alive during the invocation. For instance, - * if {@code A} has been obtained using a {@linkplain Arena#ofShared() shared arena}, - * any attempt to {@linkplain Arena#close() close} the arena while the - * downcall method handle is still executing will result in an - * {@link IllegalStateException}.
  • + *
  • {@code A} is {@linkplain MemorySegment##keep-alive kept alive} + * during the invocation. * *

    * Moreover, if the provided function descriptor's return layout is an 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 70b15bb0cd7f..7be0fd4cf978 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, 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 @@ -506,6 +506,17 @@ * be used with caution: assigning a segment incorrect spatial and/or temporal bounds * could result in a VM crash when attempting to access the memory segment. * + *

    Keep-alive operations

    + * + * Some operations on memory segments keep the memory segment {@linkplain Scope#isAlive() alive}. + * For instance, if the segment has been obtained using a {@linkplain Arena#ofShared() shared arena}, + * any attempt to {@linkplain Arena#close() close} the arena while such an operation is still + * executing will result in an {@link IllegalStateException}. + *

    + * Examples of keep-alive operations are: passing a memory segment to a + * {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handle}, + * or calling one of the methods {@link #load()}, {@link #unload()}, {@link #force()}, or {@link #isLoaded()}. + * * @implSpec * Implementations of this interface are immutable, thread-safe and * value-based. @@ -732,8 +743,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { MemorySegment asSlice(long offset); /** - * Returns a new memory segment that has the same address and scope as this segment, - * but with the provided size. + * {@return a new memory segment that has the same address and scope as this segment, + * but with the provided size} *

    * If this segment is {@linkplain MemorySegment#isReadOnly() read-only}, * the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}. @@ -742,8 +753,6 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * Hence, no memory will be allocated or freed by this method. * * @param newSize the size of the returned segment - * @return a new memory segment that has the same address and scope as - * this segment, but the new provided size * @throws IllegalArgumentException if {@code newSize < 0} * @throws UnsupportedOperationException if this segment is not a * {@linkplain #isNative() native} segment @@ -755,11 +764,13 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { MemorySegment reinterpret(long newSize); /** - * Returns a new memory segment with the same address and size as this segment, but - * with the provided arena's scope. As such, the returned segment cannot be accessed - * after the provided arena has been closed. Moreover, the returned segment can be - * accessed compatibly with the confinement restrictions associated with the provided - * arena: that is, if the provided arena is a {@linkplain Arena#ofConfined() confined arena}, + * {@return a new memory segment with the same address and size as this segment, but + * with the provided arena's scope} + *

    + * As such, the returned segment cannot be accessed after the provided arena has been + * closed. Moreover, the returned segment can be accessed compatibly with + * the confinement restrictions associated with the provided arena: that is, if + * the provided arena is a {@linkplain Arena#ofConfined() confined arena}, * the returned segment can only be accessed by the arena's owner thread, regardless * of the confinement restrictions associated with this segment. In other words, this * method returns a segment that can be used as any other segment allocated using the @@ -799,7 +810,6 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * @param arena the arena to be associated with the returned segment * @param cleanup the cleanup action that should be executed when the provided arena * is closed (can be {@code null}) - * @return a new memory segment with unbounded size * @throws IllegalStateException if {@code arena.scope().isAlive() == false} * @throws UnsupportedOperationException if this segment is not a * {@linkplain #isNative() native} segment @@ -811,11 +821,13 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { MemorySegment reinterpret(Arena arena, Consumer cleanup); /** - * Returns a new segment with the same address as this segment, but with the provided - * size and the provided arena's scope. As such, the returned segment cannot be - * accessed after the provided arena has been closed. Moreover, if the returned - * segment can be accessed compatibly with the confinement restrictions associated - * with the provided arena: that is, if the provided arena is a {@linkplain Arena#ofConfined() confined arena}, + * {@return a new segment with the same address as this segment, but with the provided + * size and the provided arena's scope} + *

    + * As such, the returned segment cannot be accessed after the provided arena has been + * closed. Moreover, if the returned segment can be accessed compatibly with + * the confinement restrictions associated with the provided arena: that is, if + * the provided arena is a {@linkplain Arena#ofConfined() confined arena}, * the returned segment can only be accessed by the arena's owner thread, regardless * of the confinement restrictions associated with this segment. In other words, this * method returns a segment that can be used as any other segment allocated using the @@ -856,8 +868,6 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * @param arena the arena to be associated with the returned segment * @param cleanup the cleanup action that should be executed when the provided arena * is closed (can be {@code null}). - * @return a new segment that has the same address as this segment, but with the new - * size and its scope set to that of the provided arena. * @throws UnsupportedOperationException if this segment is not a * {@linkplain #isNative() native} segment * @throws IllegalArgumentException if {@code newSize < 0} @@ -1008,17 +1018,20 @@ MemorySegment reinterpret(long newSize, /** * Determines whether all the contents of this mapped segment are resident in physical * memory. - * - *

    A return value of {@code true} implies that it is highly likely + *

    + * A return value of {@code true} implies that it is highly likely * that all the data in this segment is resident in physical memory and * may therefore be accessed without incurring any virtual-memory page * faults or I/O operations. A return value of {@code false} does not * necessarily imply that this segment's contents are not resident in physical * memory. - * - *

    The returned value is a hint, rather than a guarantee, because the + *

    + * The returned value is a hint, rather than a guarantee, because the * underlying operating system may have paged out some of this segment's data - * by the time that an invocation of this method returns.

    + * by the time that an invocation of this method returns. + *

    + * This memory segment is {@linkplain ##keep-alive kept alive} + * during the invocation of this method. * * @return {@code true} if it is likely that the contents of this segment * are resident in physical memory @@ -1038,7 +1051,10 @@ MemorySegment reinterpret(long newSize, * This method makes a best effort to ensure that, when it returns, * the contents of this segment are resident in physical memory. Invoking this * method may cause some number of page faults and I/O operations to - * occur.

    + * occur. + *

    + * This memory segment is {@linkplain ##keep-alive kept alive} + * during the invocation of this method. * * @throws IllegalStateException if the {@linkplain #scope() scope} associated with * this segment is not {@linkplain Scope#isAlive() alive} @@ -1055,7 +1071,10 @@ MemorySegment reinterpret(long newSize, * This method makes a best effort to ensure that the contents of this segment * are no longer resident in physical memory. Accessing this segment's contents * after invoking this method may cause some number of page faults and I/O operations - * to occur (as this segment's contents might need to be paged back in).

    + * to occur (as this segment's contents might need to be paged back in). + *

    + * This memory segment is {@linkplain ##keep-alive kept alive} + * during the invocation of this method. * * @throws IllegalStateException if the {@linkplain #scope() scope} associated with * this segment is not {@linkplain Scope#isAlive() alive} @@ -1083,6 +1102,9 @@ MemorySegment reinterpret(long newSize, * method may have no effect. In particular, the method has no effect for segments * mapped in read-only or private mapping modes. This method may or may not have an * effect for implementation-specific mapping modes. + *

    + * This memory segment is {@linkplain ##keep-alive kept alive} + * during the invocation of this method. * * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not * {@linkplain Scope#isAlive() alive} @@ -1389,9 +1411,9 @@ MemorySegment reinterpret(long newSize, * null-terminated byte sequence using the provided charset. *

    * This method always replaces malformed-input and unmappable-character - * sequences with this charset's default replacement string. The {@link - * java.nio.charset.CharsetDecoder} class should be used when more control - * over the decoding process is required. + * sequences with this charset's default replacement byte array. The {@link + * java.nio.charset.CharsetEncoder} class should be used when more control + * over the encoding process is required. *

    * If the given string contains any {@code '\0'} characters, they will be * copied as well. This means that, depending on the method used to read @@ -2647,9 +2669,9 @@ static void copy(Object srcArray, int srcIndex, * to the destination segment. *

    * This method always replaces malformed-input and unmappable-character - * sequences with this charset's default replacement string. The {@link - * java.nio.charset.CharsetDecoder} class should be used when more control - * over the decoding process is required. + * sequences with this charset's default replacement byte array. The {@link + * java.nio.charset.CharsetEncoder} class should be used when more control + * over the encoding process is required. *

    * If the given string contains any {@code '\0'} characters, they will be * copied as well. This means that, depending on the method used to read @@ -2659,7 +2681,7 @@ static void copy(Object srcArray, int srcIndex, * * @param src the Java string to be written into the destination segment * @param dstEncoding the charset used to {@linkplain Charset#newEncoder() encode} - * the string bytes. + * the string bytes * @param srcIndex the starting character index of the source string * @param dst the destination segment * @param dstOffset the starting offset, in bytes, of the destination segment @@ -2672,9 +2694,9 @@ static void copy(Object srcArray, int srcIndex, * are {@code < 0} * @throws IndexOutOfBoundsException if {@code srcIndex > src.length() - numChars} * @throws IllegalArgumentException if {@code dst} is {@linkplain #isReadOnly() read-only} - * @throws IndexOutOfBoundsException if {@code dstOffset > dstSegment.byteSize() - B} where {@code B} is the size, - * in bytes, of the substring of {@code src} encoded using the given charset - * @return the number of copied bytes. + * @throws IndexOutOfBoundsException if {@code dstOffset > dst.byteSize() - B} where {@code B} is the size, + * in bytes, of {@code src.substring(srcIndex, srcIndex + numChars)} encoded using the given charset + * @return the number of copied bytes * @since 27 */ @ForceInline diff --git a/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java b/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java index 03d92ec24ef7..db776741973a 100644 --- a/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java +++ b/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java @@ -91,7 +91,7 @@ public interface SegmentAllocator { *} * * @param str the Java string to be converted into a C string - * @return a new native segment containing the converted C string + * @return a new segment containing the converted C string */ @ForceInline default MemorySegment allocateFrom(String str) { @@ -117,7 +117,7 @@ default MemorySegment allocateFrom(String str) { * @param str the Java string to be converted into a C string * @param charset the charset used to {@linkplain Charset#newEncoder() encode} the * string bytes - * @return a new native segment containing the converted C string + * @return a new segment containing the converted C string * @throws IllegalArgumentException if {@code charset} is not a * {@linkplain StandardCharsets standard charset} * @implSpec The default implementation for this method copies the contents of the @@ -174,15 +174,14 @@ default MemorySegment allocateFrom(String str, Charset charset) { * string bytes * @param srcIndex the starting index of the source string * @param numChars the number of characters to be copied - * @return a new native segment containing the encoded string + * @return a new segment containing the encoded string * @throws IndexOutOfBoundsException if either {@code srcIndex} or {@code numChars} are {@code < 0} * @throws IndexOutOfBoundsException if {@code srcIndex > str.length() - numChars} * * @implSpec The default implementation for this method copies the contents of the * provided Java string into a new memory segment obtained by calling * {@code this.allocate(B)}, where {@code B} is the size, in bytes, of - * the string encoded using the provided charset - * (e.g. {@code str.getBytes(charset).length}); + * {@code str.substring(srcIndex, srcIndex + numChars)} encoded using the provided charset. * @since 27 */ @ForceInline diff --git a/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java b/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java index f5d1b7740613..f4d826e8806d 100644 --- a/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, 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 @@ -113,6 +113,9 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo * if, after any required inference, multiplying the element counts does not * yield the same element count as the flattened projection of this * sequence layout + * @throws UnsupportedOperationException if the element count of a flattened + * representation of this sequence layout cannot + * be represented as a {@code long} */ SequenceLayout reshape(long... elementCounts); @@ -143,6 +146,9 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo * @return a sequence layout with the same size as this layout * (but, possibly, with different element count), whose * element layout is not a sequence layout + * @throws UnsupportedOperationException if the element count of a flattened + * representation of this sequence layout cannot + * be represented as a {@code long} */ SequenceLayout flatten(); diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index 7321cf523d98..713c133ef2e2 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -653,4 +653,18 @@ StackWalker newStackWalkerInstance(Set options, * Finish initialization of the StackTraceElement objects in a stack trace. */ void finishInit(StackTraceElement[] stackTrace); + + /** + * Returns the live native pool-cache storage for the given platform thread, or + * {@code null} if uninitialized. The caller must provide owner-confined + * access; the returned array is not synchronized. + */ + long[] getConfinedMemoryPools(Thread thread); + + /** + * Returns the live native pool-cache storage for the given platform thread or + * initializes one if needed. The caller must provide owner-confined + * access; the returned array is not synchronized. + */ + long[] getOrCreateConfinedMemoryPools(Thread thread, int poolSlots); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationFrame.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationFrame.java index 4417dbaaa401..ffe9fdbec441 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationFrame.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationFrame.java @@ -154,7 +154,7 @@ boolean verify_unset_fields_compatibility(Set target_table) { } void unsatisfied_strict_fields_error(VerificationWrapper klass, int bci) { - _verifier.verifyError("All strict final fields must be initialized before super(): %d field(s), %s" + _verifier.verifyError("All strict fields must be initialized before super(): %d field(s), %s" .formatted(_assert_unset_fields.size(), _assert_unset_fields)); } diff --git a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java index 235797f66e3e..68ff47121697 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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 @@ -245,10 +245,18 @@ public boolean isNative() { @Override public final Optional asOverlappingSlice(MemorySegment other) { final AbstractMemorySegmentImpl that = (AbstractMemorySegmentImpl)Objects.requireNonNull(other); - if (overlaps(that)) { - final long offsetToThat = that.address() - this.address(); - final long newOffset = offsetToThat >= 0 ? offsetToThat : 0; - return Optional.of(asSlice(newOffset, Math.min(this.byteSize() - newOffset, that.byteSize() + offsetToThat))); + if (unsafeGetBase() == that.unsafeGetBase()) { // both either native or the same heap segment + final long thisStart = this.unsafeGetOffset(); + final long thatStart = that.unsafeGetOffset(); + final long thisEnd = thisStart + this.byteSize(); + final long thatEnd = thatStart + that.byteSize(); + // Memory segments denote half-open intervals [start, end). + if (thisStart < thatEnd && thisEnd > thatStart) { + // The intersection is [max(starts), min(ends)). + final long overlapStart = Math.max(thisStart, thatStart); + final long overlapEnd = Math.min(thisEnd, thatEnd); + return Optional.of(asSlice(overlapStart - thisStart, overlapEnd - overlapStart)); + } } return Optional.empty(); } diff --git a/src/java.base/share/classes/jdk/internal/foreign/ArenaImpl.java b/src/java.base/share/classes/jdk/internal/foreign/ArenaImpl.java index 169f27abf651..6d9ff3e797f9 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/ArenaImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/ArenaImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, 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,20 +25,24 @@ package jdk.internal.foreign; +import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.Stable; + import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment.Scope; -public final class ArenaImpl implements Arena { +public sealed class ArenaImpl implements Arena { + + protected final MemorySessionImpl session; + private final boolean shouldReserve; - private final MemorySessionImpl session; - private final boolean shouldReserveMemory; ArenaImpl(MemorySessionImpl session) { this.session = session; - shouldReserveMemory = session instanceof ImplicitSession; + this.shouldReserve = session instanceof ImplicitSession; } @Override - public Scope scope() { + public final Scope scope() { return session; } @@ -48,11 +52,92 @@ public void close() { } public NativeMemorySegmentImpl allocateNoInit(long byteSize, long byteAlignment) { - return SegmentFactories.allocateNativeSegment(byteSize, byteAlignment, session, shouldReserveMemory, false); + return SegmentFactories.allocateNativeSegment(byteSize, byteAlignment, session, shouldReserve, false); } @Override public NativeMemorySegmentImpl allocate(long byteSize, long byteAlignment) { - return SegmentFactories.allocateNativeSegment(byteSize, byteAlignment, session, shouldReserveMemory, true); + return SegmentFactories.allocateNativeSegment(byteSize, byteAlignment, session, shouldReserve, true); + } + + static final class OfConfined extends ArenaImpl { + + private static final long POOL_SIZE = ConfinedSegmentPool.pooledMemorySize(); + + // Set at most once: an arena never switches backing pools. + @Stable + private long pool; + private long poolSp; + + OfConfined(ConfinedSession session) { + super(session); + } + + @Override + public void close() { + // If this fails, the session remains open and the pool must remain owned. + session.justClose(); + try { + session.resourceList.cleanup(); + } finally { + // Cleanup actions can access the backing region through globally scoped + // cleanup segments, so clear and release the pool only after they have run. + if (pool != 0) { + ConfinedSegmentPool.release(pool, poolSp); + } + } + } + + @Override + public NativeMemorySegmentImpl allocateNoInit(long byteSize, long byteAlignment) { + return allocateLowLevel(byteSize, byteAlignment, false); + } + + @Override + public NativeMemorySegmentImpl allocate(long byteSize, long byteAlignment) { + return allocateLowLevel(byteSize, byteAlignment, true); + } + + @ForceInline + private NativeMemorySegmentImpl allocateLowLevel(long byteSize, long byteAlignment, boolean init) { + // Only alignments no greater than the pool size are guaranteed to have an + // aligned address within the pool. This also bounds the alignment arithmetic. + if (byteSize <= POOL_SIZE && byteAlignment <= POOL_SIZE) { + Utils.checkAllocationSizeAndAlign(byteSize, byteAlignment); + session.checkValidState(); + long pool = this.pool; + if (pool == 0) { + pool = ConfinedSegmentPool.acquire(); + if (pool == 0) { + pool = ConfinedSegmentPool.allocateLocal(); + } + if (pool != 0) { + this.pool = pool; + } + } + // Preserve the invariant that zero-sized segments have unique addresses + // for any given Arena. + final long allocationByteSize = Math.max(1, byteSize); + final long address; + if (pool != 0 && (address = trySlice(pool, allocationByteSize, byteAlignment)) != 0) { + return SegmentFactories.makeNativeSegmentUnchecked(address, byteSize, session); + } + } + return init + ? super.allocate(byteSize, byteAlignment) + : super.allocateNoInit(byteSize, byteAlignment); + } + + private long trySlice(long pool, long byteSize, long byteAlignment) { + final long start = Utils.alignUp(pool + poolSp, byteAlignment) - pool; + if (start + byteSize <= POOL_SIZE) { + // The backing memory is zeroed on initial allocation and on each pool release. + poolSp = start + byteSize; + return pool + start; + } + return 0; + } + } + } diff --git a/src/java.base/share/classes/jdk/internal/foreign/ConfinedSegmentPool.java b/src/java.base/share/classes/jdk/internal/foreign/ConfinedSegmentPool.java new file mode 100644 index 000000000000..8af11e21c176 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/foreign/ConfinedSegmentPool.java @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.foreign; + +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; +import jdk.internal.misc.Unsafe; +import jdk.internal.misc.VM; +import jdk.internal.vm.Continuation; +import jdk.internal.vm.ContinuationSupport; +import jdk.internal.vm.annotation.DontInline; +import jdk.internal.vm.annotation.ForceInline; + +/** + * Provides reusable native-memory pools for confined arenas. + *

    + * Each platform thread lazily maintains a cache containing a configurable number + * of fixed-size pools. Small allocations made by a confined arena are carved out + * from one pool. Allocations that do not fit in the pool use the regular native + * allocator. If no cached pool is available, the arena may allocate a local pool + * and attempt to cache it when the arena is closed. + *

    + * A platform thread acquires pools from its own cache, while a virtual thread + * acquires pools from its current carrier thread's cache. In both cases, an + * acquired pool is removed from the cache and owned exclusively by the arena + * until it is closed. Consequently, platform- or carrier-thread termination + * can free only available cached pools and does not affect pools owned by open + * arenas. Removing virtual-thread-owned pools from the carrier cache also + * prevents the original carrier from freeing such a pool if the virtual thread + * migrates and that carrier terminates. + *

    + * When an arena is closed, its pool is returned to the owning platform + * thread's cache or, for a virtual thread, to the current carrier's cache. The + * pool is freed instead if the target cache is full. + *

    + * Before a pool is released, the portion used by the arena is cleared. + * Together with clearing performed when a pool is initially allocated, this + * ensures that pooled allocations do not expose data written by an earlier + * arena. + *

    + * The pool cache is accessed only by its owning platform thread, either + * directly or while that thread is acting as a virtual-thread carrier. + * Consequently, cache acquisition and release do not require synchronization. + *

    + * Pool entries use the following representation: + *

      + *
    • zero: empty cache entry; + *
    • non-zero: available pool. + *
    + * Acquired pools are not represented in the cache. + *

    + * Pooling can be disabled through the internal pool configuration. + * When disabled, all allocations use the regular native allocator. + *

    + * This class operates directly on native addresses using {@link Unsafe}. + * Its ownership and clearing invariants must therefore be preserved when + * acquisition, release, or thread-termination protocols are changed. + * Defensive release checks detect invalid sizes and some duplicate releases, but + * cannot validate arbitrary native addresses. + */ +public final class ConfinedSegmentPool { + + private ConfinedSegmentPool() { } + + private static final Unsafe U = Unsafe.getUnsafe(); + + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + + private static final String PROPERTY_PATH = "jdk.internal.foreign.native.confined.pool.power."; + + // Unsupported implementation-specific tuning knob; no behavioral or compatibility + // guarantees are given. + // A negative value disables pooling; otherwise the pool size is + // 2^3, 2^4, ..., 2^20 bytes, defaulting to 2^6 = 64 bytes. + private static final String POOLED_MEMORY_SIZE_PROPERTY = PROPERTY_PATH + "size"; + + private static final long POOLED_MEMORY_SIZE = + clampedPowerOfPropertyOr(POOLED_MEMORY_SIZE_PROPERTY, 3, 20, 6); + + // Unsupported implementation-specific tuning knob; no behavioral or compatibility + // guarantees are given. + // A negative value disables pooling; otherwise the pool count is + // 1, 2, 4, or 8, defaulting to 4 corresponding to a cache capacity of four available + // pools per platform thread. + private static final String THREAD_POOL_COUNT_PROPERTY = PROPERTY_PATH + "count"; + + private static final int THREAD_POOL_COUNT = + clampedPowerOfPropertyOr(THREAD_POOL_COUNT_PROPERTY, 0, 3, 2); + + private static final boolean POOLING_DISABLED = POOLED_MEMORY_SIZE <= 0 || THREAD_POOL_COUNT <= 0; + + /** + * Returns the size of the native memory pool, or {@code -1} if pooling is disabled. + */ + public static long pooledMemorySize() { + return POOLING_DISABLED ? -1 : POOLED_MEMORY_SIZE; + } + + /** + * Acquires and removes a pool from the appropriate cache for an arena owned + * by the current thread. A platform-thread arena uses its owner's cache, while + * a virtual-thread arena uses the current carrier's cache. + * + * @return a non-zero native address, or zero if no pool is available + */ + @ForceInline + static long acquire() { + if (POOLING_DISABLED) { + return 0; + } + final Thread thread = Thread.currentThread(); + if (ContinuationSupport.isSupported() && thread.isVirtual()) { + Continuation.pin(); + try { + return acquireFromCache(JLA.currentCarrierThread()); + } finally { + Continuation.unpin(); + } + } else { + return acquireFromCache(thread); + } + } + + /** + * Allocates a pool owned directly by the arena and not yet present in any + * thread cache. On arena close, the pool is cached or freed. + */ + static long allocateLocal() { + return POOLING_DISABLED ? 0 : allocateDetachedPool(); + } + + /** + * Clears the used prefix and returns the pool to the appropriate cache. + * Platform-thread arenas return pools to their owner; virtual-thread arenas + * return pools to the current carrier. + */ + @ForceInline + static void release(long pool, long usedSize) { + final Thread thread = Thread.currentThread(); + if (ContinuationSupport.isSupported() && thread.isVirtual()) { + Continuation.pin(); + try { + releaseToCache(JLA.currentCarrierThread(), pool, usedSize); + } finally { + Continuation.unpin(); + } + } else { + releaseToCache(thread, pool, usedSize); + } + } + + /** + * Frees all available pools recorded in the terminating platform thread's + * cache. Pools owned by open arenas are detached from the cache and are not + * affected. + */ + public static void threadTerminated(long[] pools) { + for (int i = 0; i < pools.length; i++) { + final long pool = pools[i]; + if (pool != 0) { + U.freeMemory(pool); + pools[i] = 0; + } + } + } + + @ForceInline + private static long acquireFromCache(Thread cacheOwner) { + final long[] pools = JLA.getConfinedMemoryPools(cacheOwner); + if (pools == null) { + return 0; + } + for (int i = 0; i < pools.length; i++) { + final long pool = pools[i]; + if (pool != 0) { + pools[i] = 0; // available -> arena-owned and detached + return pool; + } + } + return 0; + } + + private static long allocateDetachedPool() { + final long address; + try { + address = U.allocateMemory(POOLED_MEMORY_SIZE); + } catch (OutOfMemoryError _) { + return 0; + } + zeroOutMemory(address, POOLED_MEMORY_SIZE); + return address; + } + + @ForceInline + private static void releaseToCache(Thread cacheOwner, long pool, long usedSize) { + // Reject invalid prefixes before zeroOutMemory performs unchecked writes. + if (pool == 0 || usedSize < 0 || usedSize > POOLED_MEMORY_SIZE) { + throw cannotReleasePooledMemory(pool, usedSize); + } + + long[] pools = JLA.getConfinedMemoryPools(cacheOwner); + if (pools == null) { + pools = createPoolCacheOrFree(cacheOwner, pool); + if (pools == null) { + return; // The `createPoolCacheOrFree` method freed the pool. + } + } + + for (int i = 0; i < pools.length; i++) { + final long entry = pools[i]; + if (entry == pool) { + throw cannotReleasePooledMemory(pool, usedSize); // already released + } + if (entry == 0) { + zeroOutMemory(pool, usedSize); + pools[i] = pool; + return; + } + } + U.freeMemory(pool); + } + + // Support method to isolate exception handling from the hot inline path + @DontInline + private static long[] createPoolCacheOrFree(Thread cacheOwner, long pool) { + try { + return JLA.getOrCreateConfinedMemoryPools(cacheOwner, THREAD_POOL_COUNT); + } catch (OutOfMemoryError _) { + // In the unlikely event a `new long[]` fails we still need to free the + // pool and allow the rest of the Arena's cleanup operations to continue + U.freeMemory(pool); + return null; + } + } + + @DontInline + private static IllegalStateException cannotReleasePooledMemory(long pool, long size) { + return new IllegalStateException("Cannot release pooled memory owned by " + JLA.currentCarrierThread() + ", pool = " + pool + ", size = " + size); + } + + @SuppressWarnings("fallthrough") + @ForceInline + private static void zeroOutMemory(long address, long size) { + // Pools are always at least `long` aligned so we can use aligned Unsafe access + // below. + // We are first checking `POOLED_MEMORY_SIZE` here rather than + // `size` to enable potential code elimination by the C2 compiler. + if (POOLED_MEMORY_SIZE <= 64 || size <= 64) { + // Deliberate fall-through clears the required number of 8-byte buckets + // without a loop branch. The validated size guarantees writes remain in-pool. + switch ((int) ((size + Long.BYTES - 1) >>> 3)) { + case 8: U.putLong(address + 0x38, 0L); + case 7: U.putLong(address + 0x30, 0L); + case 6: U.putLong(address + 0x28, 0L); + case 5: U.putLong(address + 0x20, 0L); + case 4: U.putLong(address + 0x18, 0L); + case 3: U.putLong(address + 0x10, 0L); + case 2: U.putLong(address + 0x08, 0L); + case 1: U.putLong(address, 0L); + case 0: break; + default: throw new IllegalStateException(Long.toString(size)); + } + } else { + // This is safe because the underlying pool is guaranteed to be of a size + // that is a multiple of a `long`. + for (long i = 0; i < size; i += Long.BYTES) { + U.putLong(address + i, 0L); + } + } + } + + private static int clampedPowerOfPropertyOr(String name, int minPower, + int maxPower, int defaultPower) { + // Slicing out memory segment from an otherwise page aligned pool slab would make + // native memory slices non-aligned to page boundaries. Hence, we need to + // disable pooling in such cases. + if (VM.isDirectMemoryPageAligned()) { + return -1; + } + final int power = Integer.getInteger(name, defaultPower); + + return power < 0 + ? -1 + : Math.toIntExact(1L << Math.clamp(power, minPower, maxPower)); + } + +} diff --git a/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java b/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java index 47dfc69e887d..926d09512658 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java +++ b/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java @@ -82,6 +82,11 @@ void justClose() { } } + @Override + public ArenaImpl asArena() { + return new ArenaImpl.OfConfined(this); + } + /** * A confined resource list; no races are possible here. */ diff --git a/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java b/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java index a9e7751fc50b..c3dc4829eca1 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, 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 @@ -112,8 +112,10 @@ public static void copy(AbstractMemorySegmentImpl src, long srcOffset, src.checkAccess(srcOffset, size, true); dst.checkAccess(dstOffset, size, false); - if (size <= 0) { - // Do nothing + if (size == 0) { + // No memory access occurs below, so the segments' states must be checked explicitly. + src.sessionImpl().checkValidState(); + dst.sessionImpl().checkValidState(); } else if (size < NATIVE_THRESHOLD_COPY && !src.overlaps(dst)) { // 0 < size < FILL_NATIVE_LIMIT : 0...0X...XXXX // @@ -257,6 +259,9 @@ public static long mismatch(AbstractMemorySegmentImpl src, long srcFromOffset, l final boolean srcAndDstBytesDiffer = srcBytes != dstBytes; if (length == 0) { + // No memory access occurs below, so the segments' states must be checked explicitly. + src.sessionImpl().checkValidState(); + dst.sessionImpl().checkValidState(); return srcAndDstBytesDiffer ? 0 : -1; } else if (length < NATIVE_THRESHOLD_MISMATCH) { return mismatch(src, srcFromOffset, dst, dstFromOffset, 0, (int) length, srcAndDstBytesDiffer); diff --git a/src/java.base/share/classes/jdk/internal/foreign/layout/SequenceLayoutImpl.java b/src/java.base/share/classes/jdk/internal/foreign/layout/SequenceLayoutImpl.java index 1dc9ba918477..de0396cd0c1f 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/layout/SequenceLayoutImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/layout/SequenceLayoutImpl.java @@ -30,6 +30,7 @@ import java.lang.foreign.MemoryLayout; import java.lang.foreign.SequenceLayout; +import java.util.Arrays; import java.util.Objects; import java.util.Optional; @@ -115,7 +116,7 @@ public SequenceLayout reshape(long... elementCounts) { if (elementCounts.length == 0) { throw new IllegalArgumentException(); } - SequenceLayout flat = flatten(); + SequenceLayout flat = flatten(); // May throw UnsupportedOperationException long expectedCount = flat.elementCount(); long actualCount = 1; @@ -130,7 +131,7 @@ public SequenceLayout reshape(long... elementCounts) { } else if (elementCounts[i] <= 0) { throw new IllegalArgumentException("Invalid element count: " + elementCounts[i]); } else { - actualCount = elementCounts[i] * actualCount; + actualCount = multiplyExactOrIae(elementCounts[i], actualCount, elementCounts); } } @@ -138,7 +139,7 @@ public SequenceLayout reshape(long... elementCounts) { if (inferPosition != -1) { long inferredCount = expectedCount / actualCount; elementCounts[inferPosition] = inferredCount; - actualCount = actualCount * inferredCount; + actualCount = multiplyExactOrIae(actualCount, inferredCount, elementCounts); } if (actualCount != expectedCount) { @@ -170,10 +171,27 @@ public SequenceLayout reshape(long... elementCounts) { * element count), whose element layout is not a sequence layout. */ public SequenceLayout flatten() { - long count = elementCount(); MemoryLayout elemLayout = elementLayout(); + boolean hasZeroCount = elementCount() == 0; + // Do an intitial pass and check if any of the element counts are zero + // to prevent throwing an overflow in that case. while (elemLayout instanceof SequenceLayoutImpl elemSeq) { - count = count * elemSeq.elementCount(); + long elemCount = elemSeq.elementCount(); + hasZeroCount |= elemCount == 0; + elemLayout = elemSeq.elementLayout(); + } + if (hasZeroCount) { + return MemoryLayout.sequenceLayout(0, elemLayout); + } + + long count = elementCount(); + elemLayout = elementLayout(); + while (elemLayout instanceof SequenceLayoutImpl elemSeq) { + try { + count = Math.multiplyExact(count, elemSeq.elementCount()); + } catch (ArithmeticException e) { + throw new UnsupportedOperationException("Flattening of elements gave a count that is out of range.", e); + } elemLayout = elemSeq.elementLayout(); } return MemoryLayout.sequenceLayout(count, elemLayout); @@ -222,4 +240,12 @@ public static SequenceLayout of(long elementCount, MemoryLayout elementLayout) { return new SequenceLayoutImpl(elementCount, elementLayout); } + private static long multiplyExactOrIae(long a, long b, long[] elementCounts) { + try { + return Math.multiplyExact(a, b); + } catch (ArithmeticException e) { + throw new IllegalArgumentException("Counts overflow: " + Arrays.toString(elementCounts)); + } + } + } diff --git a/src/java.base/share/classes/jdk/internal/math/Int128Math.java b/src/java.base/share/classes/jdk/internal/math/Int128Math.java new file mode 100644 index 000000000000..8dd8388f52db --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/math/Int128Math.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.math; + +import jdk.internal.vm.annotation.IntrinsicCandidate; + +/** + * This class serves as API points to verify the correctness of the + * implementation of corresponding C2 nodes. + */ +public final class Int128Math { + private Int128Math() { + throw new UnsupportedOperationException(); + } + + @IntrinsicCandidate + public static long addLo(long lo1, long hi1, long lo2, long hi2) { + return lo1 + lo2; + } + + @IntrinsicCandidate + public static long addHi(long lo1, long hi1, long lo2, long hi2) { + long sumLo = lo1 + lo2; + boolean loOverflow = Long.compareUnsigned(sumLo, lo1) < 0; + return hi1 + hi2 + (loOverflow ? 1 : 0); + } + + @IntrinsicCandidate + public static long subLo(long lo1, long hi1, long lo2, long hi2) { + return lo1 - lo2; + } + + @IntrinsicCandidate + public static long subHi(long lo1, long hi1, long lo2, long hi2) { + boolean loOverflow = Long.compareUnsigned(lo1, lo2) < 0; + return hi1 - hi2 - (loOverflow ? 1 : 0); + } +} diff --git a/src/java.base/share/classes/jdk/internal/misc/X-ScopedMemoryAccess.java.template b/src/java.base/share/classes/jdk/internal/misc/X-ScopedMemoryAccess.java.template index a04fea67b882..b97652f0cb67 100644 --- a/src/java.base/share/classes/jdk/internal/misc/X-ScopedMemoryAccess.java.template +++ b/src/java.base/share/classes/jdk/internal/misc/X-ScopedMemoryAccess.java.template @@ -239,85 +239,57 @@ public final class ScopedMemoryAccess { @ForceInline public boolean isLoaded(MemorySessionImpl session, MappedMemoryUtilsProxy mappedUtils, long address, boolean isSync, long size) { - try { - return isLoadedInternal(session, mappedUtils, address, isSync, size); - } catch (ScopedAccessError ex) { - throw ex.newRuntimeException(); + if (session != null) { + session.acquire0(); } - } - - @ForceInline @Scoped - public boolean isLoadedInternal(MemorySessionImpl session, MappedMemoryUtilsProxy mappedUtils, long address, boolean isSync, long size) { try { - if (session != null) { - session.checkValidStateRaw(); - } return mappedUtils.isLoaded(address, isSync, size); } finally { - Reference.reachabilityFence(session); + if (session != null) { + session.release0(); + } } } @ForceInline public void load(MemorySessionImpl session, MappedMemoryUtilsProxy mappedUtils, long address, boolean isSync, long size) { - try { - loadInternal(session, mappedUtils, address, isSync, size); - } catch (ScopedAccessError ex) { - throw ex.newRuntimeException(); + if (session != null) { + session.acquire0(); } - } - - @ForceInline @Scoped - public void loadInternal(MemorySessionImpl session, MappedMemoryUtilsProxy mappedUtils, long address, boolean isSync, long size) { try { - if (session != null) { - session.checkValidStateRaw(); - } mappedUtils.load(address, isSync, size); } finally { - Reference.reachabilityFence(session); + if (session != null) { + session.release0(); + } } } @ForceInline public void unload(MemorySessionImpl session, MappedMemoryUtilsProxy mappedUtils, long address, boolean isSync, long size) { - try { - unloadInternal(session, mappedUtils, address, isSync, size); - } catch (ScopedAccessError ex) { - throw ex.newRuntimeException(); + if (session != null) { + session.acquire0(); } - } - - @ForceInline @Scoped - public void unloadInternal(MemorySessionImpl session, MappedMemoryUtilsProxy mappedUtils, long address, boolean isSync, long size) { try { - if (session != null) { - session.checkValidStateRaw(); - } mappedUtils.unload(address, isSync, size); } finally { - Reference.reachabilityFence(session); + if (session != null) { + session.release0(); + } } } @ForceInline public void force(MemorySessionImpl session, MappedMemoryUtilsProxy mappedUtils, FileDescriptor fd, long address, boolean isSync, long index, long length) { - try { - forceInternal(session, mappedUtils, fd, address, isSync, index, length); - } catch (ScopedAccessError ex) { - throw ex.newRuntimeException(); + if (session != null) { + session.acquire0(); } - } - - @ForceInline @Scoped - public void forceInternal(MemorySessionImpl session, MappedMemoryUtilsProxy mappedUtils, FileDescriptor fd, long address, boolean isSync, long index, long length) { try { - if (session != null) { - session.checkValidStateRaw(); - } mappedUtils.force(fd, address, isSync, index, length); } finally { - Reference.reachabilityFence(session); + if (session != null) { + session.release0(); + } } } diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index f84f27cb4a95..316408d01116 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -155,7 +155,8 @@ exports jdk.internal.javac to java.compiler, jdk.compiler, - jdk.jdeps; // Uses Valhalla reflective preview APIs + jdk.jdeps, // Uses Valhalla reflective preview APIs + jdk.incubator.json; exports jdk.internal.access to java.desktop, java.logging, diff --git a/src/java.base/share/classes/sun/security/ssl/Finished.java b/src/java.base/share/classes/sun/security/ssl/Finished.java index 7ca9f50be971..918664a6037c 100644 --- a/src/java.base/share/classes/sun/security/ssl/Finished.java +++ b/src/java.base/share/classes/sun/security/ssl/Finished.java @@ -433,6 +433,7 @@ private byte[] onProduceFinished(ClientHandshakeContext chc, if (!chc.sslContext.isDTLS()) { chc.conContext.finishHandshake(); } + recordEvent(chc); } // The handshake message has been delivered. @@ -499,6 +500,7 @@ private byte[] onProduceFinished(ServerHandshakeContext shc, if (!shc.sslContext.isDTLS()) { shc.conContext.finishHandshake(); } + recordEvent(shc); } // The handshake message has been delivered. @@ -562,12 +564,12 @@ private void onConsumeFinished(ClientHandshakeContext chc, // handshake context cleanup. chc.handshakeFinished = true; - recordEvent(chc); // May need to retransmit the last flight for DTLS. if (!chc.sslContext.isDTLS()) { chc.conContext.finishHandshake(); } + recordEvent(chc); } else { chc.handshakeProducers.put(SSLHandshake.FINISHED.id, SSLHandshake.FINISHED); @@ -623,12 +625,12 @@ private void onConsumeFinished(ServerHandshakeContext shc, // handshake context cleanup. shc.handshakeFinished = true; - recordEvent(shc); // May need to retransmit the last flight for DTLS. if (!shc.sslContext.isDTLS()) { shc.conContext.finishHandshake(); } + recordEvent(shc); } else { shc.handshakeProducers.put(SSLHandshake.FINISHED.id, SSLHandshake.FINISHED); diff --git a/src/java.base/share/native/libjli/java.c b/src/java.base/share/native/libjli/java.c index bf2d309e8e8f..1236e7cbaf12 100644 --- a/src/java.base/share/native/libjli/java.c +++ b/src/java.base/share/native/libjli/java.c @@ -88,6 +88,7 @@ static jboolean _have_classpath = JNI_FALSE; static const char *_fVersion; static jboolean _wc_enabled = JNI_FALSE; static jboolean dumpSharedSpaces = JNI_FALSE; /* -Xshare:dump */ +static const char *launchModeNames[] = { "Unknown", "Main class", "JAR file", "Module", "Source" }; /* * Values that will be stored into splash screen environment variables. @@ -727,7 +728,8 @@ IsModuleOption(const char* name) { JLI_StrCmp(name, "--add-exports") == 0 || JLI_StrCmp(name, "--add-opens") == 0 || JLI_StrCmp(name, "--add-reads") == 0 || - JLI_StrCmp(name, "--patch-module") == 0; + JLI_StrCmp(name, "--patch-module") == 0 || + JLI_StrCmp(name, "--enable-final-field-mutation") == 0; } static jboolean @@ -739,7 +741,21 @@ IsLongFormModuleOption(const char* name) { JLI_StrCCmp(name, "--limit-modules=") == 0 || JLI_StrCCmp(name, "--add-exports=") == 0 || JLI_StrCCmp(name, "--add-reads=") == 0 || - JLI_StrCCmp(name, "--patch-module=") == 0; + JLI_StrCCmp(name, "--patch-module=") == 0 || + JLI_StrCCmp(name, "--enable-final-field-mutation=") == 0; +} + +/* + * Test if the given name is a non-module VM white-space option that + * will be passed to the VM with its corresponding long-form option + * name and "=" delimiter. + */ +static jboolean +IsNonModuleVMWhiteSpaceOption(const char* name) { + return JLI_StrCmp(name, "--illegal-native-access") == 0 || + JLI_StrCmp(name, "--illegal-final-field-mutation") == 0 || + JLI_StrCmp(name, "--sun-misc-unsafe-memory-access") == 0 || + JLI_StrCmp(name, "--finalization") == 0; } /* @@ -748,7 +764,8 @@ IsLongFormModuleOption(const char* name) { jboolean IsWhiteSpaceOption(const char* name) { return IsModuleOption(name) || - IsLauncherOption(name); + IsLauncherOption(name) || + IsNonModuleVMWhiteSpaceOption(name); } /* @@ -1125,7 +1142,7 @@ GetOpt(int *pargc, char ***pargv, char **poption, char **pvalue) { } kind = IsLauncherMainOption(arg) ? LAUNCHER_MAIN_OPTION : LAUNCHER_OPTION_WITH_ARGUMENT; - } else if (IsModuleOption(arg)) { + } else if (IsModuleOption(arg) || IsNonModuleVMWhiteSpaceOption(arg)) { kind = VM_LONG_OPTION_WITH_ARGUMENT; if (has_arg) { value = *argv; @@ -1239,6 +1256,12 @@ ParseArguments(int *pargc, char ***pargv, } else if (kind == VM_LONG_OPTION_WITH_ARGUMENT) { AddLongFormOption(option, value); } + /* + * Normalize a missing argument to the equivalent "--option=" form + * and let the subsequent option validation handle the empty value. + */ + } else if (!has_arg && IsNonModuleVMWhiteSpaceOption(arg)) { + AddLongFormOption(option, ""); /* * Error missing argument */ diff --git a/src/java.base/share/native/libjli/java.h b/src/java.base/share/native/libjli/java.h index 5586cef5cbc8..e6ed469fc5c9 100644 --- a/src/java.base/share/native/libjli/java.h +++ b/src/java.base/share/native/libjli/java.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, 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 @@ -215,9 +215,6 @@ enum LaunchMode { // cf. sun.launcher.LauncherHelper LM_SOURCE }; -static const char *launchModeNames[] - = { "Unknown", "Main class", "JAR file", "Module", "Source" }; - typedef struct { int argc; char **argv; diff --git a/src/java.base/unix/native/libjava/childproc.c b/src/java.base/unix/native/libjava/childproc.c index 6bc15dfb40c4..833adba52748 100644 --- a/src/java.base/unix/native/libjava/childproc.c +++ b/src/java.base/unix/native/libjava/childproc.c @@ -369,10 +369,11 @@ JDK_execvpe(int mode, const char *file, } /** - * Child process after a successful fork(). - * This function must not return, and must be prepared for either all - * of its address space to be shared with its parent, or to be a copy. - * It must not modify global variables such as "environ". + * Child process after a successful fork() or after posix_spawn() inside + * jspawnhelper. + * This function must not return. It will prepare the exec of the target + * binary, then exec the target binary. If an error occurs, it ends the + * process with _exit(). */ int childProcess(void *arg) diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsChannelFactory.java b/src/java.base/windows/classes/sun/nio/fs/WindowsChannelFactory.java index 75d68f938c1e..ef03b6a6f413 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsChannelFactory.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsChannelFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, 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 @@ -319,7 +319,7 @@ private static FileDescriptor open(String pathForWindows, // make the file sparse if needed if (dwCreationDisposition == CREATE_NEW && flags.sparse) { try { - DeviceIoControlSetSparse(handle); + DeviceIoControl(handle, FSCTL_SET_SPARSE, 0L, 0); } catch (WindowsException x) { // ignore as sparse option is hint } diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsConstants.java b/src/java.base/windows/classes/sun/nio/fs/WindowsConstants.java index 2c91bb017738..b66e73f1d206 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsConstants.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsConstants.java @@ -78,6 +78,11 @@ private WindowsConstants() { } public static final int IO_REPARSE_TAG_DEDUP = 0x80000013; public static final int IO_REPARSE_TAG_CLOUD = 0x9000001A; public static final int IO_REPARSE_TAG_CLOUD_MASK = 0x0000F000; + + // DeviceIoControl control codes + public static final int FSCTL_GET_REPARSE_POINT = 0x000900A8; + public static final int FSCTL_SET_SPARSE = 0x000900C4; + public static final int MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024; public static final int SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1; public static final int SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 0x2; diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java b/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java index 0b938bde54c8..40cd5169518b 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java @@ -328,8 +328,8 @@ static WindowsFileAttributes readAttributes(long handle) if (isReparsePoint(fileAttrs)) { int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; try (NativeBuffer reparseBuffer = NativeBuffers.getNativeBuffer(size)) { - DeviceIoControlGetReparsePoint(handle, reparseBuffer.address(), size); - reparseTag = (int)unsafe.getLong(reparseBuffer.address()); + DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, reparseBuffer.address(), size); + reparseTag = unsafe.getInt(reparseBuffer.address()); } } diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsLinkSupport.java b/src/java.base/windows/classes/sun/nio/fs/WindowsLinkSupport.java index fc79153914d4..8e3bf4ce49a3 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsLinkSupport.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsLinkSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ private WindowsLinkSupport() { } /** - * Creates a symbolic link, retyring if not privileged + * Creates a symbolic link, retrying if not privileged */ static void createSymbolicLink(String link, String target, int flags) throws WindowsException @@ -148,7 +148,7 @@ static String getFinalPath(WindowsPath input, boolean followLinks) try { WindowsFileAttributes attrs = WindowsFileAttributes.get(target, false); - // non a link so we are done + // not a link so we are done if (!attrs.isSymbolicLink()) { return target.getPathForWin32Calls(); } @@ -207,7 +207,7 @@ static String getRealPath(WindowsPath input, boolean resolveLinks) char c1 = path.charAt(1); if ((c0 <= 'z' && c0 >= 'a' || c0 <= 'Z' && c0 >= 'A') && c1 == ':' && path.charAt(2) == '\\') { - // Driver specifier + // Drive specifier sb.append(Character.toUpperCase(c0)); sb.append(":\\"); start = 3; @@ -291,14 +291,17 @@ static String getRealPath(WindowsPath input, boolean resolveLinks) */ static String readLink(WindowsPath path, long handle) throws IOException { int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; + String pathname = path.getPathForExceptionMessage(); try (NativeBuffer buffer = NativeBuffers.getNativeBuffer(size)) { + int bytesReturned; try { - DeviceIoControlGetReparsePoint(handle, buffer.address(), size); + bytesReturned = DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, + buffer.address(), size); } catch (WindowsException x) { - String pathname = path.getPathForExceptionMessage(); - if (x.lastError() == ERROR_NOT_A_REPARSE_POINT) + if (x.lastError() == ERROR_NOT_A_REPARSE_POINT) { throw new NotLinkException(pathname, null, x.errorString()); - x.rethrowAsIOException(pathname + ": " + x.errorString()); + } + throw x.asIOException(path); } /* @@ -312,6 +315,7 @@ static String readLink(WindowsPath path, long handle) throws IOException { * USHORT SubstituteNameLength; * USHORT PrintNameOffset; * USHORT PrintNameLength; + * ULONG Flags; * WCHAR PathBuffer[1]; * } SymbolicLinkReparseBuffer; * struct { @@ -328,21 +332,41 @@ static String readLink(WindowsPath path, long handle) throws IOException { * } REPARSE_DATA_BUFFER */ final short OFFSETOF_REPARSETAG = 0; + final short OFFSETOF_REPARSEDATALENGTH = 4; final short OFFSETOF_PATHOFFSET = 8; final short OFFSETOF_PATHLENGTH = 10; - final short OFFSETOF_PATHBUFFER = 16 + 4; // check this + final short OFFSETOF_PATHBUFFER = 20; + final short SIZEOF_REPARSE_DATA_BUFFER_HEADER = 8; + final short SIZEOF_SYMLINK_REPARSE_BUFFER = 12; - int tag = (int)unsafe.getLong(buffer.address() + OFFSETOF_REPARSETAG); + int tag = unsafe.getInt(buffer.address() + OFFSETOF_REPARSETAG); if (tag != IO_REPARSE_TAG_SYMLINK) { - String pathname = path.getPathForExceptionMessage(); throw new NotLinkException(pathname, null, "Reparse point is not a symbolic link"); } - // get offset and length of target - short nameOffset = unsafe.getShort(buffer.address() + OFFSETOF_PATHOFFSET); - short nameLengthInBytes = unsafe.getShort(buffer.address() + OFFSETOF_PATHLENGTH); - if ((nameLengthInBytes % 2) != 0) - throw new FileSystemException(null, null, "Symbolic link corrupted"); + // minimum size of valid symbolic-link REPARSE_DATA_BUFFER is 20 bytes + if (bytesReturned < OFFSETOF_PATHBUFFER) { + throw new NotLinkException(pathname, null, "Symbolic link corrupted"); + } + + int reparseDataLength = Short.toUnsignedInt( + unsafe.getShort(buffer.address() + OFFSETOF_REPARSEDATALENGTH)); + int nameOffset = Short.toUnsignedInt( + unsafe.getShort(buffer.address() + OFFSETOF_PATHOFFSET)); + int nameLengthInBytes = Short.toUnsignedInt( + unsafe.getShort(buffer.address() + OFFSETOF_PATHLENGTH)); + int pathBufferSize = reparseDataLength - SIZEOF_SYMLINK_REPARSE_BUFFER; + + // returned data must contain the fixed fields and an even-length + // UTF-16 name whose offset and length are within the path buffer + if ((reparseDataLength < SIZEOF_SYMLINK_REPARSE_BUFFER) + || (reparseDataLength > bytesReturned - SIZEOF_REPARSE_DATA_BUFFER_HEADER) + || ((nameOffset & 1) != 0) + || ((nameLengthInBytes & 1) != 0) + || (nameOffset > pathBufferSize) + || (nameLengthInBytes > pathBufferSize - nameOffset)) { + throw new NotLinkException(pathname, null, "Symbolic link corrupted"); + } // copy into char array char[] name = new char[nameLengthInBytes/2]; @@ -352,7 +376,7 @@ static String readLink(WindowsPath path, long handle) throws IOException { // remove special prefix String target = stripPrefix(new String(name)); if (target.isEmpty()) { - throw new IOException("Symbolic link target is invalid"); + throw new NotLinkException(pathname, null, "Symbolic link target is empty"); } // return normalized path string @@ -361,7 +385,7 @@ static String readLink(WindowsPath path, long handle) throws IOException { } /** - * Resolve all symbolic-links in a given absolute and normalized path + * Resolve all symbolic links in a given absolute and normalized path */ private static WindowsPath resolveAllLinks(WindowsPath path) throws IOException diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java b/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java index d6f68b72ed39..1832e9d6821b 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java @@ -141,23 +141,18 @@ private static native void RemoveDirectory0(long lpFileName) throws WindowsException; /** - * Marks a file as a sparse file. - * * DeviceIoControl( - * FSCTL_SET_SPARSE - * ) - */ - static native void DeviceIoControlSetSparse(long handle) - throws WindowsException; - - /** - * Retrieves the reparse point data associated with the file or directory. - * - * DeviceIoControl( - * FSCTL_GET_REPARSE_POINT + * HANDLE hDevice, + * DWORD dwIoControlCode, + * NULL, + * 0, + * LPVOID lpOutBuffer, + * DWORD nOutBufferSize, + * LPDWORD lpBytesReturned, + * NULL * ) */ - static native void DeviceIoControlGetReparsePoint(long handle, + static native int DeviceIoControl(long handle, int dwIoControlCode, long bufferAddress, int bufferSize) throws WindowsException; /** diff --git a/src/java.base/windows/native/libjava/TimeZone_md.c b/src/java.base/windows/native/libjava/TimeZone_md.c index 7b78951793c1..31397b6fcee4 100644 --- a/src/java.base/windows/native/libjava/TimeZone_md.c +++ b/src/java.base/windows/native/libjava/TimeZone_md.c @@ -318,15 +318,6 @@ static int getWinTimeZone(char *winZoneName, size_t winZoneNameBufSize) ret = getValueInRegistry(hSubKey, STD_NAME, &valueType, szValue, &size); if (ret != ERROR_SUCCESS) { - /* - * NT 4.0 SP3 fails here since it doesn't have the "Std" - * entry in the Time Zones registry. - */ - RegCloseKey(hSubKey); - ret = RegOpenKeyExW(hKey, stdNamePtr, 0, KEY_READ, (PHKEY)&hSubKey); - if (ret != ERROR_SUCCESS) { - goto err; - } RegCloseKey(hSubKey); break; } diff --git a/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c b/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c index 87beaf4fc666..68dbcc097373 100644 --- a/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c +++ b/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c @@ -278,30 +278,21 @@ Java_sun_nio_fs_WindowsNativeDispatcher_CreateFile0(JNIEnv* env, jclass this, return ptr_to_jlong(handle); } -JNIEXPORT void JNICALL -Java_sun_nio_fs_WindowsNativeDispatcher_DeviceIoControlSetSparse(JNIEnv* env, jclass this, - jlong handle) -{ - DWORD bytesReturned; - HANDLE h = (HANDLE)jlong_to_ptr(handle); - if (DeviceIoControl(h, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &bytesReturned, NULL) == 0) { - throwWindowsException(env, GetLastError()); - } -} - -JNIEXPORT void JNICALL -Java_sun_nio_fs_WindowsNativeDispatcher_DeviceIoControlGetReparsePoint(JNIEnv* env, jclass this, - jlong handle, jlong bufferAddress, jint bufferSize) +JNIEXPORT jint JNICALL +Java_sun_nio_fs_WindowsNativeDispatcher_DeviceIoControl(JNIEnv* env, jclass this, + jlong handle, jint dwIoControlCode, jlong bufferAddress, jint bufferSize) { DWORD bytesReturned; HANDLE h = (HANDLE)jlong_to_ptr(handle); LPVOID outBuffer = (LPVOID)jlong_to_ptr(bufferAddress); - if (DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, outBuffer, (DWORD)bufferSize, + if (DeviceIoControl(h, (DWORD)dwIoControlCode, NULL, 0, outBuffer, (DWORD)bufferSize, &bytesReturned, NULL) == 0) { throwWindowsException(env, GetLastError()); + return 0; } + return (jint)bytesReturned; } JNIEXPORT void JNICALL diff --git a/src/java.se/share/data/jdwp/jdwp.spec b/src/java.se/share/data/jdwp/jdwp.spec index f8973fb1406d..1d4b73cf8aa6 100644 --- a/src/java.se/share/data/jdwp/jdwp.spec +++ b/src/java.se/share/data/jdwp/jdwp.spec @@ -2141,9 +2141,12 @@ JDWP "Java(tm) Debug Wire Protocol" "language method. Forcing return on a thread with only one " "frame on the stack causes the thread to exit when resumed. " "

    " - "When preview features are enabled in the target VM, " - "the method can not be the constructor of a " - "value classPREVIEW." + "When preview features are enabled in the target VM, the specified " + "thread's current frame can not be a constructor of a class with " + "" + "strictly-initializedPREVIEW instance fields in the class " + "or any of its superclasses, or the class initializer of a class with " + "strictly-initialized static fields." "

    " "For void methods, the value must be a void value. " "For methods that return primitive values, the value's type must " @@ -2165,8 +2168,12 @@ JDWP "Java(tm) Debug Wire Protocol" (Error INVALID_OBJECT "Thread or value is not a known ID.") (Error THREAD_NOT_SUSPENDED) (Error OPAQUE_FRAME "Unable to force the current frame to return " - "(e.g. the current frame is executing a native method or " - "the current frame is the constructor for a value class).") + "(e.g. the current frame is executing a native method or, " + "if preview features are enabled in the target VM, " + "either the current frame is a constructor of a class " + "with strictly-initialized instance fields in its class " + "hierarchy or the current frame is the class initializer " + "of a class with strictly-initialized static fields).") (Error NO_MORE_FRAMES) (Error NOT_IMPLEMENTED) (Error TYPE_MISMATCH "Value is not an appropriate type for the " diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java index e546d019f5f8..3a84d5068638 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java @@ -136,14 +136,16 @@ protected Lint(Lint other) { // Process command line options on demand to allow use of root Lint early during startup private void initializeRootIfNeeded() { if (values == null) { - values = options.getLintCategoriesOf(Option.XLINT, this::getDefaults); + values = options.getLintCategoriesOf(Option.XLINT, + this::getDefaultsXLintAbsent, + this::getDefaultsXLintPresent); suppressedValues = LintCategory.newEmptySet(); } } // Obtain the set of on-by-default categories. Note that for a few categories, // whether the category is on-by-default depends on other compiler options. - private EnumSet getDefaults() { + private EnumSet getDefaultsXLintAbsent() { EnumSet defaults = LintCategory.newEmptySet(); Source source = Source.instance(context); Stream.of(LintCategory.values()) @@ -158,6 +160,14 @@ private EnumSet getDefaults() { return defaults; } + private EnumSet getDefaultsXLintPresent() { + EnumSet defaults = EnumSet.allOf(LintCategory.class); + if (options.isSet(Option.PREVIEW)) { + defaults.remove(LintCategory.PREVIEW); + } + return defaults; + } + @Override public String toString() { initializeRootIfNeeded(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java index a6d8d88e972a..5173f37bcf9c 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java @@ -2552,7 +2552,7 @@ public IntersectionClassType makeIntersectionType(List bounds, boolean all syms.noSymbol); IntersectionClassType intersectionType = new IntersectionClassType(bounds, bc, allInterfaces); bc.type = intersectionType; - bc.erasure_field = (bounds.head.hasTag(TYPEVAR)) || bounds.head.hasTag(ARRAY) ? + bc.erasure_field = (bounds.head.hasTag(TYPEVAR)) ? syms.objectType : // error condition, recover erasure(firstExplicitBound); bc.members_field = WriteableScope.create(bc); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 5a32378a9311..52444d611d17 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -814,7 +814,16 @@ void attribTypeVariables(List typarams, Env env, b List bounds = List.of(attribType(tvar.bounds.head, env)); for (JCExpression bound : tvar.bounds.tail) bounds = bounds.prepend(attribType(bound, env)); - types.setBounds(a, bounds.reverse()); + bounds = bounds.reverse(); + if (bounds.head.hasTag(ARRAY)) { + /* A single bound that is an array type may structurally reference + * this same type variable, as in ``, setting the bound to + * Object as a recovery strategy + */ + types.setBounds(a, List.of(syms.objectType)); + } else { + types.setBounds(a, bounds); + } } else { // if no bounds are given, assume a single bound of // java.lang.Object. diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ExhaustivenessComputer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ExhaustivenessComputer.java index e275b6a7849f..0697a80a81a4 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ExhaustivenessComputer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ExhaustivenessComputer.java @@ -75,8 +75,10 @@ public class ExhaustivenessComputer { private final Types types; private final Check chk; private final Infer infer; + private final Resolve rs; private final Map, Boolean> isSubtypeCache = new LinkedHashMap<>(); private final long maxBaseChecks; + private Env env; private long baseChecks = NO_BASE_CHECKS_COUNTING; public static ExhaustivenessComputer instance(Context context) { @@ -93,6 +95,7 @@ protected ExhaustivenessComputer(Context context) { types = Types.instance(context); chk = Check.instance(context); infer = Infer.instance(context); + rs = Resolve.instance(context); Options options = Options.instance(context); String baseChecks = options.get("exhaustivityMaxBaseChecks"); long computedMaxBaseChecks = DEFAULT_MAX_BASE_CHECKS; @@ -108,7 +111,16 @@ protected ExhaustivenessComputer(Context context) { maxBaseChecks = computedMaxBaseChecks; } - public ExhaustivenessResult exhausts(JCExpression selector, List cases) { + public ExhaustivenessResult exhausts(Env env, JCExpression selector, List cases) { + this.env = env; + try { + return doExhausts(selector, cases); + } finally { + this.env = null; + } + } + + private ExhaustivenessResult doExhausts(JCExpression selector, List cases) { Set patternSet = new LinkedHashSet<>(); Map> enum2Constants = new LinkedHashMap<>(); Set booleanLiterals = new LinkedHashSet<>(Set.of(0, 1)); @@ -864,18 +876,139 @@ protected Set computeMissingPatternDescriptions(Type selecto try { baseChecks = 0; PatternDescription defaultPattern = new BindingPattern(selectorType); - return expandMissingPatternDescriptions(selectorType, - selectorType, - defaultPattern, - incompletePatterns, - Set.of(defaultPattern)); + Set missingPatterns = + expandMissingPatternDescriptions(selectorType, + selectorType, + defaultPattern, + incompletePatterns, + Set.of(defaultPattern)); + missingPatterns = generalizeInaccessibleTypes(selectorType, missingPatterns); + return missingPatterns; } catch (TooManyChecksException ex) { - return ex.missingPatterns != null ? ex.missingPatterns : Set.of(); + return ex.missingPatterns != null ? generalizeInaccessibleTypes(selectorType, ex.missingPatterns) + : Set.of(); } finally { baseChecks = NO_BASE_CHECKS_COUNTING; } } + private Set generalizeInaccessibleTypes(Type selectorType, + Set forPatterns) { + Set generalized = + forPatterns.stream() + .map(pd -> generalizeInaccessibleTypes(selectorType, pd)) + .collect(Collectors.toCollection(LinkedHashSet::new)); + + OUTER: for (Iterator it = generalized.iterator(); it.hasNext(); ) { + PatternDescription current = it.next(); + for (PatternDescription check : generalized) { + if (check != current && patternDominated(check, current)) { + it.remove(); + continue OUTER; + } + } + } + + return generalized; + } + + private PatternDescription generalizeInaccessibleTypes(Type targetType, + PatternDescription forPattern) { + switch (forPattern) { + case BindingPattern _, EnumConstantPattern _ -> { + Type generalized = generalizeInaccessibleTypes(targetType, forPattern.type()); + if (generalized != forPattern.type()) { + return new BindingPattern(generalized); + } else { + return forPattern; + } + } + case RecordPattern rp -> { + Type generalized = generalizeInaccessibleTypes(targetType, rp.type()); + if (generalized != rp.type()) { + return new BindingPattern(generalized); + } else { + PatternDescription[] newNested = new PatternDescription[rp.nested().length]; + boolean modified = false; + + for (int i = 0; i < rp.nested().length; i++) { + PatternDescription orig = rp.nested()[i]; + PatternDescription nue = generalizeInaccessibleTypes(rp.fullComponentTypes()[i], orig); + + newNested[i] = nue; + modified = modified || orig != nue; + } + + return modified ? new RecordPattern(rp.recordType(), rp.fullComponentTypes(), newNested) : rp; + } + } + } + } + + private Type generalizeInaccessibleTypes(Type targetType, + Type generalized) { + ListBuffer todo = new ListBuffer<>(); + + todo.add(generalized); + + while (todo.nonEmpty() && !isAccessible(todo.first().tsym)) { + Type current = todo.poll(); + + for (Type generalizedSuper : types.directSupertypes(current)) { + if (types.asSuper(generalizedSuper, targetType.tsym) != null) { + generalized = generalizedSuper; + todo.add(generalizedSuper); + } + } + } + + return todo.nonEmpty() ? todo.first() : generalized; + } + + private boolean isAccessible(Symbol candidate) { + while (candidate.kind == Kind.TYP) { + if (!rs.isAccessible(env, (TypeSymbol) candidate)) { + return false; + } + + candidate = candidate.owner; + } + + return true; + } + + private boolean patternDominated(PatternDescription existingPattern, PatternDescription currentPattern) { + Type existingPatternType = types.erasure(existingPattern.type()); + Type currentPatternType = types.erasure(currentPattern.type()); + if (!types.isUnconditionallyExactTypeBased(currentPatternType, existingPatternType)) { + return false; + } + if (currentPattern instanceof BindingPattern) { + return existingPattern instanceof BindingPattern; + } else if (currentPattern instanceof RecordPattern currentRecordPattern) { + if (existingPattern instanceof BindingPattern) { + return true; + } else if (existingPattern instanceof RecordPattern existingRecordPattern) { + PatternDescription[] existingNested = existingRecordPattern.nested(); + PatternDescription[] currentNested = currentRecordPattern.nested(); + if (existingNested.length != currentNested.length) { + return false; + } + for (int i = 0; i < existingNested.length; i++) { + if (!patternDominated(existingNested[i], currentNested[i])) { + return false; + } + } + return true; + } else { + Assert.error("Unknown pattern: " + existingPattern.getClass()); + } + } else { + Assert.error("Unknown pattern: " + currentPattern.getClass()); + } + return false; + } + private Set expandMissingPatternDescriptions(Type selectorType, Type targetType, PatternDescription toExpand, @@ -902,7 +1035,8 @@ private Set doExpandMissingPatternDescriptions(Type selector if (bp.type.tsym.isSealed()) { //try to replace binding patterns for sealed types with all their immediate permitted applicable types: Set applicableDirectPermittedPatterns = - directPermittedSubTypes(bp.type) + leafPermittedSubTypes(bp.type.tsym, isApplicableSubtypePredicate(targetType)) + .stream() .map(csym -> new BindingPattern(types.erasure(csym.type))) .collect(Collectors.toCollection(LinkedHashSet::new)); @@ -911,16 +1045,18 @@ private Set doExpandMissingPatternDescriptions(Type selector removeUnnecessaryPatterns(selectorType, bp, basePatterns, inMissingPatterns, applicableDirectPermittedPatterns); if (!reduced && !hasMatchingRecordPattern(basePatterns, inMissingPatterns, toExpand)) { - //if all immediate permitted subtypes are needed + //if all permitted subtypes are needed //give up, and simply use the current pattern: return inMissingPatterns; } + Set simplifiedPatterns = + simplifyPatterns(selectorType, targetType, bp, basePatterns, inMissingPatterns, applicableDirectPermittedPatterns); Set currentMissingPatterns = - replace(inMissingPatterns, toExpand, applicableDirectPermittedPatterns); + replace(inMissingPatterns, toExpand, simplifiedPatterns); //try to recursively expand on each viable pattern: - for (PatternDescription viable : applicableDirectPermittedPatterns) { + for (PatternDescription viable : simplifiedPatterns) { currentMissingPatterns = expandMissingPatternDescriptions(selectorType, targetType, viable, basePatterns, currentMissingPatterns); @@ -972,26 +1108,12 @@ private Set doExpandMissingPatternDescriptions(Type selector removeUnnecessaryPatterns(selectorType, bp, basePatterns, inMissingPatterns, combinatorialPatterns); - CoverageResult coverageResult = computeCoverage(targetType, combinatorialPatterns, PatternEquivalence.LOOSE); - - if (!coverageResult.covered()) { - //use the partially merged/combined patterns: - combinatorialPatterns = coverageResult.incompletePatterns(); - } - - //combine sealed subtypes into the supertype, if all is covered. - //but preserve more specific record types in positions where there are record patterns in the original patterns - //this is particularly important for the case where the sealed supertype only has one permitted type, the record - //the base type could be used instead of the record otherwise, which would produce less specific missing pattern: - Set sortedCandidates = - partialSortPattern(combinatorialPatterns, basePatterns, replace(inMissingPatterns, toExpand, combinatorialPatterns)); - - removeUnnecessaryPatterns(selectorType, bp, basePatterns, inMissingPatterns, sortedCandidates); - + Set simplifiedPatterns = + simplifyPatterns(selectorType, targetType, bp, basePatterns, inMissingPatterns, combinatorialPatterns); Set currentMissingPatterns = - replace(inMissingPatterns, toExpand, sortedCandidates); + replace(inMissingPatterns, toExpand, simplifiedPatterns); - for (PatternDescription addedPattern : sortedCandidates) { + for (PatternDescription addedPattern : simplifiedPatterns) { if (addedPattern instanceof RecordPattern addedRP) { for (int c = 0; c < addedRP.nested.length; c++) { currentMissingPatterns = expandMissingPatternDescriptions(selectorType, @@ -1053,6 +1175,34 @@ private Collection replace(PatternDescription in, } } + /* Simplifies patterns, e.g. when the input patterns include all permitted subtypes + * of a type, the supertype will be used. + */ + private Set simplifyPatterns(Type selectorType, + Type targetType, + PatternDescription toExpand, + Set basePatterns, + Set inMissingPatterns, + Set toReduce) { + CoverageResult coverageResult = computeCoverage(targetType, toReduce, PatternEquivalence.LOOSE); + + if (!coverageResult.covered()) { + //use the partially merged/combined patterns: + toReduce = coverageResult.incompletePatterns(); + } + + //combine sealed subtypes into the supertype, if all is covered. + //but preserve more specific record types in positions where there are record patterns in the original patterns + //this is particularly important for the case where the sealed supertype only has one permitted type, the record + //the base type could be used instead of the record otherwise, which would produce less specific missing pattern: + Set sortedCandidates = + partialSortPattern(toReduce, basePatterns, replace(inMissingPatterns, toExpand, toReduce)); + + removeUnnecessaryPatterns(selectorType, toExpand, basePatterns, inMissingPatterns, sortedCandidates); + + return sortedCandidates; + } + /* Out of "candidates" remove patterns that are not necessary to achieve exhaustiveness. * Note that iteration order of "candidates" is important - if the set contains * two pattern, out of which either, but not both, is needed to achieve exhaustiveness, @@ -1125,18 +1275,28 @@ private boolean shouldAppearBefore(PatternDescription pd1, } else if (pd1 instanceof BindingPattern bp1 && pd2 instanceof BindingPattern bp2) { Type t1 = bp1.type(); Type t2 = bp2.type(); - boolean t1IsImportantRecord = - (t1.tsym.flags_field & RECORD) != 0 && - hasMatchingRecordPattern(basePatterns, missingPatterns, bp1); - boolean t2IsImportantRecord = - (t2.tsym.flags_field & RECORD) != 0 && - hasMatchingRecordPattern(basePatterns, missingPatterns, bp2); - if (t1IsImportantRecord && !t2IsImportantRecord) { + + //put types with a single permitted subtype (when the other type is the permitted subtype) + //to the front, so that are preferrably removed: + List t1PermittedSubClasses = t1.tsym instanceof ClassSymbol c1 ? c1.getPermittedSubclasses() + : List.nil(); + if (t1PermittedSubClasses.size() == 1 && t1PermittedSubClasses.head.tsym == t2.tsym) { + return true; + } + List t2PermittedSubClasses = t2.tsym instanceof ClassSymbol c2 ? c2.getPermittedSubclasses() + : List.nil(); + if (t2PermittedSubClasses.size() == 1 && t2PermittedSubClasses.head.tsym == t1.tsym) { return false; } - if (!t1IsImportantRecord && t2IsImportantRecord) { + + //put inaccessible types in front, so they are preferrably removed: + if (isAccessible(t1.tsym) && !isAccessible(t2.tsym)) { + return false; + } + if (!isAccessible(t1.tsym) && isAccessible(t2.tsym)) { return true; } + if (!types.isSameType(t1, t2) && types.isSubtype(t1, t2)) { return true; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java index 4b11a3ae56d5..7eb7dd04a2b8 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java @@ -721,7 +721,7 @@ public void visitSwitch(JCSwitch tree) { TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases); if (exhaustiveSwitch) { if (!tree.isExhaustive) { - ExhaustivenessResult exhaustivenessResult = exhaustiveness.exhausts(tree.selector, tree.cases); + ExhaustivenessResult exhaustivenessResult = exhaustiveness.exhausts(attrEnv, tree.selector, tree.cases); tree.isExhaustive = exhaustivenessResult.exhaustive(); @@ -729,7 +729,7 @@ public void visitSwitch(JCSwitch tree) { if (exhaustivenessResult.notExhaustiveDetails().isEmpty()) { log.error(tree, Errors.NotExhaustiveStatement); } else { - logNotExhaustiveError(tree.pos(), exhaustivenessResult, Errors.NotExhaustiveStatementDetails); + logNotExhaustiveError(tree.pos(), exhaustivenessResult, "not.exhaustive.statement.details"); } } } @@ -768,7 +768,7 @@ public void visitSwitchExpression(JCSwitchExpression tree) { TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases)) { tree.isExhaustive = true; } else { - ExhaustivenessResult exhaustivenessResult = exhaustiveness.exhausts(tree.selector, tree.cases); + ExhaustivenessResult exhaustivenessResult = exhaustiveness.exhausts(attrEnv, tree.selector, tree.cases); tree.isExhaustive = exhaustivenessResult.exhaustive(); @@ -776,7 +776,7 @@ public void visitSwitchExpression(JCSwitchExpression tree) { if (exhaustivenessResult.notExhaustiveDetails().isEmpty()) { log.error(tree, Errors.NotExhaustive); } else { - logNotExhaustiveError(tree.pos(), exhaustivenessResult, Errors.NotExhaustiveDetails); + logNotExhaustiveError(tree.pos(), exhaustivenessResult, "not.exhaustive.details"); } } } @@ -787,7 +787,7 @@ public void visitSwitchExpression(JCSwitchExpression tree) { private void logNotExhaustiveError(DiagnosticPosition pos, ExhaustivenessResult exhaustivenessResult, - Error errorKey) { + String errorKey) { List details = exhaustivenessResult.notExhaustiveDetails() .stream() @@ -795,23 +795,26 @@ private void logNotExhaustiveError(DiagnosticPosition pos, .sorted((d1, d2) -> d1.toString() .compareTo(d2.toString())) .collect(List.collector()); - JCDiagnostic main = diags.error(null, log.currentSource(), pos, errorKey); - JCDiagnostic d = new JCDiagnostic.MultilineDiagnostic(main, details); + JCDiagnostic missingCases = diags.fragment(details.size() == 1 ? Fragments.MissingCase + : Fragments.MissingCases); + JCDiagnostic augmentedMissingCases = new JCDiagnostic.MultilineDiagnostic(missingCases, details); + JCDiagnostic d = diags.error(null, log.currentSource(), pos, errorKey, augmentedMissingCases); log.report(d); } private JCDiagnostic patternToDiagnostic(PatternDescription desc) { - Type patternType = types.erasure(desc.type()); + Type erasedPatternType = types.erasure(desc.type()); return diags.fragment(switch (desc) { case BindingPattern _ -> - Fragments.BindingPattern(patternType); + Fragments.BindingPattern(desc.type().hasTag(TypeTag.TYPEVAR) ? desc.type() + : erasedPatternType); case RecordPattern rp -> - Fragments.RecordPattern(patternType, + Fragments.RecordPattern(erasedPatternType, Arrays.stream(rp.nested()) .map(this::patternToDiagnostic) .toList()); case EnumConstantPattern ep -> - Fragments.EnumConstantPattern(patternType, + Fragments.EnumConstantPattern(erasedPatternType, ep.enumConstant()); }); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java index a361ce318f20..e560a9db9f29 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -4009,7 +4009,9 @@ private boolean isQualifiedEarlyRefAllowed(DiagnosticPosition pos, // early this can only qualify instance field accesses return false; } - return isSimpleEarlyFieldRefAllowed(pos, env, context, field, writeOnlyTarget); + // early qualified access only allowed for writes + return writeOnlyTarget && + isSimpleEarlyFieldRefAllowed(pos, env, context, field, writeOnlyTarget); } /** Implements early access checks for unqualified field references (6.5.6.1) */ diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index b48bfd0394ce..c395671d4d06 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -791,7 +791,12 @@ Type sigToTypeParam() { bounds = bounds.prepend(sigToType()); } if (!sigEnterPhase) { - types.setBounds(tvar, bounds.reverse(), allInterfaces); + bounds = bounds.reverse(); + if (bounds.head.hasTag(ARRAY)) { + throw badClassFile("illegal.tvar.bound", bounds.head); + } else { + types.setBounds(tvar, bounds, allInterfaces); + } } return tvar; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java index 56dfd395aed0..df4a1a268f47 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -441,7 +441,7 @@ public JavaCompiler(Context context) { devVerbose = options.isSet("dev"); processPcks = options.isSet("process.packages"); werrorNonLint = options.isSet(WERROR) || options.isSet(WERROR_CUSTOM, Option.LINT_CUSTOM_ALL); - werrorLint = options.getLintCategoriesOf(WERROR, LintCategory::newEmptySet); + werrorLint = options.getLintCategoriesOf(WERROR, LintCategory::newEmptySet, () -> EnumSet.allOf(LintCategory.class)); verboseCompilePolicy = options.isSet("verboseCompilePolicy"); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties index c3f186bc22f6..f676b7ae44d6 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -1483,13 +1483,15 @@ compiler.err.not.exhaustive=\ compiler.err.not.exhaustive.statement=\ the switch statement does not cover all possible input values +# 0: diagnostic compiler.err.not.exhaustive.details=\ the switch expression does not cover all possible input values\n\ - missing patterns: + {0} +# 0: diagnostic compiler.err.not.exhaustive.statement.details=\ the switch statement does not cover all possible input values\n\ - missing patterns: + {0} # 0: type compiler.misc.binding.pattern=\ @@ -1503,6 +1505,12 @@ compiler.misc.record.pattern=\ compiler.misc.enum.constant.pattern=\ {0}.{1} +compiler.misc.missing.case=\ + missing case: + +compiler.misc.missing.cases=\ + missing cases: + compiler.err.initializer.must.be.able.to.complete.normally=\ initializer must be able to complete normally @@ -2850,6 +2858,9 @@ compiler.misc.wrong.version=\ compiler.misc.illegal.flag.combo=\ class file contains illegal flag combination {0} for {1} {2} +compiler.misc.illegal.tvar.bound=\ + illegal type variable bound: {0} + ##### # 0: type, 1: type or symbol diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Options.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Options.java index 030e5b21758e..620583f8d08e 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Options.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Options.java @@ -266,9 +266,10 @@ public boolean isExplicitlyDisabled(Option option, LintCategory lc) { *

    * The set of categories is calculated as follows. First, an initial set is created: *

      - *
    • If {@code -Flag} or {@code -Flag:all} appears, the initial set contains all categories; otherwise, + *
    • If {@code -Flag:all} appears, the initial set contains all categories; otherwise, + *
    • If {@code -Flag} appears, the {@code enabledByDefaultWhenLintPresent} parameter is invoked to construct an initial set; otherwise, *
    • If {@code -Flag:none} appears, the initial set is empty; otherwise, - *
    • The {@code defaults} parameter is invoked to construct an initial set. + *
    • The {@code enabledByDefaultWhenLintAbsent} parameter is invoked to construct an initial set. *
    * Next, for each lint category key {@code key}: *
      @@ -278,21 +279,25 @@ public boolean isExplicitlyDisabled(Option option, LintCategory lc) { * Unrecognized {@code key}s are ignored. * * @param option the plain (non-custom) version of the option (e.g., {@link Option#XLINT}) - * @param defaults populates the default set, or null for an empty default set + * @param enabledByDefaultWhenLintAbsent the default categories enabled when the option is not present + * @param enabledByDefaultWhenLintPresent the default categories enabled when the option is present without details * @return the specified set of categories * @throws IllegalArgumentException if there is no lint custom variant of {@code option} */ - public EnumSet getLintCategoriesOf(Option option, Supplier> defaults) { - + public EnumSet getLintCategoriesOf(Option option, + Supplier> enabledByDefaultWhenLintAbsent, + Supplier> enabledByDefaultWhenLintPresent) { // Create the initial set EnumSet categories; Option customOption = option.getLintCustom(); - if (isSet(option) || isSet(customOption, Option.LINT_CUSTOM_ALL)) { + if (isSet(customOption, Option.LINT_CUSTOM_ALL)) { categories = EnumSet.allOf(LintCategory.class); + } else if (isSet(option)) { + categories = enabledByDefaultWhenLintPresent.get(); } else if (isSet(customOption, Option.LINT_CUSTOM_NONE)) { categories = EnumSet.noneOf(LintCategory.class); } else { - categories = defaults.get(); + categories = enabledByDefaultWhenLintAbsent.get(); } // Apply specific overrides diff --git a/src/jdk.compiler/share/man/javac.md b/src/jdk.compiler/share/man/javac.md index 47d0d7f04eee..bcfde3695c6b 100644 --- a/src/jdk.compiler/share/man/javac.md +++ b/src/jdk.compiler/share/man/javac.md @@ -566,8 +566,9 @@ file system locations may be directories, JAR files or JMOD files. section of the `javadoc` command documentation. `-Xlint` -: Enables recommended lint warning categories. In this release, all available - lint warning categories are recommended. +: Enables recommended lint warning categories. All lint warning categories are + recommended by default. If preview language features are enabled + (`--enable-preview`), all lint warning categories except `preview` are recommended. `-Xlint:`\[`-`\]*key*(`,`\[`-`\]*key*)\* : Enables and/or disables lint warning categories using the one or more of the keys described diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp index f23ffce9a071..751cb8872c7c 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.cpp @@ -131,14 +131,14 @@ bool DwarfParser::process_cie(unsigned char *start_of_entry, uint32_t id) { init_state(_state); _state.return_address_reg = initial_ra; - parse_dwarf_instructions(0L, static_cast(-1L), end); + bool result = parse_dwarf_instructions(0L, static_cast(-1L), end); _initial_state = _state; _buf = orig_pos; - return true; + return result; } -void DwarfParser::parse_dwarf_instructions(uintptr_t begin, uintptr_t pc, const unsigned char *end) { +bool DwarfParser::parse_dwarf_instructions(uintptr_t begin, uintptr_t pc, const unsigned char *end) { uintptr_t operand1; _current_pc = begin; std::stack remember_state; @@ -152,7 +152,7 @@ void DwarfParser::parse_dwarf_instructions(uintptr_t begin, uintptr_t pc, const switch (op) { case 0x0: // DW_CFA_nop - return; + break; case 0x01: // DW_CFA_set_loc operand1 = get_decoded_value(_fde_ptr_encoding); if (_current_pc != 0L) { @@ -200,6 +200,17 @@ void DwarfParser::parse_dwarf_instructions(uintptr_t begin, uintptr_t pc, const } break; } + case 0x05: { // DW_CFA_offset_extended + enum DWARF_Register reg = static_cast(read_leb(false)); + uintptr_t operand2 = read_leb(false); + _state.offset_from_cfa[reg] = operand2 * _data_factor; + break; + } + case 0x06: { // DW_CFA_restore_extended + enum DWARF_Register reg = static_cast(read_leb(false)); + _state.offset_from_cfa[reg] = _initial_state.offset_from_cfa[reg]; + break; + } case 0x07: { // DW_CFA_undefined enum DWARF_Register reg = static_cast(read_leb(false)); _state.offset_from_cfa[reg] = INT_MAX; @@ -215,12 +226,15 @@ void DwarfParser::parse_dwarf_instructions(uintptr_t begin, uintptr_t pc, const case 0x0b: // DW_CFA_restore_state if (remember_state.empty()) { print_debug("DWARF Error: DW_CFA_restore_state with empty stack.\n"); - return; + return false; } _state = remember_state.top(); remember_state.pop(); restore_arch_specific_state(); break; + case 0x0f: // DW_CFA_def_cfa_expression + print_debug("DWARF: DW_CFA_def_cfa_expression is not yet supported.\n"); + return false; case 0xc0: {// DW_CFA_restore enum DWARF_Register reg = static_cast(opa); _state.offset_from_cfa[reg] = _initial_state.offset_from_cfa[reg]; @@ -228,11 +242,13 @@ void DwarfParser::parse_dwarf_instructions(uintptr_t begin, uintptr_t pc, const } default: if (!process_arch_specific_dwarf_instructions(op)) { - print_debug("DWARF: Unknown opcode: 0x%x\n", op); - return; + print_error("DWARF: Unknown opcode: 0x%x\n", op); + return false; } } } + + return true; } /* from dwarf.c in binutils */ @@ -347,8 +363,7 @@ bool DwarfParser::process_dwarf(const uintptr_t pc) { } // Process FDE - parse_dwarf_instructions(pc_begin, pc, next_entry); - return true; + return parse_dwarf_instructions(pc_begin, pc, next_entry); } } diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp index 110cd91ed4c4..8d5325b188e8 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf.hpp @@ -75,7 +75,7 @@ class DwarfParser { void init_state(struct DwarfState& st); uint64_t get_entry_length(); bool process_cie(unsigned char *start_of_entry, uint32_t id); - void parse_dwarf_instructions(uintptr_t begin, uintptr_t pc, const unsigned char *end); + bool parse_dwarf_instructions(uintptr_t begin, uintptr_t pc, const unsigned char *end); uint32_t get_decoded_value(unsigned char enc); unsigned int get_pc_range(); diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf_regs_aarch64.h b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf_regs_aarch64.h index 5a95e9405e16..36132d446623 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf_regs_aarch64.h +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/dwarf_regs_aarch64.h @@ -66,7 +66,40 @@ DWARF_REG(FP, 29) \ DWARF_REG(LR, 30) \ DWARF_REG(SP, 31) \ - DWARF_REG(PC, 32) + DWARF_REG(PC, 32) \ + \ + DWARF_REG(V0, 64) \ + DWARF_REG(V1, 65) \ + DWARF_REG(V2, 66) \ + DWARF_REG(V3, 67) \ + DWARF_REG(V4, 68) \ + DWARF_REG(V5, 69) \ + DWARF_REG(V6, 70) \ + DWARF_REG(V7, 71) \ + DWARF_REG(V8, 72) \ + DWARF_REG(V9, 73) \ + DWARF_REG(V10, 74) \ + DWARF_REG(V11, 75) \ + DWARF_REG(V12, 76) \ + DWARF_REG(V13, 77) \ + DWARF_REG(V14, 78) \ + DWARF_REG(V15, 79) \ + DWARF_REG(V16, 80) \ + DWARF_REG(V17, 81) \ + DWARF_REG(V18, 82) \ + DWARF_REG(V19, 83) \ + DWARF_REG(V20, 84) \ + DWARF_REG(V21, 85) \ + DWARF_REG(V22, 86) \ + DWARF_REG(V23, 87) \ + DWARF_REG(V24, 88) \ + DWARF_REG(V25, 89) \ + DWARF_REG(V26, 90) \ + DWARF_REG(V27, 91) \ + DWARF_REG(V28, 92) \ + DWARF_REG(V29, 93) \ + DWARF_REG(V30, 94) \ + DWARF_REG(V31, 95) // RA_SIGN_STATE might be needed in future to handle PAC. #define DWARF_PSEUDO_REGLIST diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/aarch64/AARCH64ThreadContext.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/aarch64/AARCH64ThreadContext.java index 6cf8f438b4c6..b81c5cac70a7 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/aarch64/AARCH64ThreadContext.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/aarch64/AARCH64ThreadContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, Red Hat Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -52,6 +52,9 @@ public abstract class AARCH64ThreadContext implements ThreadContext { // __u8 __reserved[4096] __attribute__((__aligned__(16))); // }; + // These constants are referenced by "DWARF_REG" macro in DwarfParser.cpp + // to map DWARF register numbers to the corresponding indices. + // // NOTE: the indices for the various registers must be maintained as // listed across various operating systems. However, only a small // subset of the registers' values are guaranteed to be present (and @@ -95,7 +98,40 @@ public abstract class AARCH64ThreadContext implements ThreadContext { public static final int PC = 32; public static final int PSTATE = 33; - public static final int NPRGREG = 34; + public static final int V0 = 34; + public static final int V1 = 35; + public static final int V2 = 36; + public static final int V3 = 37; + public static final int V4 = 38; + public static final int V5 = 39; + public static final int V6 = 40; + public static final int V7 = 41; + public static final int V8 = 42; + public static final int V9 = 43; + public static final int V10 = 44; + public static final int V11 = 45; + public static final int V12 = 46; + public static final int V13 = 47; + public static final int V14 = 48; + public static final int V15 = 49; + public static final int V16 = 50; + public static final int V17 = 51; + public static final int V18 = 52; + public static final int V19 = 53; + public static final int V20 = 54; + public static final int V21 = 55; + public static final int V22 = 56; + public static final int V23 = 57; + public static final int V24 = 58; + public static final int V25 = 59; + public static final int V26 = 60; + public static final int V27 = 61; + public static final int V28 = 62; + public static final int V29 = 63; + public static final int V30 = 64; + public static final int V31 = 65; + + public static final int NPRGREG = 66; private long[] data; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/DwarfCFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/DwarfCFrame.java index 886215e051e1..f27f187b5dc4 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/DwarfCFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/DwarfCFrame.java @@ -26,6 +26,7 @@ package sun.jvm.hotspot.debugger.linux; import sun.jvm.hotspot.debugger.Address; +import sun.jvm.hotspot.debugger.DebuggerException; import sun.jvm.hotspot.debugger.ThreadProxy; import sun.jvm.hotspot.debugger.UnalignedAddressException; import sun.jvm.hotspot.debugger.UnmappedAddressException; @@ -57,7 +58,19 @@ protected static DwarfParser createDwarfParser(LinuxDebugger linuxDbg, Address p if (libptr != null) { DwarfParser dwarf = linuxDbg.getCPU().equals("aarch64") ? new AARCH64DwarfParser(libptr) : new DwarfParser(libptr); - dwarf.processDwarf(pc); + try { + dwarf.processDwarf(pc); + } catch (DebuggerException e) { + // DebuggerException might be thrown from unwinding signal trampoline + // (e.g. __restore_rt on AMD64) because it might have DW_CFA_def_cfa_expression + // DWARF instruction. + // However SA can ignore the case safely because it does not rely on DWARF, + // would restore register values from the stack directly. + // Thus DebuggerException would be rethrown if the pc is not in signal trampoline. + if (!linuxDbg.isSignalTrampoline(pc)) { + throw e; + } + } return dwarf; } return null; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FileMapInfo.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FileMapInfo.java index a905a51f2d90..c3630b484715 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FileMapInfo.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FileMapInfo.java @@ -138,7 +138,7 @@ private static void populateMetadataTypeArray(TypeDataBase db) { metadataTypeArray[10] = db.lookupType("ObjArrayKlass"); metadataTypeArray[11] = db.lookupType("RefArrayKlass"); metadataTypeArray[12] = db.lookupType("FlatArrayKlass"); - metadataTypeArray[13] = db.lookupType("InlineKlass"); + metadataTypeArray[13] = db.lookupType("ValueKlass"); } public FileMapHeader getHeader() { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java index a14731ae89e3..128cb58649c5 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java @@ -211,9 +211,9 @@ public int getFieldIndex() { private static boolean fieldIsGeneric(int flags) { return ((flags >> InstanceKlass.FIELD_FLAG_IS_GENERIC ) & 1 ) != 0; } private static boolean fieldIsStable(int flags) { return ((flags >> InstanceKlass.FIELD_FLAG_IS_STABLE ) & 1 ) != 0; } private static boolean fieldIsContended(int flags) { return ((flags >> InstanceKlass.FIELD_FLAG_IS_CONTENDED ) & 1 ) != 0; } - private static boolean fieldIsNullFreeInlineType(int flags) { return ((flags >> InstanceKlass.FIELD_FLAG_IS_NULL_FREE_INLINE) & 1 ) != 0; } - private static boolean fieldIsFlat(int flags) { return ((flags >> InstanceKlass.FIELD_FLAG_IS_FLAT) & 1 ) != 0; } - private static boolean fieldHasNullMarker(int flags) { return ((flags >> InstanceKlass.FIELD_FLAG_IS_NULL_MARKER) & 1 ) != 0; } + private static boolean fieldIsNullFreeValueType(int flags) { return ((flags >> InstanceKlass.FIELD_FLAG_IS_NULL_FREE_VALUE) & 1 ) != 0; } + private static boolean fieldIsFlat(int flags) { return ((flags >> InstanceKlass.FIELD_FLAG_IS_FLAT) & 1 ) != 0; } + private static boolean fieldHasNullMarker(int flags) { return ((flags >> InstanceKlass.FIELD_FLAG_IS_NULL_MARKER) & 1 ) != 0; } public boolean isInitialized() { return fieldIsInitialized(values.fieldFlags); } public boolean isInjected() { return fieldIsInjected(values.fieldFlags); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java index f5e7f8c84bbc..96d177bc190e 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java @@ -53,7 +53,7 @@ public void update(Observable o, Object data) { static int FIELD_FLAG_IS_GENERIC; static int FIELD_FLAG_IS_STABLE; static int FIELD_FLAG_IS_CONTENDED; - static int FIELD_FLAG_IS_NULL_FREE_INLINE; + static int FIELD_FLAG_IS_NULL_FREE_VALUE; static int FIELD_FLAG_IS_FLAT; static int FIELD_FLAG_IS_NULL_MARKER; @@ -76,7 +76,7 @@ public void update(Observable o, Object data) { public boolean isSuper() { return getAccessFlagsObj().isSuper(); } public boolean isSynthetic() { return getAccessFlagsObj().isSynthetic(); } - public boolean supportsInlineTypes() { + public boolean supportsValueTypes() { return majorVersion() >= VALUE_TYPES_MAJOR_VERSION && minorVersion() == JAVA_PREVIEW_MINOR_VERSION; } @@ -113,7 +113,7 @@ private static synchronized void initialize(TypeDataBase db) throws WrongTypeExc FIELD_FLAG_IS_GENERIC = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_generic"); FIELD_FLAG_IS_STABLE = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_stable"); FIELD_FLAG_IS_CONTENDED = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_contended"); - FIELD_FLAG_IS_NULL_FREE_INLINE = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_null_free_inline_type"); + FIELD_FLAG_IS_NULL_FREE_VALUE = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_null_free_value_type"); FIELD_FLAG_IS_FLAT = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_flat"); FIELD_FLAG_IS_NULL_MARKER = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_null_marker"); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java index 912a6ec16f96..d4f59185b3ef 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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,6 +34,84 @@ import sun.jvm.hotspot.utilities.Observer; public class Klass extends Metadata implements ClassConstants { + + public static class KlassKind { + + public static KlassKind InstanceKlassKind; + public static KlassKind ValueKlassKind; + public static KlassKind InstanceRefKlassKind; + public static KlassKind InstanceMirrorKlassKind; + public static KlassKind InstanceClassLoaderKlassKind; + public static KlassKind InstanceStackChunkKlassKind; + public static KlassKind TypeArrayKlassKind; + public static KlassKind ObjArrayKlassKind; + public static KlassKind RefArrayKlassKind; + public static KlassKind FlatArrayKlassKind; + public static KlassKind UnknownKlassKind; + + private final int value; + + static { + VM.registerVMInitializedObserver((_, _) -> initialize(VM.getVM().getTypeDataBase())); + } + + private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { + Type type = db.lookupType("Klass::KlassKind"); + + InstanceKlassKind = new KlassKind(db.lookupIntConstant("Klass::KlassKind::InstanceKlassKind").intValue()); + ValueKlassKind = new KlassKind(db.lookupIntConstant("Klass::KlassKind::ValueKlassKind").intValue()); + InstanceRefKlassKind = new KlassKind(db.lookupIntConstant("Klass::KlassKind::InstanceRefKlassKind").intValue()); + InstanceMirrorKlassKind = new KlassKind(db.lookupIntConstant("Klass::KlassKind::InstanceMirrorKlassKind").intValue()); + InstanceClassLoaderKlassKind = new KlassKind(db.lookupIntConstant("Klass::KlassKind::InstanceClassLoaderKlassKind").intValue()); + InstanceStackChunkKlassKind = new KlassKind(db.lookupIntConstant("Klass::KlassKind::InstanceStackChunkKlassKind").intValue()); + TypeArrayKlassKind = new KlassKind(db.lookupIntConstant("Klass::KlassKind::TypeArrayKlassKind").intValue()); + ObjArrayKlassKind = new KlassKind(db.lookupIntConstant("Klass::KlassKind::ObjArrayKlassKind").intValue()); + RefArrayKlassKind = new KlassKind(db.lookupIntConstant("Klass::KlassKind::RefArrayKlassKind").intValue()); + FlatArrayKlassKind = new KlassKind(db.lookupIntConstant("Klass::KlassKind::FlatArrayKlassKind").intValue()); + UnknownKlassKind = new KlassKind(db.lookupIntConstant("Klass::KlassKind::UnknownKlassKind").intValue()); + } + + private KlassKind(int value) { + this.value = value; + } + + public static KlassKind valueOf(int rawValue) { + if (rawValue == InstanceKlassKind.value) { + return InstanceKlassKind; + } else if (rawValue == ValueKlassKind.value) { + return ValueKlassKind; + } else if (rawValue == InstanceRefKlassKind.value) { + return InstanceRefKlassKind; + } else if (rawValue == InstanceMirrorKlassKind.value) { + return InstanceMirrorKlassKind; + } else if (rawValue == InstanceClassLoaderKlassKind.value) { + return InstanceClassLoaderKlassKind; + } else if (rawValue == InstanceStackChunkKlassKind.value) { + return InstanceStackChunkKlassKind; + } else if (rawValue == TypeArrayKlassKind.value) { + return TypeArrayKlassKind; + } else if (rawValue == ObjArrayKlassKind.value) { + return ObjArrayKlassKind; + } else if (rawValue == RefArrayKlassKind.value) { + return RefArrayKlassKind; + } else if (rawValue == FlatArrayKlassKind.value) { + return FlatArrayKlassKind; + } else if (rawValue == UnknownKlassKind.value) { + return UnknownKlassKind; + } else { + throw new IllegalArgumentException("Out of range"); + } + } + + @Override + public boolean equals(Object obj) { + if ((obj != null) && (obj instanceof KlassKind k)) { + return k.value == this.value; + } + return false; + } + } + static { VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { @@ -54,6 +132,7 @@ public void update(Observable o, Object data) { private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { Type type = db.lookupType("Klass"); javaMirrorFieldOffset = type.getField("_java_mirror").getOffset(); + kindField = new CIntField(type.getCIntegerField("_kind"), 0); superField = new MetadataField(type.getAddressField("_super"), 0); layoutHelper = new IntField(type.getJIntField("_layout_helper"), 0); name = type.getAddressField("_name"); @@ -90,6 +169,7 @@ public int getClassStatus() { // Fields private static long javaMirrorFieldOffset; + private static CIntField kindField; private static MetadataField superField; private static IntField layoutHelper; private static AddressField name; @@ -110,6 +190,7 @@ public Instance getJavaMirror() { VMOopHandle vmOopHandle = VMObjectFactory.newObject(VMOopHandle.class, addr); return vmOopHandle.resolve(); } + public KlassKind getKind() { return KlassKind.valueOf((int)kindField.getValue(this)); } public Klass getSuper() { return (Klass) superField.getValue(this); } public Klass getJavaSuper() { return null; } public int getLayoutHelper() { return layoutHelper.getValue(this); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java index 3f217edc9835..a7b7698849a9 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java @@ -118,10 +118,6 @@ public long value() { return markField.getValue(addr); } - public Address valueAsAddress() { - return addr.getAddressAt(markField.getOffset()); - } - // lock accessors (note that these assume lock_shift == 0) public boolean isNonNeutral() { return (Bits.maskBitsLong(value(), lockMaskInPlace) != neutralValue); @@ -133,12 +129,6 @@ public boolean isMarked() { return (Bits.maskBitsLong(value(), lockMaskInPlace) == markedValue); } - // Special temporary state of the markWord while being inflated. - // Code that looks at mark outside a lock need to take this into account. - public boolean isBeingInflated() { - return (value() == 0); - } - // Should this header be preserved during GC? public boolean mustBePreserved() { return (isNonNeutral() || !hasNoHash()); @@ -152,7 +142,7 @@ public boolean isFastLocked() { return ((value() & lockMaskInPlace) == fastLockedValue); } public boolean hasMonitor() { - return ((value() & monitorValue) != 0); + return (value() & lockMaskInPlace) == monitorValue; } public ObjectMonitor monitor() { if (Assert.ASSERTS_ENABLED) { @@ -167,16 +157,6 @@ public ObjectMonitor monitor() { } return null; } - public boolean hasDisplacedMarkHelper() { - return ((value() & neutralValue) == 0); - } - public Mark displacedMarkHelper() { - if (Assert.ASSERTS_ENABLED) { - Assert.that(hasDisplacedMarkHelper(), "check"); - } - Address addr = valueAsAddress().andWithMask(~monitorValue); - return new Mark(addr.getAddressAt(0)); - } public int age() { return (int) Bits.maskBitsLong(value() >> ageShift, ageMask); } // hash operations @@ -195,18 +175,27 @@ public Klass getKlass() { // Debugging public void printOn(PrintStream tty) { - if (isNonNeutral()) { - tty.print("locked(0x" + - Long.toHexString(value()) + ")->"); - displacedMarkHelper().printOn(tty); + if (isMarked()) { + tty.print("marked(" + Long.toHexString(value()) + ")"); + return; + } + tty.print("mark("); + if (hasMonitor()) { + tty.print("has_monitor"); + } else if (isNeutral()) { + tty.print("is_lock_neutral"); } else { if (Assert.ASSERTS_ENABLED) { - Assert.that(isNeutral(), "just checking"); + Assert.that(isFastLocked(), "should be"); } - tty.print("mark("); - tty.print("hash " + Long.toHexString(hash()) + ","); - tty.print("age " + age() + ")"); + tty.print("is_fast_locked"); + } + if (hasNoHash()) { + tty.print(" no_hash"); + } else { + tty.print(" hash=" + Long.toHexString(hash())); } + tty.print(" age=" + age() + ")"); } public long getSize() { return (long)value(); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Metadata.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Metadata.java index 088b3cff49fd..c80d04781046 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Metadata.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Metadata.java @@ -64,7 +64,7 @@ private static synchronized void initialize(TypeDataBase db) throws WrongTypeExc metadataConstructor.addMapping("InstanceRefKlass", InstanceRefKlass.class); metadataConstructor.addMapping("InstanceClassLoaderKlass", InstanceClassLoaderKlass.class); metadataConstructor.addMapping("InstanceStackChunkKlass", InstanceStackChunkKlass.class); - metadataConstructor.addMapping("InlineKlass", InlineKlass.class); + metadataConstructor.addMapping("ValueKlass", ValueKlass.class); metadataConstructor.addMapping("TypeArrayKlass", TypeArrayKlass.class); metadataConstructor.addMapping("ObjArrayKlass", ObjArrayKlass.class); metadataConstructor.addMapping("RefArrayKlass", RefArrayKlass.class); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InlineKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ValueKlass.java similarity index 93% rename from src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InlineKlass.java rename to src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ValueKlass.java index 6015fd945003..bc05f0cf3988 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InlineKlass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ValueKlass.java @@ -36,7 +36,7 @@ // An InstanceKlass is the VM level representation of a Java class. -public class InlineKlass extends InstanceKlass { +public class ValueKlass extends InstanceKlass { static { VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { @@ -47,10 +47,10 @@ public void update(Observable o, Object data) { private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { // Just make sure it's there for now - Type type = db.lookupType("InlineKlass"); + Type type = db.lookupType("ValueKlass"); } - public InlineKlass(Address addr) { + public ValueKlass(Address addr) { super(addr); } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java index 1bdbf8ce8a21..547c3cd3efa5 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,9 +45,7 @@ private static synchronized void initialize(TypeDataBase db) throws WrongTypeExc heap = VM.getVM().getObjectHeap(); Type type = db.lookupType("ObjectMonitor"); - sun.jvm.hotspot.types.Field f = type.getField("_metadata"); - metadataFieldOffset = f.getOffset(); - f = type.getField("_object"); + sun.jvm.hotspot.types.Field f = type.getField("_object"); objectFieldOffset = f.getOffset(); f = type.getField("_owner"); ownerFieldOffset = f.getOffset(); @@ -64,13 +62,6 @@ public ObjectMonitor(Address addr) { super(addr); } - public Mark header() { - return new Mark(addr.addOffsetTo(metadataFieldOffset)); - } - - // FIXME - // void set_header(markWord hdr); - // FIXME: must implement and delegate to platform-dependent implementation // public boolean isBusy(); public boolean isEntered(sun.jvm.hotspot.runtime.Thread current) { @@ -110,14 +101,15 @@ public int contentions() { return (int)contentionsField.getValue(this); } - // The following four either aren't expressed as typed fields in + private static ObjectHeap heap; + + // The following three either aren't expressed as typed fields in // vmStructs.cpp because they aren't strongly typed in the VM, or // would confuse the SA's type system. - private static ObjectHeap heap; - private static long metadataFieldOffset; private static long objectFieldOffset; private static long ownerFieldOffset; private static long nextOMFieldOffset; + private static CIntField contentionsField; private static CIntField waitersField; private static CIntegerField recursionsField; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectSynchronizer.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectSynchronizer.java index 35ed66f14f13..6ce258d2bd53 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectSynchronizer.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectSynchronizer.java @@ -27,7 +27,6 @@ import java.util.*; import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.utilities.*; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.types.*; import sun.jvm.hotspot.utilities.Observable; @@ -50,23 +49,7 @@ private static synchronized void initialize(TypeDataBase db) throws WrongTypeExc } public long identityHashValueFor(Oop obj) { - Mark mark = obj.getMark(); - if (mark.isNeutral()) { - // FIXME: can not generate marks in debugging system - return mark.hash(); - } else if (mark.hasMonitor()) { - return mark.hash(); - } else { - if (Assert.ASSERTS_ENABLED) { - Assert.that(VM.getVM().isDebugging(), "Can not access displaced header otherwise"); - } - if (mark.hasDisplacedMarkHelper()) { - Mark temp = mark.displacedMarkHelper(); - return temp.hash(); - } - // FIXME: can not do anything else here in debugging system - return 0; - } + return obj.getMark().hash(); } public static Iterator objectMonitorIterator() { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java index 328a3117a68a..3d049fc21d52 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java @@ -858,7 +858,7 @@ protected void writeClassAttributes() throws IOException { dos.writeShort(innerClasses.at(index++)); short accFlag = innerClasses.at(index++); - if (!klass.supportsInlineTypes()) { + if (!klass.supportsValueTypes()) { // Filter out ACC_IDENTITY from access flags for inner class. accFlag &= ~ (short) JVM_ACC_IDENTITY; } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/MonitorCacheDumpPanel.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/MonitorCacheDumpPanel.java index ffedbc515983..20771c2b8766 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/MonitorCacheDumpPanel.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/MonitorCacheDumpPanel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, 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 @@ -65,7 +65,6 @@ private static void dumpMonitor(PrintStream tty, ObjectMonitor mon, boolean raw) tty.print("ObjectMonitor@" + mon.getAddress()); if (raw) tty.print("(Raw Monitor)"); tty.println(); - tty.println(" _header: 0x" + Long.toHexString(mon.header().value())); OopHandle obj = mon.object(); if (obj == null) { tty.println(" _object: null"); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java index 21e9fa999d8c..49def616ff79 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java @@ -706,11 +706,22 @@ private int calculateArrayMaxLength(long originalArrayLength, return (int) length; } + // Direct instances of ObjArrayKlass represent the Java types that Java code can see. + // RefArrayKlass/FlatArrayKlass describe different implementations of the arrays, + // filter them out to avoid duplicates. + private boolean filterOutKlass(Klass k) { + return (k instanceof ObjArrayKlass) && + !k.getKind().equals(Klass.KlassKind.ObjArrayKlassKind); + } + private void writeClassDumpRecords() throws IOException { ClassLoaderDataGraph cldGraph = VM.getVM().getClassLoaderDataGraph(); try { cldGraph.classesDo(new ClassLoaderDataGraph.ClassVisitor() { public void visit(Klass k) { + if (filterOutKlass(k)) { + return; + } try { writeHeapRecordPrologue(calculateClassDumpRecordSize(k)); writeClassDumpRecord(k); @@ -1285,6 +1296,9 @@ private void writeClasses() throws IOException { try { cldGraph.classesDo(new ClassLoaderDataGraph.ClassVisitor() { public void visit(Klass k) { + if (filterOutKlass(k)) { + return; + } try { Instance clazz = k.getJavaMirror(); writeHeader(HPROF_LOAD_CLASS, 2 * (OBJ_ID_SIZE + 4)); diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/Json.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/Json.java new file mode 100644 index 000000000000..c28a881097c1 --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/Json.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.incubator.json; + +import java.util.Objects; + +import jdk.incubator.json.impl.JsonParser; +import jdk.incubator.json.impl.JsonGenerator; + +/** + * This class provides static methods for parsing and generating JSON texts. + * + *

      + * {@link #parse(String)} and {@link #parse(char[])} produce a {@code JsonValue} + * by parsing data adhering to the JSON syntax defined in + * RFC 8259. + * {@snippet lang = java: + * JsonValue root = Json.parse(jsonText); + * } + * Successful parsing guarantees there are no syntax errors. Unsuccessful + * parsing throws a {@link JsonParseException}. Note that duplicate names in + * a {@code JsonObject} also result in this exception. + *

      + * {@link #toDisplayString(JsonValue, String)} produces a + * JSON text representation of the given {@code JsonValue} suitable for display. + * + * @spec https://datatracker.ietf.org/doc/html/rfc8259 RFC 8259: The JavaScript + * Object Notation (JSON) Data Interchange Format + * @since 28 + */ +public final class Json { + + /** + * Parses and creates a {@code JsonValue} from the given JSON text. + * If parsing succeeds, it guarantees that the input text conforms to + * the JSON syntax. If the text contains any JSON object that has + * duplicate names, a {@code JsonParseException} is thrown. + *

      + * {@code JsonObject}s preserve the order of members in the input JSON + * text. + * + * @implNote {@code JsonValue}s created by this method may produce their + * underlying value representation lazily. + * + * @param in the input JSON text as {@code String}. Non-null. + * @throws JsonParseException if the input JSON text does not conform + * to the JSON text format or a JSON object containing + * duplicate names is encountered. + * @throws NullPointerException if {@code in} is {@code null} + * @return the parsed {@code JsonValue} + */ + public static JsonValue parse(String in) { + Objects.requireNonNull(in); + return new JsonParser(in.toCharArray()).parseRoot(); + } + + /** + * Parses and creates a {@code JsonValue} from the given JSON text. + * If parsing succeeds, it guarantees that the input text conforms to + * the JSON syntax. If the text contains any JSON object that has + * duplicate names, a {@code JsonParseException} is thrown. After parsing, + * changes to the input array have no effect on the returned {@code JsonValue}. + *

      + * {@code JsonObject}s preserve the order of their members declared in and parsed from + * the JSON text. + * + * @implNote {@code JsonValue}s created by this method may produce their + * underlying value representation lazily. + * + * @param in the input JSON text as {@code char[]}. Non-null. + * @throws JsonParseException if the input JSON text does not conform + * to the JSON text format or a JSON object containing + * duplicate names is encountered. + * @throws NullPointerException if {@code in} is {@code null} + * @return the parsed {@code JsonValue} + */ + public static JsonValue parse(char[] in) { + Objects.requireNonNull(in); + // Defensive copy on input. Ensure source is immutable. + return new JsonParser(in.clone()).parseRoot(); + } + + /** + * {@return the String representation of the given {@code JsonValue} that conforms + * to the JSON syntax} As opposed to the compact output returned by {@link + * JsonValue#toString()}, this method returns JSON text that is better + * suited for display. The {@code indent} parameter specifies the indentation + * string used for each line and may contain only JSON insignificant whitespace + * characters: space ({@code ' '}), horizontal tab ({@code '\t'}), line feed + * ({@code '\n'}), or carriage return ({@code '\r'}). + * + * @param value the {@code JsonValue} to create the display string from. Non-null. + * @param indent the {@code String} for the indentation. Non-null. + * @throws IllegalArgumentException if {@code indent} contains characters other + * than insignificant whitespace characters. + * @throws NullPointerException if {@code value} or {@code indent} is {@code null} + * @see JsonValue#toString() + */ + public static String toDisplayString(JsonValue value, String indent) { + Objects.requireNonNull(value); + Objects.requireNonNull(indent); + if (!indent.chars().allMatch(c -> + c == ' ' || c == '\t' || c == '\n' || c == '\r')) { + throw new IllegalArgumentException("indent contains non-insignificant" + + " whitespace: " + indent); + } + return JsonGenerator.toDisplayString(value, indent); + } + + // no instantiation is allowed for this class + private Json() {} +} diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonArray.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonArray.java new file mode 100644 index 000000000000..9e763b887771 --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonArray.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.incubator.json; + +import java.util.List; + +import jdk.incubator.json.impl.JsonArrayImpl; + +/** + * The interface that represents JSON array. + *

      + * A {@code JsonArray} can be created by parsing JSON text using either + * {@link Json#parse(String)} or {@link Json#parse(char[])}. + *

      Alternatively, {@link #of(List)} can be used to obtain a {@code JsonArray}. + * + * @spec https://datatracker.ietf.org/doc/html/rfc8259#section-5 RFC 8259: + * The JavaScript Object Notation (JSON) Data Interchange Format - Arrays + * @since 28 + */ +public non-sealed interface JsonArray extends JsonValue { + + /** + * {@inheritDoc} + */ + @Override + List asList(); + + /** + * {@inheritDoc} + * + * @param index {@inheritDoc} + * @throws JsonValueException if the given index is out of bounds + */ + @Override + default JsonValue get(int index) { + // Overridden to specify + return JsonValue.super.get(index); + } + + /** + * {@return the {@code JsonArray} whose contents are copied from the given + * list of {@code JsonValue}s} + * + * @param src the list of {@code JsonValue}s. Non-null. + * @throws NullPointerException if {@code src} is {@code null}, or contains + * any values that are {@code null} + */ + static JsonArray of(List src) { + return new JsonArrayImpl(src); + } +} diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonBoolean.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonBoolean.java new file mode 100644 index 000000000000..c2632bcea78e --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonBoolean.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.incubator.json; + +import jdk.incubator.json.impl.JsonBooleanImpl; + +/** + * The interface that represents the JSON boolean literals, "true" and "false". + *

      + * A {@code JsonBoolean} can be created by parsing JSON text using either + * {@link Json#parse(String)} or {@link Json#parse(char[])}. + *

      Alternatively, {@link #of(boolean)} can be used to + * obtain a {@code JsonBoolean}. + * + * @spec https://datatracker.ietf.org/doc/html/rfc8259#section-3 RFC 8259: + * The JavaScript Object Notation (JSON) Data Interchange Format - Values + * @since 28 + */ +public non-sealed interface JsonBoolean extends JsonValue { + + /** + * {@inheritDoc} + */ + @Override + boolean asBoolean(); + + /** + * {@return the {@code JsonBoolean} created from the given + * {@code boolean}} + * + * @param src the given {@code boolean}. + */ + static JsonBoolean of(boolean src) { + return src ? JsonBooleanImpl.TRUE : JsonBooleanImpl.FALSE; + } +} diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonNull.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonNull.java new file mode 100644 index 000000000000..8b1d1e332acc --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonNull.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.incubator.json; + +import jdk.incubator.json.impl.JsonNullImpl; + +/** + * The interface that represents JSON null. + *

      + * A {@code JsonNull} can be created by parsing JSON text using either + * {@link Json#parse(String)} or {@link Json#parse(char[])}. + *

      Alternatively, {@link #of()} can be used to obtain a {@code JsonNull}. + * + * @since 28 + */ +public non-sealed interface JsonNull extends JsonValue { + + /** + * {@return a {@code JsonNull}} + */ + static JsonNull of() { + return JsonNullImpl.NULL; + } +} diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonNumber.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonNumber.java new file mode 100644 index 000000000000..cddf401ec699 --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonNumber.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.incubator.json; + +import jdk.incubator.json.impl.JsonNumberImpl; + +/** + * The interface that represents JSON number, an arbitrary-precision + * number represented in base 10 using decimal digits. + *

      + * A {@code JsonNumber} can be created by parsing JSON text using either + * {@link Json#parse(String)} or {@link Json#parse(char[])}. + * When a JSON number is parsed, a {@code JsonNumber} object is created + * as long as the input number text adheres to the JSON number + * + * syntax. + *

      Alternatively, {@link #of(int)}, {@link #of(long)}, {@link #of(double)}, + * or {@link #of(String)} can be used to obtain a {@code JsonNumber}. + * The value of the {@code JsonNumber} can be retrieved as an {@code int} with + * {@link #asInt()}, as a {@code long} with {@link #asLong()}, or as a + * {@code double} with {@link #asDouble()}. {@link #toString()} can be used to + * return the string representation of the {@code JsonNumber}. + * + * @apiNote + * To avoid precision loss when converting {@code JsonNumber}s to Java types, or when + * converting {@code JsonNumber}s outside the range of {@code long} or {@code double}, + * use {@link #toString()} to create arbitrary-precision Java objects, for + * example, + * {@snippet lang="java" : + * new BigDecimal(jsonNumber.toString()) + * // or if an integral number is preferred + * new BigInteger(jsonNumber.toString()) + * // for cases with an exponent or zero fractional part + * new BigDecimal(jsonNumber.toString()).toBigIntegerExact() + * } + * + * @spec https://datatracker.ietf.org/doc/html/rfc8259#section-6 RFC 8259: + * The JavaScript Object Notation (JSON) Data Interchange Format - Numbers + * @since 28 + */ +public non-sealed interface JsonNumber extends JsonValue { + + /** + * {@inheritDoc} + * + * @throws JsonValueException if this {@code JsonNumber} is not representable + * as an {@code int}. + */ + @Override + int asInt(); + + /** + * {@inheritDoc} + * + * @throws JsonValueException if this {@code JsonNumber} is not representable + * as a {@code long}. + */ + @Override + long asLong(); + + /** + * {@inheritDoc} + * + * @apiNote {@inheritDoc} + * + * @throws JsonValueException if this {@code JsonNumber} is not representable + * as a finite {@code double}. + */ + @Override + double asDouble(); + + /** + * Creates a {@code JsonNumber} from the given {@code double} value. + * The string representation of the {@code JsonNumber} created is produced by applying + * {@link Double#toString(double)} on {@code num}. + * + * @param num the given {@code double} value. + * @return a {@code JsonNumber} created from the {@code double} value + * @throws IllegalArgumentException if the given {@code double} value + * is not a finite floating-point value ({@link Double#NaN NaN}, + * {@link Double#POSITIVE_INFINITY positive infinity}, or + * {@link Double#NEGATIVE_INFINITY negative infinity}). + */ + static JsonNumber of(double num) { + if (!Double.isFinite(num)) { + throw new IllegalArgumentException("Not a valid JSON number"); + } + var str = Double.toString(num); + return new JsonNumberImpl(str.toCharArray(), true, 0, str.length(), str.indexOf('.'), str.indexOf('E')); + } + + /** + * Creates a {@code JsonNumber} from the given {@code int} value. + * The string representation of the {@code JsonNumber} created is produced by applying + * {@link Integer#toString(int)} on {@code num}. + * + * @param num the given {@code int} value. + * @return a {@code JsonNumber} created from the {@code int} value + */ + static JsonNumber of(int num) { + var str = Integer.toString(num); + return new JsonNumberImpl(str.toCharArray(), true, 0, str.length(), -1, -1); + } + + /** + * Creates a {@code JsonNumber} from the given {@code long} value. + * The string representation of the {@code JsonNumber} created is produced by applying + * {@link Long#toString(long)} on {@code num}. + * + * @param num the given {@code long} value. + * @return a {@code JsonNumber} created from the {@code long} value + */ + static JsonNumber of(long num) { + var str = Long.toString(num); + return new JsonNumberImpl(str.toCharArray(), true, 0, str.length(), -1, -1); + } + + /** + * Creates a {@code JsonNumber} from the given {@code String} value. + * The string representation of the {@code JsonNumber} created is equivalent to + * {@code num} with any leading or trailing JSON insignificant whitespaces removed. + * + * @param num the given {@code String} value. + * @throws IllegalArgumentException if {@code num} is not a valid string + * representation of a {@code JsonNumber}. + * @throws NullPointerException if {@code num} is {@code null} + * @return a {@code JsonNumber} created from the {@code String} value + */ + static JsonNumber of(String num) { + try { + if (Json.parse(num) instanceof JsonNumberImpl jn) { + return jn.toFactoryValue(); + } + } catch (JsonParseException _) {} + throw new IllegalArgumentException("Not a JSON number"); + } + + /** + * {@return the string representation of this {@code JsonNumber}} + * + * If this {@code JsonNumber} is created by parsing a JSON number in a JSON text, + * it preserves the string representation in the JSON text, regardless of its + * precision or range. For example, a JSON number like + * "3.141592653589793238462643383279" in the JSON text will be + * returned exactly as it appears. + * If this {@code JsonNumber} is created via one of the factory methods, + * such as {@link JsonNumber#of(double)}, then the string representation is + * specified by the factory method. + */ + @Override + String toString(); +} diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonObject.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonObject.java new file mode 100644 index 000000000000..61d176484361 --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonObject.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.incubator.json; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import jdk.incubator.json.impl.JsonObjectImpl; + +/** + * The interface that represents JSON object. + *

      + * A {@code JsonObject} can be created by parsing JSON text using either + * {@link Json#parse(String)} or {@link Json#parse(char[])}. + *

      Alternatively, {@link #of(Map)} can be used to obtain a {@code JsonObject}. + *

      + * Implementations of {@code JsonObject} cannot be created from sources that + * contain duplicate member names. If duplicate names appear while parsing with + * {@link Json#parse(String)}, a {@code JsonParseException} is thrown. If duplicate + * member names are detected while creating a {@code JsonObject} with {@link #of(Map)}, + * an {@code IllegalArgumentException} is thrown. + * + * @spec https://datatracker.ietf.org/doc/html/rfc8259#section-4 RFC 8259: + * The JavaScript Object Notation (JSON) Data Interchange Format - Objects + * @since 28 + */ +public non-sealed interface JsonObject extends JsonValue { + + /** + * {@inheritDoc} + * + * @implNote {@inheritDoc} + */ + @Override + Map asMap(); + + /** + * {@inheritDoc} + * + * @param name {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @throws JsonValueException if there is no association with the member name + */ + @Override + default JsonValue get(String name) { + // Overridden to specify + return JsonValue.super.get(name); + } + + /** + * {@inheritDoc} + * + * @param name {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + */ + @Override + default Optional tryGet(String name) { + // Overridden to specify + return JsonValue.super.tryGet(name); + } + + /** + * {@return the {@code JsonObject} created from the given + * map of {@code String} to {@code JsonValue}s} + * + * @param map the map of {@code JsonValue}s. Non-null. + * @throws IllegalArgumentException if duplicate member names are given in + * {@code map}, including when they are encountered while iterating over + * the mappings of an {@link java.util.IdentityHashMap}. + * @throws NullPointerException if {@code map} is {@code null}, contains + * any keys that are {@code null}, or contains any values that are {@code null}. + */ + static JsonObject of(Map map) { + Objects.requireNonNull(map); + + LinkedHashMap m = LinkedHashMap.newLinkedHashMap(map.size()); + for (var e : map.entrySet()) { + var key = Objects.requireNonNull(e.getKey()); + var value = Objects.requireNonNull(e.getValue()); + if (m.putIfAbsent(key, value) != null) { + throw new IllegalArgumentException("Duplicate member name: " + key); + } + } + return new JsonObjectImpl(m); + } +} diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonParseException.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonParseException.java new file mode 100644 index 000000000000..15a4fbe684c6 --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonParseException.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.incubator.json; + +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.Serial; + +/** + * Signals that an error has been detected while parsing the + * JSON text. This exception is thrown if the value supplied + * to either {@link Json#parse(String)} or {@link Json#parse(char[])} + * is not valid JSON syntax, or contains a JSON object with duplicate + * names. + * + * @since 28 + */ +public final class JsonParseException extends RuntimeException { + + @Serial + private static final long serialVersionUID = 7022545379651073390L; + + /** + * Zero-based line number of the error, counted by {@code '\n'} (linefeed, + * {@code U+000A}) characters. + * + * @serial + */ + private final int line; + + /** + * Zero-based position of the error within the line, counted in UTF-16 + * code units. + * + * @serial + */ + private final int pos; + + /** + * Constructs a JsonParseException with the specified detail message. + * @param message the detail message + * @param line the zero-based line number of the error, counted by + * {@code '\n'} (linefeed, {@code U+000A}) characters. Non-negative. + * @param pos the zero-based position of the error within the line, counted + * in UTF-16 code units. Non-negative. + * @throws IllegalArgumentException if {@code line} or {@code pos} are negative + */ + public JsonParseException(String message, int line, int pos) { + super(message); + if (line < 0 || pos < 0) { + throw new IllegalArgumentException(INVALID_LOCATION); + } + this.line = line; + this.pos = pos; + } + + /** + * {@return the zero-based line number of the error, counted by + * {@code '\n'} (linefeed, {@code U+000A}) characters} + */ + public int getErrorLine() { + return line; + } + + /** + * {@return the zero-based position of the error within the line, + * counted in UTF-16 code units} + */ + public int getErrorPosition() { + return pos; + } + + /** + * Restores the state of this exception from the specified stream. + * + * @param in the stream from which to read the exception + * @throws IOException if an I/O error occurs + * @throws ClassNotFoundException if a class in the stream cannot be found + * @throws InvalidObjectException if {@code line} or {@code pos} is negative + */ + @Serial + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + if (line < 0 || pos < 0) { + throw new InvalidObjectException(INVALID_LOCATION); + } + } + + private static final String INVALID_LOCATION = + "\"line\" and \"pos\" should be non-negative"; +} diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonString.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonString.java new file mode 100644 index 000000000000..13e75a12c1b9 --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonString.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.incubator.json; + +import java.util.Objects; + +import jdk.incubator.json.impl.JsonStringImpl; +import jdk.incubator.json.impl.Utils; + +/** + * The interface that represents JSON string. + *

      + * A {@code JsonString} can be created by parsing JSON text using either + * {@link Json#parse(String)} or {@link Json#parse(char[])}. + *

      Alternatively, {@link #of(String)} can be used to obtain a {@code JsonString} + * directly from a {@code String}. The {@code String} values of {@code JsonString} + * instances produced by the following expressions are all equivalent: + * {@snippet lang = "java": + * Json.parse("\"foo\\t\"").asString(); + * Json.parse("\"foo\\u0009\"").asString(); + * JsonString.of("foo\t").asString(); + * } + * Within a valid JSON string, any character may be escaped using either a + * two-character escape sequence (if applicable) or one or two Unicode escape + * sequences. A supplementary character is represented by two Unicode escape + * sequences corresponding to its surrogate pair. + * Quotation Mark (U+0022), Backslash (Reverse Solidus, U+005C), and the control + * characters (U+0000 through U+001F) must be escaped. + * + * @spec https://datatracker.ietf.org/doc/html/rfc8259#section-7 RFC 8259: + * The JavaScript Object Notation (JSON) Data Interchange Format - Strings + * @since 28 + */ +public non-sealed interface JsonString extends JsonValue { + + /** + * {@return the {@code JsonString} created from the given {@code String}} + * Unlike {@link Json#parse(String)}, {@code src} is not expected to be + * surrounded by quotation marks and the {@linkplain ##escape-characters special characters} + * do not need to be escaped. As a result, {@code src} is equal to {@code + * JsonString.of(src).asString()}. + * + * @param src the given source {@code String}. Non-null. + * @throws NullPointerException if {@code src} is {@code null} + */ + static JsonString of(String src) { + var escaped = '"' + Utils.escape(Objects.requireNonNull(src)) + '"'; + return new JsonStringImpl(escaped.toCharArray(), true, 0, escaped.length(), + escaped.length() != src.length() + 2); + } + + /** + * {@return the JSON string represented by this {@code JsonString}} + * If this {@code JsonString} was created by parsing a JSON text, it + * preserves the original text representation of the corresponding JSON + * string. Otherwise, the returned JSON string is the source {@code String} + * passed to the factory method {@link #of(String)} surrounded by double quotes + * with {@linkplain ##escape-characters special characters} properly escaped. + * + * @see #asString() + */ + @Override + String toString(); + + /** + * {@inheritDoc} + * + * @see #toString() + */ + @Override + String asString(); +} diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonValue.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonValue.java new file mode 100644 index 000000000000..f6a4b5d10060 --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonValue.java @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.incubator.json; + +import jdk.incubator.json.impl.Utils; + +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +/** + * The interface that represents a JSON value. A {@code JsonValue} represents + * a syntactic element within a JSON text. The {@code JsonValue} subtypes + * correspond to the JSON types, while {@code JsonValue} itself provides a uniform + * interface for navigation, conversion, and generation. + * + *

      {@code JsonValue} does not define any identity or value semantics. + * Code that requires equality, hashing, or comparisons should use a + * {@linkplain jdk.incubator.json/jdk.incubator.json##conversion conversion} + * method to obtain a Java value upon which such operations are performed. + * + *

      Instances of {@code JsonValue} are immutable and thread safe. See the + * {@linkplain jdk.incubator.json/jdk.incubator.json package specification} + * for an overview of parsing, accessing, converting, and generating JSON text. + * + * @since 28 + */ +public sealed interface JsonValue permits JsonString, JsonNumber, JsonObject, JsonArray, JsonBoolean, JsonNull { + + /** + * {@return a String representation of this {@code JsonValue} that conforms to JSON syntax} + * + * The returned string represents the same JSON value as this object and + * does not contain insignificant whitespace or line separators. The returned String + * may or may not be a canonical representation of the JSON value. If this {@code JsonValue} + * was obtained via one of the parsing methods on the {@link Json} class, the + * returned String is not necessarily an exact lexical match of the JSON text that + * was parsed. Subinterfaces may specify stronger preservation behavior for their + * corresponding JSON type. + *

      + * For a String representation suitable for display, use + * {@link Json#toDisplayString(JsonValue, String)}. + * + * @see Json#toDisplayString(JsonValue, String) + */ + String toString(); + + // Conversion methods all throw exceptions by default in JsonValue. + // Implementors of the sub-interfaces are expected to provide reasonable implementations. + + /** + * {@return the {@code boolean} value represented by this {@code JsonValue} if + * it is an instance of {@link JsonBoolean}; otherwise, throws a + * {@code JsonValueException}} + * + * @implSpec + * The default implementation provided by {@code JsonValue} throws {@code + * JsonValueException}. As such, implementors of {@code JsonBoolean} are expected to + * provide an implementation of this method. + * + * @throws JsonValueException if this {@code JsonValue} is not an instance of {@code JsonBoolean}. + */ + default boolean asBoolean() { + throw Utils.composeTypeError(this, JsonBoolean.class); + } + + /** + * {@return an {@code int} if this {@code JsonValue} is an instance of {@link JsonNumber} + * that can be converted exactly; otherwise, throws a {@code JsonValueException}} + * + * This {@code JsonValue} must be a JSON number that represents + * a whole number and that is within the range + * {@link Integer#MIN_VALUE} to {@link Integer#MAX_VALUE}, inclusive. This is true + * even if the JSON number contains an exponent or a fractional part consisting of + * all zeroes. For example, the JSON numbers "123.0" and "1.23e2" both + * produce an {@code int} value of {@code 123}. A {@code JsonValueException} + * is thrown when the numeric value cannot be represented as an {@code int}; + * for example, the JSON number "5.5". + * + * @implSpec + * The default implementation provided by {@code JsonValue} throws {@code + * JsonValueException}. As such, implementors of {@code JsonNumber} are expected to + * provide an implementation of this method. + * + * @throws JsonValueException if this {@code JsonValue} is not an instance + * of {@code JsonNumber} or is not representable as an {@code int}. + */ + default int asInt() { + throw Utils.composeTypeError(this, JsonNumber.class); + } + + /** + * {@return a {@code long} if this {@code JsonValue} is an instance of {@link JsonNumber} + * that can be converted exactly; otherwise, throws a {@code JsonValueException}} + * + * This {@code JsonValue} must be a JSON number that represents + * a whole number and that is within the range {@link Long#MIN_VALUE} to + * {@link Long#MAX_VALUE}, inclusive. This is true even if the JSON number contains an + * exponent or a fractional part consisting of all zeroes. For example, + * the JSON numbers "123.0" and "1.23e2" both produce a {@code long} value of + * {@code 123}. A {@code JsonValueException} is thrown when the numeric value + * cannot be represented as a {@code long}; for example, the JSON number "5.5". + * + * @implSpec + * The default implementation provided by {@code JsonValue} throws {@code + * JsonValueException}. As such, implementors of {@code JsonNumber} are expected to + * provide an implementation of this method. + * + * @throws JsonValueException if this {@code JsonValue} is not an instance + * of {@code JsonNumber} or is not representable as a {@code long}. + */ + default long asLong() { + throw Utils.composeTypeError(this, JsonNumber.class); + } + + /** + * {@return a {@code double} if this {@code JsonValue} is an instance of {@link JsonNumber} + * that can be converted, as if by {@link Double#parseDouble Double.parseDouble}, to a finite + * {@code double} value; otherwise, throws a {@code JsonValueException}} + * + * @apiNote Callers of this method should be aware of the potential loss in precision or + * magnitude when a {@code JsonNumber} is converted to a {@code double}. A JSON number + * may be rounded to the nearest representable {@code double} value, and a JSON number + * with more than about 15 decimal digits may lose precision. A JSON number with a + * magnitude larger than about 1.8 × 10308 cannot be + * represented as a finite {@code double}, + * and attempting to convert such a number will result in {@code JsonValueException}. + * (This differs from {@link Double#parseDouble Double.parseDouble}, which will return + * {@link Double#POSITIVE_INFINITY} or {@link Double#NEGATIVE_INFINITY} for such cases.) + * This method will never return {@link Double#NaN}. However, this method will + * properly convert and return negative zero ({@code -0.0}). To handle numbers of almost + * arbitrary precision and magnitude, consider converting to {@link java.math.BigDecimal + * BigDecimal} using {@code new BigDecimal(jsonNumber.toString())}. Note that + * {@code BigDecimal} cannot represent negative zero. + * + * @implSpec + * The default implementation provided by {@code JsonValue} throws {@code + * JsonValueException}. As such, implementors of {@code JsonNumber} are expected to + * provide an implementation of this method. + * + * @throws JsonValueException if this {@code JsonValue} is not an instance + * of {@code JsonNumber} or is not representable as a finite {@code double}. + */ + default double asDouble() { + throw Utils.composeTypeError(this, JsonNumber.class); + } + + /** + * {@return the {@code String} value represented by this {@code JsonValue} if + * it is an instance of {@link JsonString}; otherwise, throws a + * {@code JsonValueException}} + * If this {@code JsonString} was created by parsing a JSON text, any + * escaped characters in the original JSON text are converted to their + * unescaped form. + * + * @implSpec + * The default implementation provided by {@code JsonValue} throws {@code + * JsonValueException}. As such, implementors of {@code JsonString} are expected to + * provide an implementation of this method. + * + * @throws JsonValueException if this {@code JsonValue} is not an instance of {@code JsonString}. + */ + default String asString() { + throw Utils.composeTypeError(this, JsonString.class); + } + + /** + * {@return an unmodifiable list of the {@code JsonValue}s if this + * {@code JsonValue} is an instance of {@link JsonArray}; otherwise, throws a + * {@code JsonValueException}} + * + * @implSpec + * The default implementation provided by {@code JsonValue} throws {@code + * JsonValueException}. As such, implementors of {@code JsonArray} are expected to + * provide an implementation of this method. + * + * @throws JsonValueException if this {@code JsonValue} is not an instance of {@code JsonArray}. + */ + default List asList() { + throw Utils.composeTypeError(this, JsonArray.class); + } + + /** + * {@return an unmodifiable map of {@code String} to {@code JsonValue} if this + * {@code JsonValue} is an instance of {@link JsonObject}; otherwise, throws a + * {@code JsonValueException}} + * + * @implSpec + * The default implementation provided by {@code JsonValue} throws {@code + * JsonValueException}. As such, implementors of {@code JsonObject} are expected to + * provide an implementation of this method. + * @implNote + * The JDK platform implementation of {@code JsonObject} preserves the + * encounter order of members. When a {@code JsonObject} is created by + * parsing, this corresponds to the order of members in the source JSON + * text. When created via the {@link JsonObject#of(Map)} factory method, the order + * follows the encounter order of the provided map. + * + * @throws JsonValueException if this {@code JsonValue} is not an instance of {@code JsonObject}. + */ + default Map asMap() { + throw Utils.composeTypeError(this, JsonObject.class); + } + + // Access methods are able to provide a suitable default implementation directly + // in JsonValue, and as such are not specified to be implemented by sub-interfaces. + // However, relevant sub-interfaces will override them to explicitly have them + // declared in their Javadoc as well as make any needed specification alterations. + + /** + * {@return the {@code JsonValue} associated with the given member name if this + * {@code JsonValue} is an instance of {@link JsonObject}; otherwise, throws a + * {@code JsonValueException}} + * + * @implSpec + * The default implementation obtains a {@code JsonValue} which is the result + * of invoking {@link #asMap()}{@code .get(name)}. If {@code name} is absent, + * {@code JsonValueException} is thrown. + * + * @param name the member name + * @throws NullPointerException if the member name is {@code null} + * @throws JsonValueException if this {@code JsonValue} is not an instance of a {@code JsonObject} or + * there is no association with the member name + */ + default JsonValue get(String name) { + Objects.requireNonNull(name); + return switch (asMap().get(name)) { + case JsonValue jv -> jv; + case null -> throw Utils.composeError(this, + "JsonObject member \"%s\" does not exist.".formatted(name)); + }; + } + + /** + * {@return an {@code Optional} containing the value of a given member of + * this {@link JsonObject}, or an empty {@code Optional} if the member is + * absent; throws {@code JsonValueException} if this {@code JsonValue} is + * not a {@code JsonObject}} + * + * @implSpec + * The default implementation obtains an {@code Optional} by invoking {@link + * #asMap()}{@code .get(name)}, which is then passed to {@link Optional#ofNullable}. + * + * @param name the member name + * @throws NullPointerException if the member name is {@code null} + * @throws JsonValueException if this {@code JsonValue} is not an instance of a {@code JsonObject} + */ + default Optional tryGet(String name) { + Objects.requireNonNull(name); + return Optional.ofNullable(asMap().get(name)); + } + + /** + * {@return the {@code JsonValue} associated with the given index if this + * {@code JsonValue} is an instance of {@link JsonArray}; otherwise, throws a + * {@code JsonValueException}} + * + * @implSpec + * The default implementation obtains a {@code JsonValue} which is the result + * of invoking {@link #asList()}{@code .get(index)}. If {@code index} is + * out of bounds, {@code JsonValueException} is thrown. + * + * @param index the index of the array + * @throws JsonValueException if this {@code JsonValue} is not an instance of a {@code JsonArray} + * or the given index is out of bounds + */ + default JsonValue get(int index) { + List elements = asList(); + try { + return elements.get(index); + } catch (IndexOutOfBoundsException _) { + throw Utils.composeError(this, String.format(Locale.ROOT, + "JsonArray index %d out of bounds for length %d.", + index, elements.size())); + } + } + + /** + * {@return an {@code Optional} containing this {@code JsonValue} if it + * is not an instance of {@code JsonNull}, otherwise an empty {@code Optional}} + * + * @implSpec + * The default implementation returns {@link Optional#empty} if this + * {@code JsonValue} is an instance of {@code JsonNull}; otherwise + * {@link Optional#of Optional.of(this)}. + */ + default Optional tryValue() { + return switch (this) { + case JsonNull _ -> Optional.empty(); + case JsonValue _ -> Optional.of(this); + }; + } +} diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonValueException.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonValueException.java new file mode 100644 index 000000000000..06edc35e4937 --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/JsonValueException.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.incubator.json; + +import java.io.Serial; + +/** + * Indicates that an error has been detected while operating on the {@code JsonValue}. + * This exception is thrown under the following conditions: + *

        + *
      • + * An {@linkplain jdk.incubator.json/jdk.incubator.json##access access} or a + * {@linkplain jdk.incubator.json/jdk.incubator.json##conversion conversion} method is invoked on a + * {@code JsonValue} of an incompatible type. For example, calling + * {@code asBoolean()} on a {@code JsonString}. + *
      • + *
      • + * An access method returning {@code JsonValue} is invoked for a non-existent + * value, such as {@code get(String)} for a missing member in a + * {@code JsonObject}, or {@code get(int)} for an out-of-bounds index in a + * {@code JsonArray}. + *
      • + *
      • + * {@code asInt()} or {@code asLong()} is invoked on a {@code JsonNumber} + * that cannot be represented without loss of information by the target type. + *
      • + *
      • + * {@code asDouble()} is invoked on a {@code JsonNumber} whose string + * representation cannot be converted to a finite {@code double}. + *
      • + *
      + * @since 28 + */ +public final class JsonValueException extends RuntimeException { + + @Serial + private static final long serialVersionUID = 2040280066622450939L; + + /** + * Constructs a {@code JsonValueException} with the specified detail message. + * @param message the detail message + */ + public JsonValueException(String message) { + super(message); + } +} diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonArrayImpl.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonArrayImpl.java new file mode 100644 index 000000000000..bf20cb019a73 --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonArrayImpl.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.incubator.json.impl; + +import java.util.List; +import java.util.Locale; + +import jdk.incubator.json.JsonArray; +import jdk.incubator.json.JsonValue; + +/** + * JsonArray implementation class. Instances of this class are immutable. + * + *

      For a parsed instance, {@code doc} is the backing input JSON + * text and {@code offset} indicates the starting offset in {@code doc}. + * For a factory-created instance, {@code doc} and {@code offset} are + * {@code null} and {@code -1}, respectively. + * + *

      {@code theValues} holds an immutable shallow copy of JSON values + * parsed from the backing JSON text or supplied to the factory method. + * {@code asList()} returns this immutable list. + */ +public final class JsonArrayImpl implements JsonArray, JsonValueSupport { + + private final List theValues; + private final int offset; + private final char[] doc; + + public JsonArrayImpl(List from) { + this(from, -1, null); + } + + public JsonArrayImpl(List from, int o, char[] d) { + theValues = List.copyOf(from); + offset = o; + doc = d; + } + + // Conversion override + @Override + public List asList() { + return theValues; + } + + // Navigation overrides (on default) -> bypass the unmodifiable wrap + @Override + public JsonValue get(int index) { + try { + return theValues.get(index); + } catch (IndexOutOfBoundsException _) { + throw Utils.composeError(this, String.format(Locale.ROOT, + "JsonArray index %d out of bounds for length %d.", + index, theValues.size())); + } + } + + @Override + public char[] doc() { + return doc; + } + + @Override + public int offset() { + return offset; + } + + @Override + public String toString() { + return JsonGenerator.toCompactString(this); + } +} diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonBooleanImpl.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonBooleanImpl.java new file mode 100644 index 000000000000..062185de225f --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonBooleanImpl.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.incubator.json.impl; + +import jdk.incubator.json.JsonBoolean; + +/** + * JsonBoolean implementation class. Instances of this class are immutable. + * + *

      For a parsed instance, {@code doc} is the backing input JSON + * text and {@code offset} indicates the starting offset in {@code doc}. + * For a factory-created instance, {@code doc} and {@code offset} are + * {@code null} and {@code -1}, respectively. + */ +public final class JsonBooleanImpl implements JsonBoolean, JsonValueSupport { + + private final boolean theBoolean; + private final int offset; + private final char[] doc; + + public static final JsonBooleanImpl TRUE = new JsonBooleanImpl(true, null, -1); + public static final JsonBooleanImpl FALSE = new JsonBooleanImpl(false, null, -1); + + public JsonBooleanImpl(boolean bool, char[] doc, int offset) { + theBoolean = bool; + this.doc = doc; + this.offset = offset; + } + + @Override + public boolean asBoolean() { + return theBoolean; + } + + @Override + public char[] doc() { + return doc; + } + + @Override + public int offset() { + return offset; + } + + @Override + public String toString() { + return String.valueOf(asBoolean()); + } +} diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonGenerator.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonGenerator.java new file mode 100644 index 000000000000..6d5e86b18fc8 --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonGenerator.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.incubator.json.impl; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Iterator; +import java.util.Map; + +import jdk.incubator.json.JsonArray; +import jdk.incubator.json.JsonObject; +import jdk.incubator.json.JsonValue; + +/** + * Generates JSON text for JsonValue, either for toString() or toDisplayString(). + */ +public final class JsonGenerator { + + private sealed interface StructureFrame permits ArrayFrame, ObjectFrame {} + private record ArrayFrame(Iterator elements, int depth) implements StructureFrame {} + private record ObjectFrame(Iterator> members, int depth) implements StructureFrame {} + + // Generates JSON text for Json[Object|Array].toString() + public static String toCompactString(JsonValue jv) { + return generate(jv, "", false); + } + + // Generates JSON text for Json.toDisplayString() + public static String toDisplayString(JsonValue jv, String indent) { + return generate(jv, indent, true); + } + + private static String generate(JsonValue root, String indent, boolean isDisplay) { + var sb = new StringBuilder(); + String delim = isDisplay ? ",\n" : ","; + Deque stack = new ArrayDeque<>(); + enterValue(root, sb, stack, 0, isDisplay); + + while (!stack.isEmpty()) { + switch (stack.peek()) { + case ArrayFrame af -> { + var elements = af.elements; + if (elements.hasNext()) { + var stackSize = stack.size(); + if (isDisplay) { + sb.repeat(indent, af.depth + 1); + } + enterValue(elements.next(), sb, stack, af.depth + 1, isDisplay); + if (stackSize == stack.size()) { + sb.append(delim); // Appends after non-structural + } + } else { + closeStructure(sb, stack, "]", indent, delim, af.depth, isDisplay); + } + } + case ObjectFrame of -> { + var members = of.members; + if (members.hasNext()) { + var stackSize = stack.size(); + var entry = members.next(); + if (isDisplay) { + sb.repeat(indent, of.depth + 1); + } + sb.append('"') + .append(Utils.escape(entry.getKey())) + .append("\":") + .append(isDisplay ? " " : ""); + enterValue(entry.getValue(), sb, stack, of.depth + 1, isDisplay); + if (stackSize == stack.size()) { + sb.append(delim); // Appends after non-structural + } + } else { + closeStructure(sb, stack, "}", indent, delim, of.depth, isDisplay); + } + } + } + } + return sb.toString(); + } + + private static void closeStructure(StringBuilder sb, Deque stack, String close, String indent, + String delim, int depth, boolean isDisplay) { + // We always append delim for each child, so trim the final exccess + sb.setLength(sb.length() - delim.length()); + if (isDisplay) { + sb.append("\n"); + sb.repeat(indent, depth); + } + sb.append(close); + stack.pop(); + if (!stack.isEmpty()) { + sb.append(delim); // Need to append delim for structures + } + } + + private static void enterValue(JsonValue jv, StringBuilder sb, Deque stack, + int depth, boolean isDisplay) { + switch (jv) { + case JsonArray ja -> { + var elements = ja.asList().iterator(); + if (!elements.hasNext()) { + sb.append("[]"); + } else { + sb.append(isDisplay ? "[\n" : "["); + stack.push(new ArrayFrame(elements, depth)); + } + } + case JsonObject jo -> { + var members = jo.asMap().entrySet().iterator(); + if (!members.hasNext()) { + sb.append("{}"); + } else { + sb.append(isDisplay ? "{\n" : "{"); + stack.push(new ObjectFrame(members, depth)); + } + } + default -> sb.append(jv); + } + } + + // Instantiation is not allowed + private JsonGenerator() {} +} diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonNullImpl.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonNullImpl.java new file mode 100644 index 000000000000..f28dc3dc75da --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonNullImpl.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.incubator.json.impl; + +import jdk.incubator.json.JsonNull; + +/** + * JsonNull implementation class. Instances of this class are immutable. + * + *

      For a parsed instance, {@code doc} is the backing input JSON + * text and {@code offset} indicates the starting offset in {@code doc}. + * For a factory-created instance, {@code doc} and {@code offset} are + * {@code null} and {@code -1}, respectively. + */ +public final class JsonNullImpl implements JsonNull, JsonValueSupport { + + private final int offset; + private final char[] doc; + + public static final JsonNullImpl NULL = new JsonNullImpl(null, -1); + private static final String VALUE = "null"; + + public JsonNullImpl(char[] doc, int offset) { + this.doc = doc; + this.offset = offset; + } + + @Override + public char[] doc() { + return doc; + } + + @Override + public int offset() { + return offset; + } + + @Override + public String toString() { + return VALUE; + } +} diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonNumberImpl.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonNumberImpl.java new file mode 100644 index 000000000000..2062b4cde5b3 --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonNumberImpl.java @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.incubator.json.impl; + +import java.util.OptionalDouble; +import java.util.OptionalInt; +import java.util.OptionalLong; + +import jdk.incubator.json.JsonNumber; + +/** + * JsonNumber implementation class. Instances of this class are immutable. + * + *

      A JSON number is represented by the range {@code [startOffset, endOffset)} + * in {@code doc}. For a parsed instance, {@code doc} is the backing input JSON text. + * For a factory-created instance, it is a private character array backing the + * JSON number. If the JSON number contains a decimal point and/or an exponent, + * their offsets are stored in {@code decimalOffset} and/or {@code exponentOffset}. + * {@code -1} offset indicates it is absent. + * + *

      {@code numString} lazily instantiates the JSON representation returned by + * {@code toString()}. It preserves the original representation for a parsed value. + * + *

      {@code numInteger}, {@code numLong}, and {@code numDouble} lazily instantiate + * the {@code OptionalInt}, {@code OptionalLong}, and {@code OptionalDouble}, + * used by the conversion methods {@code asInt()}, {@code asLong()}, + * and {@code asDouble()}, respectively. + */ +public final class JsonNumberImpl implements JsonNumber, JsonValueSupport { + + private final char[] doc; + private final int startOffset; + private final int endOffset; + private final int decimalOffset; + private final int exponentOffset; + private final boolean fromFactory; + + private final LazyConstant numString = LazyConstant.of(this::initNumString); + private final LazyConstant numInteger = LazyConstant.of(this::initNumInteger); + private final LazyConstant numLong = LazyConstant.of(this::initNumLong); + private final LazyConstant numDouble = LazyConstant.of(this::initNumDouble); + + public JsonNumberImpl(char[] doc, boolean factory, int start, int end, int dec, int exp) { + this.doc = doc; + fromFactory = factory; + startOffset = start; + endOffset = end; + decimalOffset = dec; + exponentOffset = exp; + } + + @Override + public int asInt() { + return numInteger.get().orElseThrow(() -> + Utils.composeError(this, this + " cannot be represented as an int.")); + } + + @Override + public long asLong() { + return numLong.get().orElseThrow(() -> + Utils.composeError(this, this + " cannot be represented as a long.")); + } + + @Override + public double asDouble() { + return numDouble.get().orElseThrow(() -> + Utils.composeError(this, this + " cannot be represented as a double.")); + } + + @Override + public char[] doc() { + return fromFactory ? null : doc; + } + + @Override + public int offset() { + return fromFactory ? -1 : startOffset; + } + + @Override + public String toString() { + return numString.get(); + } + + // LazyConstants initializers + private String initNumString() { + return new String(doc, startOffset, endOffset - startOffset); + } + + private OptionalInt initNumInteger() { + try { + var value = numLong.get(); + return value.isPresent() + ? OptionalInt.of(Math.toIntExact(value.getAsLong())) + : OptionalInt.empty(); + } catch (ArithmeticException _) { + return OptionalInt.empty(); + } + } + + private OptionalLong initNumLong() { + try { + if (decimalOffset == -1 && exponentOffset == -1) { + // Fast-path immediate parseable Long format + return OptionalLong.of(Long.parseLong(numString.get())); + } else { + // Decimal or exponent exists, derive value from + // following format -> sig * 10^power + // E.g. 54.32e1 + // sE is 'e' index / fL is 2 / exp is 1 / pow is -1 / sig is 5432 / scale is 0.1 + int sigEnd = exponentOffset == -1 ? endOffset : exponentOffset; + int fracLen = decimalOffset == -1 ? 0 : sigEnd - decimalOffset - 1; + int strippedZeros = 0; + + // Remove trailing zeros from the significand and compensate in the power. + // This helps us avoid overflow for a value that fits in a long but has trailing zeros. + // For example, the JSON number 9223372036854775807.000000 that fits in a long causes + // overflow when parsing its digits but normalizing the zeros lets us parse the + // sig as 9223372036854775807. + while (sigEnd > startOffset) { + var c = doc[sigEnd - 1]; + if (c == '0') { + sigEnd--; + strippedZeros++; + } else if (c == '.') { + sigEnd--; + } else { + break; + } + } + + // A zero significand represents zero regardless of exponent size. + if (sigEnd == startOffset || (doc[startOffset] == '-' && sigEnd == startOffset + 1)) { + return OptionalLong.of(0L); + } + + // If not zero, we will derive the final value from + // -> sig * 10^(exp - fracLen + strippedZeros) + // -> sig * 10^power + // -> sig * scale + int exp = exponentOffset == -1 ? 0 : Integer.parseInt(new String(doc, + exponentOffset + 1, endOffset - exponentOffset - 1)); + int power = Math.addExact(Math.subtractExact(exp, fracLen), strippedZeros); + long sig = decimalOffset == -1 || sigEnd <= decimalOffset + // Decimal point does not interfere with parsing sig + ? Long.parseLong(new String(doc, startOffset, sigEnd - startOffset)) + // Parse both chunks to the left and right of the decimal point + : Long.parseLong(new String(doc, startOffset, decimalOffset - startOffset) + + new String(doc, decimalOffset + 1, sigEnd - decimalOffset - 1)); + if (power >= 0) { + long scale = Math.powExact(10L, power); + return OptionalLong.of(Math.multiplyExact(sig, scale)); + } else { + long scale = Math.powExact(10L, Math.negateExact(power)); + return sig % scale == 0 + ? OptionalLong.of(Math.divideExact(sig, scale)) + : OptionalLong.empty(); // fractional leftover, so not representable as long + } + } + } catch (NumberFormatException | ArithmeticException _) {} + return OptionalLong.empty(); + } + + private OptionalDouble initNumDouble() { + var db = Double.parseDouble(numString.get()); + if (Double.isFinite(db)) { + return OptionalDouble.of(db); + } + return OptionalDouble.empty(); + } + + // Helper which converts this JNI to one that sees itself as created from a factory + public JsonNumber toFactoryValue() { + return new JsonNumberImpl(doc, true, startOffset, endOffset, decimalOffset, exponentOffset); + } +} diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonObjectImpl.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonObjectImpl.java new file mode 100644 index 000000000000..b32b088993a9 --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonObjectImpl.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.incubator.json.impl; + +import java.util.Collections; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.SequencedMap; + +import jdk.incubator.json.JsonObject; +import jdk.incubator.json.JsonValue; + +/** + * JsonObject implementation class. Instances of this class are immutable. + * + *

      For a parsed instance, {@code doc} is the backing input JSON + * text and {@code offset} indicates the starting offset in {@code doc}. + * For a factory-created instance, {@code doc} and {@code offset} are + * {@code null} and {@code -1}, respectively. + * + *

      {@code theMembers} is a {@code SequencedMap} that preserves member + * order. For a parsed instance, the member order follows the input JSON text. + * For a factory-created instance, it retains the iteration order of the given + * {@code Map}. {@code asMap()} returns an unmodifiable view of this map. + */ +public final class JsonObjectImpl implements JsonObject, JsonValueSupport { + + private final SequencedMap theMembers; + private final int offset; + private final char[] doc; + + public JsonObjectImpl(SequencedMap map) { + this(map, -1, null); + } + + public JsonObjectImpl(SequencedMap map, int o, char[] d) { + theMembers = map; + offset = o; + doc = d; + } + + // Conversion override + @Override + public Map asMap() { + return Collections.unmodifiableMap(theMembers); + } + + // Navigation overrides (on default) -> bypass the unmodifiable wrap + @Override + public JsonValue get(String name) { + Objects.requireNonNull(name); + return switch (theMembers.get(name)) { + case JsonValue jv -> jv; + case null -> throw Utils.composeError(this, + "JsonObject member \"%s\" does not exist.".formatted(name)); + }; + } + + @Override + public Optional tryGet(String name) { + Objects.requireNonNull(name); + return Optional.ofNullable(theMembers.get(name)); + } + + @Override + public char[] doc() { + return doc; + } + + @Override + public int offset() { + return offset; + } + + @Override + public String toString() { + return JsonGenerator.toCompactString(this); + } +} diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonParser.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonParser.java new file mode 100644 index 000000000000..e3d3476fdeb3 --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonParser.java @@ -0,0 +1,570 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.incubator.json.impl; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.SequencedMap; + +import jdk.incubator.json.JsonParseException; +import jdk.incubator.json.JsonString; +import jdk.incubator.json.JsonValue; + +/** + * Parses a JSON text char[] into a tree of JsonValues. JsonObject and JsonArray + * nodes create their data structures which maintain the connection to children. + * JsonNumber and JsonString contain only a start and end offset, which + * are used to lazily procure their underlying value/string on demand. + */ +public final class JsonParser { + + // Access to the underlying JSON contents + private final char[] doc; + // Lazily initialized for member names with escape sequences + private final LazyConstant sb = LazyConstant.of(StringBuilder::new); + // Current cursor position during parsing + private int cursorPos; + // For exception message on failure + private int line; + private int lineStart; + + // The "root" value + private JsonValue root; + // LIFO stack for objects/arrays partially parsed. Popped upon parsing completion + private final Deque containers = new ArrayDeque<>(); + + // Object/Array containers holding parsed child values + private sealed interface Container permits ObjectContainer, ArrayContainer {} + private static final class ObjectContainer implements Container { + final int startOffset; + final SequencedMap members = new LinkedHashMap<>(); + String name; + ObjectState state = ObjectState.NAME_OR_END; + + ObjectContainer(int startOffset) { + this.startOffset = startOffset; + } + } + private static final class ArrayContainer implements Container { + final int startOffset; + final List elements = new ArrayList<>(); + ArrayState state = ArrayState.VALUE_OR_END; + + ArrayContainer(int startOffset) { + this.startOffset = startOffset; + } + } + + // Object/Array container states for the next possible input + private enum ObjectState { + NAME_OR_END, VALUE, COMMA_OR_END + } + private enum ArrayState { + VALUE_OR_END, COMMA_OR_END + } + + public JsonParser(char[] doc) { + this.doc = doc; + } + + // Parses the lone JsonValue root + public JsonValue parseRoot() { + containers.clear(); + root = null; + + parseValue(); + + while (!containers.isEmpty()) { + switch (containers.peek()) { + case ObjectContainer oc -> parseObject(oc); + case ArrayContainer ac -> parseArray(ac); + } + } + + if (hasInput()) { + throw valueFailure(0, "Additional value(s) were found after the JSON Value"); + } + return root; + } + + /* + * Parse any one of the JSON value types: object, array, number, string, + * true, false, or null. + * JSON-text = ws value ws + * See https://datatracker.ietf.org/doc/html/rfc8259#section-3 + */ + private void parseValue() { + skipWhitespaces(); + int start = cursorPos; + + if (!hasInput()) { + throw valueFailure(start, "Expected a JSON Object, Array, String, Number, Boolean, or Null"); + } + + switch (doc[cursorPos]) { + case '{' -> { + cursorPos++; + skipWhitespaces(); + containers.push(new ObjectContainer(start)); + } + case '[' -> { + cursorPos++; + skipWhitespaces(); + containers.push(new ArrayContainer(start)); + } + case '"' -> finishValue(parseString(), start); + case 't' -> finishValue(parseTrue(), start); + case 'f' -> finishValue(parseFalse(), start); + case 'n' -> finishValue(parseNull(), start); + // While JSON Number does not support leading '+', '.', or 'e' + // we still accept, so that we can provide a better error message + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '-', '+', 'e', '.' -> finishValue(parseNumber(), start); + default -> throw valueFailure(start, UNEXPECTED_VAL); + } + } + + /* + * The parsed JsonObject contains a map which holds all lazy member mappings. + * No offsets are required as member values hold their own offsets. + * See https://datatracker.ietf.org/doc/html/rfc8259#section-4 + */ + private void parseObject(ObjectContainer oc) { + switch (oc.state) { + case NAME_OR_END -> { + if (!hasInput()) { + throw structureFailure(oc.startOffset, "JSON Object is not closed with a brace"); + } + if (oc.members.isEmpty() && charEquals('}')) { + finishObject(oc); + return; + } + + int nameStart = cursorPos; + var name = parseName(oc.startOffset); + int nameLine = line; + int nameLineStart = lineStart; + + skipWhitespaces(); + if (!charEquals(':')) { + throw structureFailure(oc.startOffset, "Expected a colon after the member name"); + } + if (oc.members.containsKey(name)) { + throw failure(nameStart, nameLine, nameLineStart, + "Duplicate member name: \"%s\" was already parsed".formatted(Utils.escape(name)), oc.startOffset, true); + } + oc.name = name; + oc.state = ObjectState.VALUE; + } + case VALUE -> parseValue(); + case COMMA_OR_END -> { + if (charEquals('}')) { + finishObject(oc); + } else if (charEquals(',')) { + skipWhitespaces(); + oc.state = ObjectState.NAME_OR_END; + } else { + throw structureFailure(oc.startOffset, "JSON Object is not closed with a brace"); + } + } + } + } + + private void finishObject(ObjectContainer oc) { + containers.pop(); + finishValue(new JsonObjectImpl(oc.members, oc.startOffset, doc), oc.startOffset); + } + + /* + * The parsed JsonArray contains a List which holds all lazy children + * elements. No offsets are required as children values hold their own offsets. + * See https://datatracker.ietf.org/doc/html/rfc8259#section-5 + */ + private void parseArray(ArrayContainer ac) { + switch (ac.state) { + case VALUE_OR_END -> { + if (!hasInput()) { + throw structureFailure(ac.startOffset, + "JSON Array is not closed with a bracket"); + } + if (ac.elements.isEmpty() && charEquals(']')) { + finishArray(ac); + } else { + parseValue(); + } + } + case COMMA_OR_END -> { + if (charEquals(']')) { + finishArray(ac); + } else if (charEquals(',')) { + ac.state = ArrayState.VALUE_OR_END; + } else { + throw structureFailure(ac.startOffset, + "JSON Array is not closed with a bracket"); + } + } + } + } + + private void finishArray(ArrayContainer ac) { + containers.pop(); + finishValue(new JsonArrayImpl(ac.elements, ac.startOffset, doc), ac.startOffset); + } + + // Place the value as either the root, an object member, or an array element. + private void finishValue(JsonValue jv, int start) { + if (hasInput()) { + switch (doc[cursorPos]) { + // Attribute incorrect values appended directly on a valid value as + // error on the value rather than its enclosing structure. + case ']', '}', ',', ' ', '\t', '\r', '\n' -> {} + default -> throw valueFailure(start, "Unexpected content after JSON value"); + } + } + skipWhitespaces(); + + if (containers.isEmpty()) { + root = jv; + } else { + switch (containers.peek()) { + case ObjectContainer oc -> { + oc.members.putLast(oc.name, jv); + oc.name = null; + oc.state = ObjectState.COMMA_OR_END; + } + case ArrayContainer ac -> { + ac.elements.add(jv); + ac.state = ArrayState.COMMA_OR_END; + } + } + } + } + + /* + * Member name equality and storage in the map should be done with the + * unescaped value. + * See https://datatracker.ietf.org/doc/html/rfc8259#section-8.3 + */ + private String parseName(int objStart) { + if (!charEquals('"')) { + throw structureFailure(objStart, "Expecting a JSON Object member name"); + } + var escape = false; + boolean useBldr = false; + var start = cursorPos; + + for (; hasInput(); cursorPos++) { + var c = doc[cursorPos]; + if (escape) { + var escapeLength = 0; + switch (c) { + // Allowed JSON escapes + case '"', '\\', '/' -> {} + case 'b' -> c = '\b'; + case 'f' -> c = '\f'; + case 'n' -> c = '\n'; + case 'r' -> c = '\r'; + case 't' -> c = '\t'; + case 'u' -> { + c = codeUnit(objStart, true); + escapeLength = 4; + } + default -> throw structureFailure(objStart, + UNRECOGNIZED_ESCAPE_SEQUENCE.formatted(formatChar(c))); + } + if (!useBldr) { + // Append everything up to the first escape sequence + sb.get().append(doc, start, cursorPos - escapeLength - 1 - start); + useBldr = true; + } + escape = false; + } else if (c == '\\') { + escape = true; + continue; + } else if (c == '"') { + cursorPos++; + if (useBldr) { + var name = sb.get().toString(); + sb.get().setLength(0); + return name; + } else { + return new String(doc, start, cursorPos - start - 1); + } + } else if (c < ' ') { + throw structureFailure(objStart, UNESCAPED_CONTROL_CODE); + } + if (useBldr) { + sb.get().append(c); + } + } + throw structureFailure(objStart, UNCLOSED_STRING.formatted("JSON Object member name")); + } + + /* + * The parsed JsonString will contain offsets correlating to the beginning + * and ending quotation marks. All Unicode characters are allowed except the + * following that require escaping: quotation mark, reverse solidus, and the + * control characters (U+0000 through U+001F). Any character may be escaped + * either through a Unicode escape sequence or two-char sequence. + * See https://datatracker.ietf.org/doc/html/rfc8259#section-7 + */ + private JsonString parseString() { + int start = cursorPos++; // Move past the starting quote + var escape = false; + boolean hasEscape = false; + for (; hasInput(); cursorPos++) { + var c = doc[cursorPos]; + if (escape) { + switch (c) { + // Allowed JSON escapes + case '"', '\\', '/', 'b', 'f', 'n', 'r', 't' -> {} + case 'u' -> codeUnit(start, false); + default -> throw valueFailure(start, + UNRECOGNIZED_ESCAPE_SEQUENCE.formatted((formatChar(c)))); + } + escape = false; + } else if (c == '\\') { + hasEscape = true; + escape = true; + } else if (c == '"') { + return new JsonStringImpl(doc, false, start, ++cursorPos, hasEscape); + } else if (c < ' ') { + throw valueFailure(start, UNESCAPED_CONTROL_CODE); + } + } + throw valueFailure(start, UNCLOSED_STRING.formatted("JSON String")); + } + + private JsonBooleanImpl parseTrue() { + var start = cursorPos++; + if (charEquals('r') && charEquals('u') && charEquals('e')) { + return new JsonBooleanImpl(true, doc, start); + } + throw valueFailure(start, UNEXPECTED_VAL); + } + + private JsonBooleanImpl parseFalse() { + var start = cursorPos++; + if (charEquals('a') && charEquals('l') && charEquals('s') + && charEquals('e')) { + return new JsonBooleanImpl(false, doc, start); + } + throw valueFailure(start, UNEXPECTED_VAL); + } + + private JsonNullImpl parseNull() { + var start = cursorPos++; + if (charEquals('u') && charEquals('l') && charEquals('l')) { + return new JsonNullImpl(doc, start); + } + throw valueFailure(start, UNEXPECTED_VAL); + } + + /* + * The parsed JsonNumber contains offsets correlating to the first and last + * allowed chars permitted in the JSON numeric grammar: + * number = [ minus ] int [ frac ] [ exp ] + * See https://datatracker.ietf.org/doc/html/rfc8259#section-6 + */ + private JsonNumberImpl parseNumber() { + int decOff = -1; + int expOff = -1; + boolean sawZero = false; + boolean havePart = false; + boolean sawSign = false; + var start = cursorPos; + + endloop: + for (; hasInput(); cursorPos++) { + var c = doc[cursorPos]; + switch (c) { + case '-' -> { + if ((cursorPos != start && expOff == -1) || havePart || sawSign) { + throw valueFailure(start, INVALID_POSITION_IN_NUMBER.formatted(c)); + } + sawSign = true; + } + case '+' -> { + if (expOff == -1 || havePart || sawSign) { + throw valueFailure(start, INVALID_POSITION_IN_NUMBER.formatted(c)); + } + sawSign = true; + } + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> { + if (decOff == -1 && expOff == -1 && sawZero) { + throw valueFailure(start, INVALID_POSITION_IN_NUMBER.formatted('0')); + } + if (doc[cursorPos] == '0' && !havePart) { + sawZero = true; + } + havePart = true; + } + case '.' -> { + if (decOff != -1 || expOff != -1) { + throw valueFailure(start, INVALID_POSITION_IN_NUMBER.formatted(c)); + } else { + if (!havePart) { + throw valueFailure(start, INVALID_POSITION_IN_NUMBER.formatted(c)); + } + decOff = cursorPos; + havePart = false; + } + } + case 'e', 'E' -> { + if (expOff != -1) { + throw valueFailure(start, INVALID_POSITION_IN_NUMBER.formatted(c)); + } else { + if (!havePart) { + throw valueFailure(start, INVALID_POSITION_IN_NUMBER.formatted(c)); + } + expOff = cursorPos; + havePart = false; + sawSign = false; + } + } + default -> { + // break the loop for white space or invalid characters + break endloop; + } + } + } + if (!havePart) { + throw valueFailure(start, "Input expected after '[.|e|E]'"); + } + return new JsonNumberImpl(doc, false, start, cursorPos, decOff, expOff); + } + + // Utility functions + + // Unescapes the Unicode escape sequence and produces a char + private char codeUnit(int start, boolean structural) { + char val = 0; + int end = cursorPos + 4; + if (end >= doc.length) { + throw failure("Invalid Unicode escape sequence. Expected four hex digits", + start, structural); + } + while (cursorPos < end) { + char c = doc[++cursorPos]; + val <<= 4; + val += (char) ( + switch (c) { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> c - '0'; + case 'a', 'b', 'c', 'd', 'e', 'f' -> c - 'a' + 10; + case 'A', 'B', 'C', 'D', 'E', 'F' -> c - 'A' + 10; + default -> throw failure( + "Invalid Unicode escape sequence. '%s' is not a hex digit" + .formatted((formatChar(c))), + start, structural); + }); + } + return val; + } + + // Returns true if the parser has not yet reached the end of the text + private boolean hasInput() { + return cursorPos < doc.length; + } + + // Walk to the next non-white space char from the current cursor position + private void skipWhitespaces() { + while (hasInput()) { + if (notWhitespace()) { + break; + } + cursorPos++; + } + } + + // see https://datatracker.ietf.org/doc/html/rfc8259#section-2 + private boolean notWhitespace() { + return switch (doc[cursorPos]) { + case ' ', '\t', '\r' -> false; + case '\n' -> { + // Increments the line and lineStart + line++; + lineStart = cursorPos + 1; + yield false; + } + default -> true; + }; + } + + // Returns true if within bounds and if the char at the current cursor position + // is equivalent to the input one. If so, cursor position is incremented. + private boolean charEquals(char c) { + if (hasInput() && c == doc[cursorPos]) { + cursorPos++; + return true; + } + return false; + } + + // To be thrown when a structure is incorrect, which derives the path from the enclosing structure itself + private JsonParseException structureFailure(int start, String message) { + return failure(cursorPos, line, lineStart, message, start, true); + } + + // To be thrown when a "value" is incorrect, which derives the path from the value + private JsonParseException valueFailure(int start, String message) { + return failure(cursorPos, line, lineStart, message, start, false); + } + + private JsonParseException failure(String message, int recentStart, boolean structural) { + return failure(cursorPos, line, lineStart, message, recentStart, structural); + } + + private JsonParseException failure(int off, int l, int ls, String message, int head, boolean structural) { + // Non-revealing message does not produce input source String + var pos = off - ls; + var path = Utils.getParsingPath(head, doc, structural); + return new JsonParseException(String.format(Locale.ROOT, + "%s.%s Location: line %d, position %d.", + message, path, l, pos), l, pos); + } + + private static String formatChar(char c) { + return c >= 0x21 && c <= 0x7E ? // Space is represented as "\u0020" for visibility + Character.toString(c) : + String.format(Locale.ROOT, "\\u%04X", (int)c); + } + + // Parsing error messages ---------------------- + private static final String UNEXPECTED_VAL = + "Unexpected value. Expected a JSON Object, Array, String, Number, Boolean, or Null"; + private static final String UNRECOGNIZED_ESCAPE_SEQUENCE = + "Unrecognized escape sequence: \"\\%s\""; + private static final String UNESCAPED_CONTROL_CODE = + "Unescaped control code"; + private static final String UNCLOSED_STRING = + "%s is not closed with a quotation mark"; + private static final String INVALID_POSITION_IN_NUMBER = + "Invalid position of '%c' within JSON Number"; +} diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonStringImpl.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonStringImpl.java new file mode 100644 index 000000000000..351dc7bfbc86 --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonStringImpl.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.incubator.json.impl; + +import jdk.incubator.json.JsonString; + +/** + * JsonString implementation class. Instances of this class are immutable. + * + *

      A JSON string is represented by the range {@code [startOffset, endOffset)} + * in {@code doc}. The range always includes the opening and closing quotation + * marks. For a parsed instance, {@code doc} is the backing input JSON text. For a + * factory-created instance, it is a private character array containing the generated + * JSON string. + * + *

      {@code jsonStr} lazily instantiates the quoted and escaped JSON + * representation returned by {@code toString()}. It preserves the original + * representation for a parsed value. {@code value} lazily instantiates the + * unquoted and unescaped Java string returned by {@code asString()}. + * + *

      {@code hasEscape} indicates whether the represented JSON string contains + * a JSON escape sequence. + */ +public final class JsonStringImpl implements JsonString, JsonValueSupport { + + private final char[] doc; + private final int startOffset; + private final int endOffset; + private final boolean hasEscape; + private final boolean fromFactory; + + // The String instance representing this JSON string for `toString()`. + // It always conforms to JSON syntax. If created by parsing a JSON text, + // it matches the original text exactly. If created via the factory method, + // non-conformant characters are properly escaped. + private final LazyConstant jsonStr = LazyConstant.of(this::initJsonStr); + + // The String instance returned by `asString()`. Escaped characters are unescaped. + private final LazyConstant value = LazyConstant.of(this::unescape); + + // LazyConstants initializers + private String initJsonStr() { + return new String(doc, startOffset, endOffset - startOffset); + } + + public JsonStringImpl(char[] doc, boolean factory, int start, int end, boolean escape) { + this.doc = doc; + fromFactory = factory; + startOffset = start; + endOffset = end; + hasEscape = escape; + } + + @Override + public String asString() { + return value.get(); + } + + @Override + public char[] doc() { + return fromFactory ? null : doc; + } + + @Override + public int offset() { + return fromFactory ? -1 : startOffset; + } + + @Override + public String toString() { + return jsonStr.get(); + } + + /* + * Provides the fully unescaped value with surrounding quotes trimmed. + * This method fully unescapes 2 char sequences as well as U escape sequences. + * As a result of un-escaping, the resultant String may not be JSON conformant. + */ + private String unescape() { + // If no escapes exist, produce from doc directly without un-escaping + if (!hasEscape) { + var ret = toString(); // Also loads JSON String value + return ret.substring(1, ret.length() - 1); + } + + // Unescape any escape sequences that exist and build the new String value + StringBuilder sb = new StringBuilder(endOffset - startOffset - 2); + var escape = false; + for (int offset = startOffset + 1; offset < endOffset - 1; offset++) { + var c = doc[offset]; + if (escape) { + switch (c) { + case '"', '\\', '/' -> {} + case 'b' -> c = '\b'; + case 'f' -> c = '\f'; + case 'n' -> c = '\n'; + case 'r' -> c = '\r'; + case 't' -> c = '\t'; + case 'u' -> { + // Will not throw NFE, text parse already validated input + c = (char) Integer.parseInt(new String(doc, offset + 1, 4), 16); + offset += 4; + } + } + escape = false; + } else if (c == '\\') { + escape = true; + continue; + } + sb.append(c); + } + return sb.toString(); + } +} diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonValueSupport.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonValueSupport.java new file mode 100644 index 000000000000..8b992234adf2 --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/JsonValueSupport.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.incubator.json.impl; + +/** + * Provides support methods for {@code JsonValue} implementation classes, + * primarily for constructing {@code JsonValueException} error messages. + */ +public sealed interface JsonValueSupport + permits JsonArrayImpl, JsonBooleanImpl, JsonNullImpl, JsonNumberImpl, JsonObjectImpl, JsonStringImpl { + + /** + * Return access to the underlying JSON text, if it was parsed. + * Otherwise, return null. + */ + char[] doc(); + + /** + * Return the associated offset of the JsonValue in the JSON text, + * if it was parsed. Otherwise, return -1. + */ + int offset(); +} diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/Utils.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/Utils.java new file mode 100644 index 000000000000..7381068d97c0 --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/impl/Utils.java @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.incubator.json.impl; + +import jdk.incubator.json.JsonArray; +import jdk.incubator.json.JsonValueException; +import jdk.incubator.json.JsonBoolean; +import jdk.incubator.json.JsonNull; +import jdk.incubator.json.JsonNumber; +import jdk.incubator.json.JsonObject; +import jdk.incubator.json.JsonString; +import jdk.incubator.json.JsonValue; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +/** + * Shared utilities for Json classes. + */ +public final class Utils { + + // Non instantiable + private Utils() {} + + /* + * Escapes a String to ensure it is a valid JSON String. + * Backslash, double quote, and control chars are escaped. + */ + public static String escape(String str) { + StringBuilder sb = null; // Lazy init + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + // Does not require escaping + if (c >= 32 && c != '\\' && c != '"') { + if (sb != null) { + sb.append(c); + } + // Requires escaping + } else { + if (sb == null) { + sb = new StringBuilder(str.length()).append(str, 0, i); + } + sb.append('\\'); + // Non-control characters + if (c == '\\' || c == '"') { + sb.append(c); + // 2 Char escapes (Control characters) + } else if (c == '\b') { + sb.append('b'); + } else if (c == '\f') { + sb.append('f'); + } else if (c == '\n') { + sb.append('n'); + } else if (c == '\r') { + sb.append('r'); + } else if (c == '\t') { + sb.append('t'); + } else { + // All other chars requiring Unicode escape sequence + sb.append('u').append(String.format("%04X", (int) c)); + } + } + } + return sb == null ? str : sb.toString(); + } + + public static JsonValueException composeError(JsonValue jv, String message) { + return new JsonValueException(message + + (jv instanceof JsonValueSupport jvs && jvs.doc() != null ? JsonPath.getValuePath(jvs) : "")); + } + + // Use to compose an exception when casting to an incorrect type + public static JsonValueException composeTypeError(JsonValue jv, Class expected) { + var actual = switch (jv) { + case JsonObject _ -> "JsonObject"; + case JsonArray _ -> "JsonArray"; + case JsonBoolean _ -> "JsonBoolean"; + case JsonNull _ -> "JsonNull"; + case JsonNumber _ -> "JsonNumber"; + case JsonString _ -> "JsonString"; + }; + return composeError(jv, "%s is not a %s.".formatted(actual, expected.getSimpleName())); + } + + static String getParsingPath(int offset, char[] doc, boolean structural) { + return JsonPath.getParsingPath(offset, doc, structural); + } + + // This class is responsible for creating the path produced by JsonValueException + // and JsonParseException. As a result, the appropriate method should be used + // as the path semantics differ between the two exception types. + // Backtracks from the offset of the offending JSON element to the root. + private static final class JsonPath { + private final int offset; + private final char[] doc; + // Tracked and incremented during path creation + private int line; + private int pos; + + private JsonPath(int offset, char[] doc) { + this.offset = offset; + this.doc = doc; + } + + // JsonParseException path produces a contextual path which may not always lead to a primitive + // value, but can occur in the structure itself. The offsets in the exception + // message should ultimately be derived from the parser state. + private static String getParsingPath(int offset, char[] doc, boolean structural) { + var pathParts = new ArrayList(); + // If we encounter an error within the structural state, but not within a value itself + // we need to manually insert the brace otherwise backtracking skips it + if (structural) { + // Structural parsing cases + if (doc[offset] == '[') { + pathParts.add("["); + } else if (doc[offset] == '{') { + pathParts.add("{"); + } + } + return " Path: \"%s\".".formatted(new JsonPath(offset, doc).parseToRoot(pathParts)); + } + + // JsonValueException path produces a path that always leads to a value, and should provide + // the correct line and pos positions derived from the JV itself + private static String getValuePath(JsonValueSupport jvs) { + var pathParts = new ArrayList(); + var jp = new JsonPath(jvs.offset(), jvs.doc()); + var path = jp.parseToRoot(pathParts); + // After path is produced, line and pos should be value bearing + return String.format(Locale.ROOT, + " Path: \"%s\". Location: line %d, position %d.", + path, jp.line, jp.pos); + } + + private String parseToRoot(List pathParts) { + toPath(offset, pathParts); + // If no new line encountered, pos is the starting offset value + if (line == 0) { + pos = offset; + } + return String.join("", pathParts.reversed()); + } + + private void addLine(int curr) { + line++; + if (line == 1) { + pos = offset - curr - 1; + } + } + + // List is populated upon completion. It contains the path + // to the root in reverse order. + private void toPath(int offset, List pathParts) { + // Walk past starting char and white space + offset = walkWhitespace(offset - 1); + // If offset is -1, we found the root and are finished + while (offset > -1) { + // Node case + offset = switch (doc[offset]) { + // Does the actual appending + // Walks to the node's starting [ or { + case ',', '[' -> arrayNode(offset, pathParts); + case ':' -> objectNode(offset, pathParts); + default -> throw new InternalError(); + }; + offset = walkWhitespace(offset - 1); + } + } + + private int walkWhitespace(int offset) { + while (offset >= 0) { + var ws = switch (doc[offset]) { + case ' ', '\t', '\r' -> true; + case '\n' -> { + addLine(offset); + yield true; + } + default -> false; + }; + if (!ws) { + break; + } + offset--; + } + return offset; + } + + // Backtracking from an element in a JsonArray either expects a ',' or '[' + // E.g. " [ val ... " or " [ foo, val " + private int arrayNode(int offset, List pathParts) { + int aDepth = 0; + int oDepth = 0; + int values = 0; + boolean inString = false; + while (offset > 0) { + var c = doc[offset]; + if (inString) { + if (c == '"' && doc[offset - 1] != '\\') { + inString = false; + } + } else { + if (c == '[') { + aDepth++; + } else if (c == ']') { + aDepth--; + } else if (c == '{') { + oDepth++; + } else if (c == '}') { + oDepth--; + } else if (c == ',' && aDepth == 0 && oDepth == 0) { + values++; + } else if (c == '"') { + inString = true; + } else if (c == '\n') { + addLine(offset); + } + if (aDepth > 0) { + break; + } + } + offset--; + } + pathParts.add('[' + String.valueOf(values)); + return offset; + } + + // Unlike arrayNode, always expects a ':' + // Regardless of value position, always preceded by a member name and colon + private int objectNode(int offset, List pathParts) { + offset--; // Walk past ':' + int depth = 0; + int nameStart = 0; + int nameEnd = 0; + boolean inName = false; + + // Append member name first + while (offset > 0) { + var c = doc[offset]; + if (c == '"' && !inName) { + nameEnd = offset; + inName = true; + } else if (c == '"' && doc[offset - 1] != '\\') { + // Pre-escape check should not throw AIOOBE because guaranteed + // to have enclosing opening bracket + nameStart = offset + 1; + offset--; // Walk past quote + break; + } + offset--; + } + + // Add the name + pathParts.add('{' + new String(doc, nameStart, nameEnd - nameStart)); + + boolean inString = false; + // Move to parent offset + while (offset > 0) { + var c = doc[offset]; + if (inString) { + if (c == '"' && doc[offset - 1] != '\\') { + inString = false; + } + } else { + if (c == '{') { + depth++; + } else if (c == '}') { + depth--; + } else if (c == '"') { + inString = true; + } else if (c == '\n') { + addLine(offset); + } + if (depth > 0) { + break; + } + } + offset--; + } + return offset; + } + } +} diff --git a/src/jdk.incubator.json/share/classes/jdk/incubator/json/package-info.java b/src/jdk.incubator.json/share/classes/jdk/incubator/json/package-info.java new file mode 100644 index 000000000000..f6fd93c7f6b2 --- /dev/null +++ b/src/jdk.incubator.json/share/classes/jdk/incubator/json/package-info.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2025, 2026, 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. + */ + +/** + * This API supports processing of JSON text in a simple manner. It is organized around the {@link + * JsonValue} interface which represents a JSON value, and the {@link Json} class which provides + * methods to parse and generate JSON text. Typical usage of this API involves first + * {@linkplain ##parsing parsing} JSON text into a {@code JsonValue}, {@linkplain ##access navigating} + * the parsed JSON value to the desired JSON value using access methods, and lastly + * {@linkplain ##conversion converting} the desired value using a conversion method. + * For example: + * {@snippet lang = java: + * List providers = Json.parse(text) + * .get("providers") // access + * .asList(); // conversion + * } + * + *

      Parsing JSON text

      + * Parsing JSON text can be done using either {@link Json#parse(java.lang.String)} or {@link Json#parse(char[])}. + * {@snippet lang = java: + * JsonValue json = Json.parse(text); + * } + * A successful parse indicates that the JSON text adheres to the JSON grammar. + * Unsuccessful parsing throws a {@link JsonParseException}, which provides a detail message that includes + * error details, a path to the root of the JSON text, and its location within the text. + * The parsing APIs do not accept JSON text that contains JSON objects with duplicate member names. + *

      + * The result of a successful parse is a {@code JsonValue}. The {@code JsonValue} interface has six + * sub-interfaces: {@link JsonString}, {@link JsonNumber}, {@link JsonBoolean}, {@link JsonNull}, + * {@link JsonObject}, and {@link JsonArray}. Each sub-interface corresponds to one of the elements of + * JSON syntax. This type hierarchy allows you to use pattern matching to determine the subtype + * of a {@code JsonValue}. {@code JsonValue} instances are immutable and thread safe. + * + *

      Navigating JSON text

      + * Once you have obtained a {@code JsonValue} from parsing, use the access methods to navigate + * through JSON structural elements. {@link JsonValue#get(String)} is provided for JSON objects and {@link + * JsonValue#get(int)} for JSON arrays. + * Given the JSON text: + * {@snippet lang=java: + * JsonValue json = Json.parse(""" + * { "providers": [ "SUN", "SunRsaSign", "SunEC" ], "version": 1 } + * """); + * } + * the JSON string "SUN" can be accessed as follows: + * {@snippet lang=java: + * JsonValue firstProvider = json.get("providers").get(0); + * } + * If an access method is invoked on an incompatible JSON type, for example, + * calling {@code get(String)} on a JSON array, a {@link JsonValueException} + * is thrown. + * + *

      Handling optional members

      + * A member of a JSON object can be optional. In this scenario, use the access method + * {@link JsonValue#tryGet(String)} which returns an {@code Optional} of {@code JsonValue}. + * For example: + * {@snippet lang=java: + * json.tryGet("providers") + * .ifPresent(IO::println); + * } + * This example only prints the value if the member named "providers" exists. + * + *

      Handling null values

      + * Sometimes, JSON null is used to signify absence of a member. + * In this scenario, use the access method {@link JsonValue#tryValue()} which returns an + * {@code Optional} of {@code JsonValue}. For example: + * {@snippet lang=java: + * json.get("providers") + * .tryValue() + * .ifPresent(IO::println); + * } + * This example only prints the value if the member named "providers" is not a JSON + * null. + * + *

      Handling variance in type or structure

      + * If the type for a JSON value is variable, it can be handled as follows: + * {@snippet lang = java: + * String firstProvider = switch (json.get("providers")) { + * case JsonString js -> js.asString(); // handle the value as JSON string + * case JsonArray ja -> ja.get(0).asString(); // handle the value as JSON array + * default -> throw new JsonValueException("unexpected type"); + * } + * } + * While the code above throws an exception if the type is neither {@code JsonString} nor + * {@code JsonArray}, there are times when you may prefer a fallback value instead. + * For example: + * {@snippet lang = java: + * String firstProvider = Optional.of(json) + * .filter(j -> j instanceof JsonObject) + * .flatMap(j -> j.tryGet("providers")) + * .filter(j -> j instanceof JsonString) + * .map(JsonValue::asString) + * .orElse("none"); + * } + * This code ensures that if the root JSON value is not an object, + * the member "providers" does not exist, or if the value of "providers" is not a JSON String, + * then the {@code "none"} fallback value is used over throwing an exception. + * + *

      Converting JSON values to Java values

      + * Once you have navigated to your desired {@code JsonValue}, use the conversion methods to produce + * a corresponding Java value. Each conversion method requires a particular JSON type: + *
        + *
      • {@link JsonValue#asString() asString()} converts a {@code JsonString} instance into a Java + * {@code String} with RFC 8259 + * JSON escape sequences translated to their corresponding characters.
      • + *
      • {@link JsonValue#asInt() asInt()} converts a {@code JsonNumber} instance to a Java + * {@code int} if its numeric value can be represented exactly.
      • + *
      • {@link JsonValue#asLong() asLong()} converts a {@code JsonNumber} instance to a Java + * {@code long} if its numeric value can be represented exactly.
      • + *
      • {@link JsonValue#asDouble() asDouble()} converts a {@code JsonNumber} instance to a Java + * {@code double} if its numeric value can be rounded to a finite Java {@code double}.
      • + *
      • {@link JsonValue#asBoolean() asBoolean()} converts a {@code JsonBoolean} instance to a Java + * {@code boolean} value of {@code true} or {@code false}.
      • + *
      • {@link JsonValue#asMap() asMap()} converts a {@code JsonObject} instance into an + * unmodifiable Java {@code Map}. If the JSON object contains no members, an + * empty {@code Map} is returned.
      • + *
      • {@link JsonValue#asList() asList()} converts a {@code JsonArray} instance into an + * unmodifiable Java {@code List}. If the JSON array contains no elements, + * an empty {@code List} is returned.
      • + *
      + * For example: + * {@snippet lang=java: + * String sun = firstProvider.asString(); + * } + * The code above retrieves the Java String {@code "SUN"} from the JSON value {@code firstProvider}. + * If an incorrect conversion method is used, which does not correspond to the matching + * JSON type, for example {@code firstProvider.asBoolean()}, a {@code JsonValueException} is thrown. + *

      + * Most conversion methods always return a value when the {@code JsonValue} is + * of the correct JSON type. The exceptions are {@code asInt()}, {@code asLong()}, + * and {@code asDouble()}; they may throw a {@code JsonValueException} even + * when the {@code JsonValue} is a JSON number, for example if it is outside + * their supported ranges. + * + *

      Generating JSON text

      + * Generating JSON text is performed with either {@link + * JsonValue#toString()} or {@link Json#toDisplayString(JsonValue, String)}. + * These methods produce String representations of a {@code JsonValue} that adhere + * to the JSON grammar defined in RFC 8259. + * {@code JsonValue.toString()} produces compact JSON text which does not + * include JSON insignificant whitespace, preferable for network transmission + * or storage. For example: + * {@snippet lang=json: + * {"providers":["SUN","SunRsaSign","SunEC"],"version":1} + * } + * {@code Json.toDisplayString(JsonValue, String)} produces pretty-printed + * JSON text which is easier to read, preferable for debugging or logging. + * For example: + * {@snippet lang=json: + * { + * "providers": [ + * "SUN", + * "SunRsaSign", + * "SunEC" + * ], + * "version": 1 + * } + * } + * + * @spec https://datatracker.ietf.org/doc/html/rfc8259 RFC 8259: The JavaScript + * Object Notation (JSON) Data Interchange Format + * @since 28 + */ +package jdk.incubator.json; diff --git a/src/jdk.incubator.json/share/classes/module-info.java b/src/jdk.incubator.json/share/classes/module-info.java new file mode 100644 index 000000000000..95cb7c4710c5 --- /dev/null +++ b/src/jdk.incubator.json/share/classes/module-info.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025, 2026, 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. + */ + +import jdk.internal.javac.ParticipatesInPreview; + +/** + * Defines the JSON API. See the {@link jdk.incubator.json/jdk.incubator.json} + * package specification for an overview of the API. + * + * {@incubating} + * + * @moduleGraph + */ +@ParticipatesInPreview +module jdk.incubator.json { + exports jdk.incubator.json; +} diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java index 2d770a723ad0..1ec76300a593 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java @@ -2020,6 +2020,7 @@ M testTemplate(Class maskType, Test op) { m = compare(LT, (byte) 0); } else { + int opc = opCode(op); throw new AssertionError(op); } return maskType.cast(m); @@ -2051,6 +2052,7 @@ M testTemplate(Class maskType, Test op, M mask) { m = compare(LT, (byte) 0, m); } else { + int opc = opCode(op); throw new AssertionError(op); } return maskType.cast(m); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java index bda32bed969e..c4c41a609f9c 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java @@ -1853,6 +1853,7 @@ else if (op == IS_FINITE || } } else { + int opc = opCode(op); throw new AssertionError(op); } return maskType.cast(m.cast(vsp)); @@ -1901,6 +1902,7 @@ else if (op == IS_FINITE || } } else { + int opc = opCode(op); throw new AssertionError(op); } return maskType.cast(m.cast(vsp)); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16Vector.java index 708ded947d55..04eccf4a73a6 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16Vector.java @@ -1939,6 +1939,7 @@ else if (op == IS_FINITE || } } else { + int opc = opCode(op); throw new AssertionError(op); } return maskType.cast(m.cast(vsp)); @@ -1987,6 +1988,7 @@ else if (op == IS_FINITE || } } else { + int opc = opCode(op); throw new AssertionError(op); } return maskType.cast(m.cast(vsp)); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java index 775e939de2bf..c1c9cda44506 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java @@ -1865,6 +1865,7 @@ else if (op == IS_FINITE || } } else { + int opc = opCode(op); throw new AssertionError(op); } return maskType.cast(m.cast(vsp)); @@ -1913,6 +1914,7 @@ else if (op == IS_FINITE || } } else { + int opc = opCode(op); throw new AssertionError(op); } return maskType.cast(m.cast(vsp)); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java index f1218112be56..00f72927be4b 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java @@ -2005,6 +2005,7 @@ M testTemplate(Class maskType, Test op) { m = compare(LT, (int) 0); } else { + int opc = opCode(op); throw new AssertionError(op); } return maskType.cast(m); @@ -2036,6 +2037,7 @@ M testTemplate(Class maskType, Test op, M mask) { m = compare(LT, (int) 0, m); } else { + int opc = opCode(op); throw new AssertionError(op); } return maskType.cast(m); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java index 7682616b9843..ca033b29a84a 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java @@ -1918,6 +1918,7 @@ M testTemplate(Class maskType, Test op) { m = compare(LT, (long) 0); } else { + int opc = opCode(op); throw new AssertionError(op); } return maskType.cast(m); @@ -1949,6 +1950,7 @@ M testTemplate(Class maskType, Test op, M mask) { m = compare(LT, (long) 0, m); } else { + int opc = opCode(op); throw new AssertionError(op); } return maskType.cast(m); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java index ac381330e319..a25b83809500 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java @@ -2021,6 +2021,7 @@ M testTemplate(Class maskType, Test op) { m = compare(LT, (short) 0); } else { + int opc = opCode(op); throw new AssertionError(op); } return maskType.cast(m); @@ -2052,6 +2053,7 @@ M testTemplate(Class maskType, Test op, M mask) { m = compare(LT, (short) 0, m); } else { + int opc = opCode(op); throw new AssertionError(op); } return maskType.cast(m); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java index 1bffb8d22389..747c28ad7172 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java @@ -2774,6 +2774,8 @@ public abstract long reduceLanesToLong(VectorOperators.Associative op, * @param op the operation used to test lane values * @return the mask result of testing the lanes of this vector, * according to the selected test operator + * @throws UnsupportedOperationException if this vector does + * not support the requested operation * @see VectorOperators.Comparison * @see #test(VectorOperators.Test, VectorMask) * @see #compare(VectorOperators.Comparison, Vector) @@ -2796,6 +2798,8 @@ public abstract long reduceLanesToLong(VectorOperators.Associative op, * @return the mask result of testing the lanes of this vector, * according to the selected test operator, * and only in the lanes selected by the mask + * @throws UnsupportedOperationException if this vector does + * not support the requested operation * @see #test(VectorOperators.Test) */ public abstract VectorMask test(VectorOperators.Test op, diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template index bfc8ce3dfeaa..aa5be562a65d 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template @@ -2545,6 +2545,7 @@ public abstract sealed class $abstractvectortype$ extends AbstractVector<$Boxtyp } #end[FP] else { + int opc = opCode(op); throw new AssertionError(op); } return maskType.cast(m{#if[FP]?.cast(vsp)}); @@ -2599,6 +2600,7 @@ public abstract sealed class $abstractvectortype$ extends AbstractVector<$Boxtyp } #end[FP] else { + int opc = opCode(op); throw new AssertionError(op); } return maskType.cast(m{#if[FP]?.cast(vsp)}); diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java b/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java index 88f42b27142c..779ceb43bf45 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java @@ -425,7 +425,7 @@ List ownedMonitorsAndFrames() * statement. *

      * The method which will return early is referred to as the - * called method. The called method is the current method (as + * called method. The called method is the current method (as * defined by the Frames section in the Java Virtual Machine * Specification) for the specified thread at the time this * method is called. @@ -436,28 +436,35 @@ List ownedMonitorsAndFrames() * this method and resumption of thread execution, the * state of the stack is undefined. *

      - * This method may be used to force a return from the current frame - * of a virtual thread when it is suspended at an event. - * An implementation may support forcing a return from the current frame - * of a suspended virtual thread in other cases. + * When the thread is a {@link Thread##virtual-threads virtual thread}, this + * method may be used to force a return when the virtual thread is suspended + * at an event. The target VM may support forcing a return when the virtual + * thread is suspended in other cases. *

      - * No further instructions are executed in the called - * method. Specifically, finally blocks are not executed. Note: + * This method may not be used to force a return when the called method is: + *

        + *
      • A native method.
      • + *
      • A constructor of a class with {@linkplain + * java.lang.reflect.Field#isStrictInit() strictly-initialized} instance fields + * declared in the class or any of its superclasses.
      • + *
      • The class initializer of a class with strictly-initialized static fields.
      • + *
      + *

      + * If this method succeeds then the thread does not execute any further instructions + * in the called method. Specifically, {@code finally} blocks are not executed. Note: * this can cause inconsistent states in the application. *

      * A lock acquired by calling the called method (if it is a - * synchronized method) and locks acquired by entering - * synchronized blocks within the called method are + * {@code synchronized} method) and locks acquired by entering + * {@code synchronized} blocks within the called method are * released. Note: this does not apply to native locks or - * java.util.concurrent.locks locks. + * {@link java.util.concurrent.locks} locks. *

      - * Events, such as MethodExit, are generated as they would be in - * a normal return. + * Events, such as {@link com.sun.jdi.event.MethodExitEvent}, are generated as they + * would be in a normal return. *

      - * The called method must not be a native method or the constructor of - * a {@linkplain Class#isValue() value class}. Forcing early return - * on a thread with only one frame on the stack causes the thread to - * exit when resumed. + * Forcing early return on a thread with only one frame on the stack causes the + * thread to exit when resumed. *

      * The value argument is the value that the * method is to return. diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java index ee75e8ee36c5..46bb82851784 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java @@ -42,6 +42,7 @@ import jdk.jpackage.internal.Codesign.CodesignException; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.ApplicationLayout.Directory; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.MacApplication; import jdk.jpackage.internal.model.RuntimeLayout; @@ -173,7 +174,7 @@ private static Set ensureCanWrite(Path path) { } private static IOException handleCodesignException(MacApplication app, CodesignException ex) { - if (!app.contentDirSources().isEmpty()) { + if (app.filterUserContent(Directory.CONTENT_DIR).findAny().isPresent()) { // Additional content may cause signing error. Log.progressWarning(I18N.getString("message.codesign.failed.reason.app.content")); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java index 64420d30983f..aad96c7ab1e2 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java @@ -45,6 +45,7 @@ import jdk.jpackage.internal.model.AppImageSigningConfig; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLaunchers; +import jdk.jpackage.internal.model.ApplicationLayout.Directory; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.ExternalApplication; import jdk.jpackage.internal.model.JPackageException; @@ -54,9 +55,9 @@ import jdk.jpackage.internal.summary.StandardWarning; import jdk.jpackage.internal.summary.StandardProperty; import jdk.jpackage.internal.summary.SummaryAccumulator; +import jdk.jpackage.internal.util.ExplodedPath; import jdk.jpackage.internal.util.PListReader; import jdk.jpackage.internal.util.Result; -import jdk.jpackage.internal.util.RootedPath; final class MacApplicationBuilder { @@ -174,9 +175,11 @@ private static void validateAppVersion(Application app) { } private static Stream appContentTopPaths(Application app) { - return app.contentDirSources().stream().filter(rootedPath -> { - return rootedPath.branch().getNameCount() == 1; - }).map(RootedPath::fullPath); + return app.filterUserContent(Directory.CONTENT_DIR).flatMap(explodedPath -> { + return explodedPath.children().stream().map(ExplodedPath.Node::path).filter(childPath -> { + return childPath.getNameCount() == 1; + }).map(explodedPath.root()::resolve); + }); } private static void validateAppContentDirs(SummaryAccumulator summary, Application app) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java index b9e407b4a475..c3ad7f372510 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackageBuilder.java @@ -31,7 +31,7 @@ import java.util.Optional; import jdk.jpackage.internal.model.MacDmgPackage; import jdk.jpackage.internal.model.MacDmgPackageMixin; -import jdk.jpackage.internal.util.RootedPath; +import jdk.jpackage.internal.util.ExplodedPath; final class MacDmgPackageBuilder { @@ -39,7 +39,7 @@ final class MacDmgPackageBuilder { this.pkgBuilder = Objects.requireNonNull(pkgBuilder); } - MacDmgPackageBuilder dmgRootDirSources(Collection v) { + MacDmgPackageBuilder dmgRootDirSources(Collection v) { dmgRootDirSources = v; return this; } @@ -49,7 +49,7 @@ MacDmgPackageBuilder icon(Path v) { return this; } - private Collection validatedDmgRootDirSources() { + private Collection validatedDmgRootDirSources() { return Optional.ofNullable(dmgRootDirSources).orElseGet(List::of); } @@ -62,6 +62,6 @@ MacDmgPackage create() { } private Path icon; - private Collection dmgRootDirSources; + private Collection dmgRootDirSources; private final MacPackageBuilder pkgBuilder; } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java index 8ebfdd62cd73..9435c4c69ad8 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java @@ -43,9 +43,9 @@ import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; import jdk.jpackage.internal.PackagingPipeline.TaskID; import jdk.jpackage.internal.model.MacDmgPackage; +import jdk.jpackage.internal.util.ExplodedPath; import jdk.jpackage.internal.util.FileUtils; import jdk.jpackage.internal.util.PathGroup; -import jdk.jpackage.internal.util.RootedPath; record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, MacDmgSystemEnvironment sysEnv) implements Consumer { @@ -128,8 +128,10 @@ private Path dmgWorkdir() { } private void copyDmgContent() throws IOException { - final var srcFolder = env.appImageDir(); - RootedPath.copy(pkg.dmgRootDirSources().stream(), srcFolder); + final var dstFolder = env.appImageDir(); + ExplodedPath.copy(pkg.dmgRootDirSources().stream().map(v -> { + return ExplodedPath.copySpec(v, dstFolder); + }).toList()); } private Executor hdiutil(String... args) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java index e4a651ce9160..ad85150cebad 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java @@ -51,7 +51,6 @@ import static jdk.jpackage.internal.util.function.ExceptionBox.toUnchecked; import java.nio.file.Path; -import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -75,7 +74,6 @@ import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.model.RuntimeLayout; import jdk.jpackage.internal.util.MacBundle; -import jdk.jpackage.internal.util.RootedPath; import jdk.jpackage.internal.util.Slot; import jdk.jpackage.internal.util.function.ExceptionBox; @@ -94,14 +92,12 @@ static MacDmgPackage createMacDmgPackage(Options options) { final var pkgBuilder = new MacDmgPackageBuilder(superPkgBuilder); - MAC_DMG_CONTENT.findIn(options).map((List> v) -> { - // Reverse the order of content sources. - // If there are multiple source files for the same - // destination file, only the first will be used. - // Reversing the order of content sources makes it use the last file - // from the original list of source files for the given destination file. - return v.reversed().stream().flatMap(Collection::stream).toList(); - }).ifPresent(pkgBuilder::dmgRootDirSources); + // Reverse the order of content sources. + // If there are multiple source files for the same + // destination file, only the first will be used. + // Reversing the order of content sources makes it use the last file + // from the original list of source files for the given destination file. + MAC_DMG_CONTENT.findIn(options).map(List::reversed).ifPresent(pkgBuilder::dmgRootDirSources); return pkgBuilder.create(); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackageMixin.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackageMixin.java index 08797b115094..7506e9eea5e6 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackageMixin.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/model/MacDmgPackageMixin.java @@ -27,7 +27,7 @@ import java.nio.file.Path; import java.util.Collection; import java.util.Optional; -import jdk.jpackage.internal.util.RootedPath; +import jdk.jpackage.internal.util.ExplodedPath; public interface MacDmgPackageMixin { @@ -40,8 +40,8 @@ public interface MacDmgPackageMixin { * * @return the source paths of additional top-level content for DMG package */ - Collection dmgRootDirSources(); + Collection dmgRootDirSources(); - record Stub(Optional icon, Collection dmgRootDirSources) implements MacDmgPackageMixin { + record Stub(Optional icon, Collection dmgRootDirSources) implements MacDmgPackageMixin { } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index cd0ff8d0da2a..537001ab4504 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -27,6 +27,7 @@ import static jdk.jpackage.internal.I18N.buildConfigException; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; @@ -38,6 +39,7 @@ import java.util.function.Predicate; import java.util.function.UnaryOperator; import jdk.jpackage.internal.model.AppImageLayout; +import jdk.jpackage.internal.model.AppImageLayout.DirectorySelector; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLaunchers; import jdk.jpackage.internal.model.ExternalApplication; @@ -48,12 +50,13 @@ import jdk.jpackage.internal.model.ResourceDirLauncherIcon; import jdk.jpackage.internal.model.RuntimeBuilder; import jdk.jpackage.internal.model.RuntimeLayout; -import jdk.jpackage.internal.util.RootedPath; +import jdk.jpackage.internal.util.ExplodedPath; import jdk.jpackage.internal.util.RuntimeReleaseFile; final class ApplicationBuilder { ApplicationBuilder() { + userContent = new ArrayList<>(); } ApplicationBuilder(ApplicationBuilder other) { @@ -62,10 +65,8 @@ final class ApplicationBuilder { version = other.version; vendor = other.vendor; copyright = other.copyright; - appDirSources = other.appDirSources; + userContent = new ArrayList<>(other.userContent); externalApp = other.externalApp; - contentDirSources = other.contentDirSources; - resourcesDirSources = other.resourcesDirSources; appImageLayout = other.appImageLayout; runtimeBuilder = other.runtimeBuilder; launchers = other.launchers; @@ -95,9 +96,7 @@ Application create() { validatedVersion(), Optional.ofNullable(vendor).orElseGet(DEFAULTS::vendor), Optional.ofNullable(copyright).orElseGet(DEFAULTS::copyright), - Optional.ofNullable(appDirSources).orElseGet(List::of), - Optional.ofNullable(contentDirSources).orElseGet(List::of), - Optional.ofNullable(resourcesDirSources).orElseGet(List::of), + List.copyOf(userContent), appImageLayout, Optional.ofNullable(runtimeBuilder), launchersAsList, @@ -171,18 +170,16 @@ ApplicationBuilder copyright(String v) { return this; } - ApplicationBuilder appDirSources(Collection v) { - appDirSources = v; + ApplicationBuilder addUserContent(ExplodedPath source, DirectorySelector dest) { + userContent.add(Map.entry(source, dest)); return this; } - ApplicationBuilder contentDirSources(Collection v) { - contentDirSources = v; - return this; - } - - ApplicationBuilder resourcesDirSources(Collection v) { - resourcesDirSources = v; + ApplicationBuilder addUserContent(List sources, DirectorySelector dest) { + Objects.requireNonNull(dest); + sources.reversed().forEach(source -> { + addUserContent(source, dest); + }); return this; } @@ -344,9 +341,7 @@ static Application overrideAppImageLayout(Application app, AppImageLayout appIma app.version(), app.vendor(), app.copyright(), - app.appDirSources(), - app.contentDirSources(), - app.resourcesDirSources(), + app.userContent(), Objects.requireNonNull(appImageLayout), app.runtimeBuilder(), app.launchers(), @@ -393,10 +388,8 @@ String copyright() { private String version; private String vendor; private String copyright; - private Collection appDirSources; + private Collection> userContent; private ExternalApplication externalApp; - private Collection contentDirSources; - private Collection resourcesDirSources; private AppImageLayout appImageLayout; private RuntimeBuilder runtimeBuilder; private ApplicationLaunchers launchers; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java index 8a42004da3a5..1500aaf2ca72 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationImageUtils.java @@ -29,8 +29,6 @@ import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.StandardCopyOption; -import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.function.Function; import jdk.jpackage.internal.PackagingPipeline.ApplicationImageTaskAction; @@ -40,7 +38,7 @@ import jdk.jpackage.internal.model.DefaultLauncherIcon; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.ResourceDirLauncherIcon; -import jdk.jpackage.internal.util.RootedPath; +import jdk.jpackage.internal.util.ExplodedPath; final class ApplicationImageUtils { @@ -83,14 +81,9 @@ static ApplicationImageTaskAction createWriteApp static ApplicationImageTaskAction createCopyContentAction() { return env -> { - for (var e : List.of( - Map.entry(env.app().appDirSources(), env.resolvedLayout().appDirectory()), - Map.entry(env.app().resourcesDirSources(), env.resolvedLayout().resourcesDirectory()), - Map.entry(env.app().contentDirSources(), env.resolvedLayout().contentDirectory()) - )) { - RootedPath.copy(e.getKey().stream(), e.getValue(), - StandardCopyOption.REPLACE_EXISTING, LinkOption.NOFOLLOW_LINKS); - } + ExplodedPath.copy(env.app().userContent().stream().map(spec -> { + return ExplodedPath.copySpec(spec.getKey(), spec.getValue().resolve(env.resolvedLayout())); + }).toList(), StandardCopyOption.REPLACE_EXISTING, LinkOption.NOFOLLOW_LINKS); }; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java index f2b2290d9c15..698fd7b48c72 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromOptions.java @@ -47,7 +47,6 @@ import static jdk.jpackage.internal.cli.StandardOption.VENDOR; import java.nio.file.Path; -import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Objects; @@ -59,10 +58,10 @@ import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLaunchers; import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.ApplicationLayout.Directory; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.PackageType; import jdk.jpackage.internal.model.RuntimeLayout; -import jdk.jpackage.internal.util.RootedPath; import jdk.jpackage.internal.util.RuntimeReleaseFile; final class FromOptions { @@ -179,19 +178,26 @@ private static ApplicationBuilder createApplicationBuilder( APP_VERSION.ifPresentIn(options, appBuilder::version); VENDOR.ifPresentIn(options, appBuilder::vendor); COPYRIGHT.ifPresentIn(options, appBuilder::copyright); - INPUT.ifPresentIn(options, appBuilder::appDirSources); - APP_CONTENT.findIn(options).map((List> v) -> { - // Reverse the order of content sources. - // If there are multiple source files for the same - // destination file, only the first will be used. - // Reversing the order of content sources makes it use the last file - // from the original list of source files for the given destination file. - return v.reversed().stream().flatMap(Collection::stream).toList(); - }).ifPresent(appBuilder::contentDirSources); - APP_RESOURCES.findIn(options).map((List> v) -> { - return v.reversed().stream().flatMap(Collection::stream).toList(); - }).ifPresent(appBuilder::resourcesDirSources); + // The order of processing APP_CONTENT, APP_RESOURCES and INPUT options is important! + // These options specify content to be copied in the application image. + // The order in which the content from different sources is copied is important + // when multiple sources route to the same destination file. + // In the case of such ambiguity, the implementation uses the first source and ignores others. + // We want files/directories in the APP_CONTENT option to override those in + // the APP_RESOURCES option and files/directories in the APP_CONTENT and APP_RESOURCES options + // to override those in the INPUT option. + APP_CONTENT.ifPresentIn(options, v -> { + appBuilder.addUserContent(v, Directory.CONTENT_DIR); + }); + + APP_RESOURCES.ifPresentIn(options, v -> { + appBuilder.addUserContent(v, Directory.RESOURCES_DIR); + }); + + INPUT.ifPresentIn(options, v -> { + appBuilder.addUserContent(v, Directory.APP_DIR); + }); if (isRuntimeInstaller) { appBuilder.appImageLayout(runtimeLayout); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromOptions.java index 1ba384dba2d3..e59e643a0bba 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromOptions.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherFromOptions.java @@ -56,7 +56,7 @@ import jdk.jpackage.internal.model.FileAssociation; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.LauncherIcon; -import jdk.jpackage.internal.util.RootedPath; +import jdk.jpackage.internal.util.ExplodedPath; final class LauncherFromOptions { @@ -93,9 +93,7 @@ Launcher create(Options options) { if (PREDEFINED_APP_IMAGE.findIn(options).isEmpty()) { final var startupInfoBuilder = new LauncherStartupInfoBuilder(); - INPUT.findIn(options).flatMap(v -> { - return v.stream().findAny().map(RootedPath::root); - }).ifPresent(startupInfoBuilder::inputDir); + INPUT.findIn(options).map(ExplodedPath::root).ifPresent(startupInfoBuilder::inputDir); ARGUMENTS.ifPresentIn(options, startupInfoBuilder::defaultParameters); JAVA_OPTIONS.ifPresentIn(options, startupInfoBuilder::javaOptions); MAIN_JAR.ifPresentIn(options, startupInfoBuilder::mainJar); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java index 2fde8ebb3f24..1c74c7fb12ba 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java @@ -45,7 +45,6 @@ import java.nio.file.Path; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Set; @@ -66,8 +65,8 @@ import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.LauncherShortcut; import jdk.jpackage.internal.model.LauncherShortcutStartupDirectory; -import jdk.jpackage.internal.util.RootedPath; import jdk.jpackage.internal.model.SelfContainedException; +import jdk.jpackage.internal.util.ExplodedPath; import jdk.jpackage.internal.util.SetBuilder; import jdk.jpackage.internal.log.LogEnvironment; @@ -134,12 +133,10 @@ enum LauncherProperty implements OptionScope { }); })).create(); - public static final OptionValue> INPUT = directoryOption("input").addAliases("i") + public static final OptionValue INPUT = directoryOption("input").addAliases("i") .outOfScope(NOT_BUILDING_APP_IMAGE) .map(explodedPathOptionMapper(explodedPathConverter().create())) - .create(optionValueBuilder -> { - return optionValueBuilder.to(List::of).create(); - }); + .create(); public static final OptionValue DEST = directoryOption("dest").addAliases("d") .valuePattern("destination path") @@ -210,7 +207,7 @@ public boolean test(Path path) { .inScope(LauncherProperty.VALUE) .createArray(toList()); - public static final OptionValue>> APP_CONTENT = existingPathOption("app-content") + public static final OptionValue> APP_CONTENT = existingPathOption("app-content") .tokenizer(",") .valuePattern("additional content") .outOfScope(NOT_BUILDING_APP_IMAGE) @@ -220,9 +217,9 @@ public boolean test(Path path) { b.description("help.option.app-content" + resourceKeySuffix(context.os())); } })) - .createArray(toExplodedPathList()); + .createArray(toList()); - public static final OptionValue>> APP_RESOURCES = existingPathOption("app-resources") + public static final OptionValue> APP_RESOURCES = existingPathOption("app-resources") .tokenizer(pathSeparator()) .valuePattern("additional resources") .description("help.option.app-resources" + resourceKeySuffix(OperatingSystem.current())) @@ -231,7 +228,7 @@ public boolean test(Path path) { .mutate(createOptionSpecBuilderMutator((b, context) -> { b.description("help.option.app-resources" + resourceKeySuffix(context.os())); })) - .createArray(toExplodedPathList()); + .createArray(toList()); static final OptionValue FILE_ASSOCIATIONS_INTERNAL = fileOption("file-associations") .tokenizer(pathSeparator()) @@ -356,11 +353,11 @@ public boolean test(Path path) { // MacOS-specific // - public static final OptionValue>> MAC_DMG_CONTENT = existingPathOption("mac-dmg-content") + public static final OptionValue> MAC_DMG_CONTENT = existingPathOption("mac-dmg-content") .valuePattern("additional content path") .tokenizer(",") .map(explodedPathOptionMapper(explodedPathConverter().withPathFileName().create())) - .createArray(toExplodedPathList()); + .createArray(toList()); public static final OptionValue MAC_SIGN = booleanOption("mac-sign").scope(MAC_SIGNING).addAliases("s").create(); @@ -637,27 +634,28 @@ static Consumer> launcherShortcutOptionMutat }; } - static Function, OptionSpecBuilder> explodedPathOptionMapper(ValueConverter conv) { + static Function, OptionSpecBuilder> explodedPathOptionMapper(ValueConverter conv) { Objects.requireNonNull(conv); return builder -> { return builder.map(conv) .converterExceptionFactory(ERROR_WITH_VALUE_AND_OPTION_NAME) .converterExceptionFormatString("error.path-parameter-ioexception") // Add empty mutator to OptionSpecMapperOptionScope to make - // mapped option spec have `RootedPath[]` type. + // mapped option spec have `ExplodedPath` type. // Otherwise, it will have `Path` type. .mutate(createOptionSpecBuilderMutator((b, context) -> { })); }; } - private static Function, OptionValue>>> toExplodedPathList() { + private static Consumer> validationErrorWithAdviceMutator(String messageFormatKey, String adviceKey) { + Objects.requireNonNull(messageFormatKey); + Objects.requireNonNull(adviceKey); return builder -> { - return builder.to((RootedPath[][] v) -> { - return Stream.of(v).map(arr -> { - return (Collection)List.of(arr); - }).toList(); - }).create(); + builder.validatorExceptionFactory(OptionValueExceptionFactory.build((message, cause) -> { + return new ConfigException(message, I18N.format(adviceKey), cause); + }).formatArgumentsTransformer(StandardArgumentsMapper.VALUE_AND_NAME).create()); + builder.validatorExceptionFormatString(messageFormatKey); }; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java index b1e1189654d5..ea69ae8a07e4 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardValueConverter.java @@ -26,14 +26,12 @@ package jdk.jpackage.internal.cli; import java.io.IOException; -import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.util.UUID; -import java.util.function.Function; import jdk.jpackage.internal.model.LauncherShortcut; import jdk.jpackage.internal.model.ParseUtils; -import jdk.jpackage.internal.util.RootedPath; +import jdk.jpackage.internal.util.ExplodedPath; final class StandardValueConverter { @@ -73,10 +71,10 @@ static final class ExplodedPathConverterBuilder { private ExplodedPathConverterBuilder() { } - ValueConverter create() { + ValueConverter create() { return ValueConverter.create(path -> { return explodePath(path, withPathFileName); - }, RootedPath[].class); + }, ExplodedPath.class); } ExplodedPathConverterBuilder withPathFileName(boolean v) { @@ -111,23 +109,20 @@ ExplodedPathConverterBuilder withPathFileName() { private static final ValueConverter ADD_LAUNCHER_SHORTCUT_CONV = ValueConverter.create( ParseUtils::parseLauncherShortcutForAddLauncher, LauncherShortcut.class); - private static RootedPath[] explodePath(Path path, boolean withPathFileName) throws Exception { + private static ExplodedPath explodePath(Path path, boolean withPathFileName) throws Exception { - Function mapper; - if (withPathFileName) { - mapper = RootedPath.toRootedPath(path.getParent()); - } else { - mapper = RootedPath.toRootedPath(path); - } - - RootedPath[] items; - try (var walk = Files.walk(path)) { - items = walk.map(mapper).toArray(RootedPath[]::new); + ExplodedPath reply; + try { + reply = ExplodedPath.of(path); } catch (IOException ex) { // IOException is not a converter error, it is a converting error, so map it into IAE. throw new IllegalArgumentException(ex); } - return items; + if (withPathFileName) { + reply = reply.getParent(); + } + + return reply; } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java index a64946c06d03..e27afe13efbd 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/AppImageLayout.java @@ -34,6 +34,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.function.Function; import java.util.function.UnaryOperator; import java.util.stream.Stream; import jdk.jpackage.internal.util.PathGroup; @@ -55,6 +56,27 @@ */ public interface AppImageLayout { + interface DirectorySelector { + Path resolve(AppImageLayout layout); + }; + + enum Directory implements DirectorySelector { + RUNTIME_DIR(AppImageLayout::runtimeDirectory), + ROOT_DIR(AppImageLayout::rootDirectory), + ; + + Directory(Function func) { + this.func = Objects.requireNonNull(func); + } + + @Override + public Path resolve(AppImageLayout target) { + return func.apply(target); + } + + private Function func; + } + /** * A path to Java runtime directory. * The directory should have standard JDK subdirectories like "bin", "lib", etc. diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index 3a594e9f6ae4..d5c6f50fd704 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -29,9 +29,11 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.stream.Stream; -import jdk.jpackage.internal.util.RootedPath; +import jdk.jpackage.internal.model.AppImageLayout.DirectorySelector; +import jdk.jpackage.internal.util.ExplodedPath; /** * A generic application for packaging. @@ -80,34 +82,28 @@ public non-sealed interface Application extends BundleSpec { String copyright(); /** - * Gets the source paths that should be copied into - * {@link ApplicationLayout#appDirectory()} directory of the image of this - * application. + * Gets the configuration for user-supplied paths to copy into the application + * image. *

      - * Source paths are supposed to contain the applications's classes and other - * resources. + * Each item in the collection specifies source paths and the directory in the + * application image where they should be copied. * * @return the source paths */ - Collection appDirSources(); + Collection> userContent(); /** - * Gets the source paths that should be copied into - * {@link ApplicationLayout#contentDirectory()} directory of the image of this - * application. + * Returns user content that should be copied to the given destination directory. + * @param dest the destination directory * - * @return the source paths + * @return the filtered user content */ - Collection contentDirSources(); - - /** - * Gets the source paths that should be copied into - * {@link ApplicationLayout#resourcesDirectory()} directory of the image of this - * application. - * - * @return the source paths - */ - Collection resourcesDirSources(); + default Stream filterUserContent(DirectorySelector dest) { + Objects.requireNonNull(dest); + return userContent().stream().filter(v -> { + return v.getValue() == dest; + }).map(Map.Entry::getKey); + } /** * Gets the unresolved app image layout of this application. @@ -259,9 +255,7 @@ record Stub( String version, String vendor, String copyright, - Collection appDirSources, - Collection contentDirSources, - Collection resourcesDirSources, + Collection> userContent, AppImageLayout imageLayout, Optional runtimeBuilder, List launchers, diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java index e0935cec9304..ed39fee1a389 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationLayout.java @@ -28,6 +28,7 @@ import java.nio.file.Path; import java.util.Objects; +import java.util.function.Function; import java.util.function.UnaryOperator; import jdk.jpackage.internal.util.CompositeProxy; @@ -41,6 +42,27 @@ */ public interface ApplicationLayout extends AppImageLayout, ApplicationLayoutMixin { + enum Directory implements DirectorySelector { + LAUNCHERS_DIR(ApplicationLayout::launchersDirectory), + APP_DIR(ApplicationLayout::appDirectory), + APP_MODULES_DIR(ApplicationLayout::appModsDirectory), + DESKTOP_INTEGRATION_DIR(ApplicationLayout::desktopIntegrationDirectory), + CONTENT_DIR(ApplicationLayout::contentDirectory), + RESOURCES_DIR(ApplicationLayout::resourcesDirectory), + ; + + Directory(Function func) { + this.func = Objects.requireNonNull(func); + } + + @Override + public Path resolve(AppImageLayout target) { + return func.apply((ApplicationLayout)target); + } + + private Function func; + } + @Override default ApplicationLayout resolveAt(Path root) { return (ApplicationLayout)AppImageLayout.super.resolveAt(root); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/ExplodedPath.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/ExplodedPath.java new file mode 100644 index 000000000000..634886e20d6c --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/ExplodedPath.java @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import static java.util.stream.Collectors.toUnmodifiableList; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.CopyOption; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Stream; + +/** + * Exploded directory. + */ +public record ExplodedPath(Path root, Collection children) { + + public ExplodedPath { + Objects.requireNonNull(root); + children.forEach(Objects::requireNonNull); + } + + + public record Node(Path path, boolean isDirectory) { + + public Node { + if (path.isAbsolute()) { + throw new IllegalArgumentException(); + } + } + + public Node copyWithName(Path path) { + return new Node(path, isDirectory()); + } + } + + + public record CopySpec(ExplodedPath source, Path dest) { + + public CopySpec { + Objects.requireNonNull(source); + Objects.requireNonNull(dest); + } + + Stream copyPathSpecs() { + return source.copyPathSpecs(dest); + } + } + + + public ExplodedPath getParent() { + var basename = root.getFileName(); + return new ExplodedPath(root.getParent(), children.stream().map(n -> { + return n.copyWithName(basename.resolve(n.path())); + }).collect(toUnmodifiableList())); + } + + private Stream copyPathSpecs(Path dest) { + Objects.requireNonNull(dest); + return children.stream().sorted(Comparator.comparing(Node::path)).map(child -> { + return new CopyPathSpec(root, child, dest); + }); + } + + public static ExplodedPath of(Path root) throws IOException { + try (var walk = Files.walk(root)) { + return new ExplodedPath(root, walk.map(path -> { + return new Node(root.relativize(path), Files.isDirectory(path)); + }).collect(toUnmodifiableList())); + } + } + + public static CopySpec copySpec(ExplodedPath source, Path dest) { + return new CopySpec(source, dest); + } + + public static void copy(List specs, CopyOption...options) throws IOException { + Objects.requireNonNull(specs); + + var marks = new HashMap(); + + // Preset marks for the preexisting paths. + for (var spec : specs) { + Files.walkFileTree(spec.dest(), new FileVisitor() { + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + marks.put(dir, new PathMark(true, true)); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + marks.put(file, new PathMark(false, true)); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { + return FileVisitResult.TERMINATE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + return FileVisitResult.CONTINUE; + } + + }); + } + + var replacePreexisting = Set.of(options).contains(StandardCopyOption.REPLACE_EXISTING); + + Predicate canReplace = v -> { + return v.isPreexisting() && replacePreexisting; + }; + + try { + specs.stream().flatMap(CopySpec::copyPathSpecs).forEach(spec -> { + + final var dstPathMark = marks.get(spec.resolvedDstPath()); + + if (!Optional.ofNullable(dstPathMark).map(canReplace::test).orElse(true)) { + // Destination path can not be replaced, bail out. + return; + } + + // Check the ancestors of the destination path. + for (var ancestor : ancestorPaths(spec.child().path())) { + var mark = Optional.ofNullable(marks.get(spec.destRoot().resolve(ancestor))); + + if (!mark.map(PathMark::isDirectory).orElse(true)) { + // `ancestor` is a file, don't overwrite it. + return; + } + } + + marks.put(spec.resolvedDstPath(), spec.createPathMark()); + + try { + if (dstPathMark != null && replacePreexisting && (spec.child().isDirectory() != dstPathMark.isDirectory())) { + FileUtils.deleteRecursive(spec.resolvedDstPath()); + } + + if (spec.child().isDirectory()) { + Files.createDirectories(spec.resolvedDstPath()); + } else { + Files.createDirectories(spec.resolvedDstPath().getParent()); + Files.copy(spec.resolvedSrcPath(), spec.resolvedDstPath(), options); + } + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }); + } catch (UncheckedIOException ex) { + throw ex.getCause(); + } + } + + private static Collection ancestorPaths(Path path) { + var ancestors = new ArrayList(); + + if (!EMPTY_PATH.equals(path)) { + ancestors.add(EMPTY_PATH); + } + + while ((path = path.getParent()) != null) { + ancestors.add(path); + } + + return ancestors; + } + + + private record PathMark(boolean isDirectory, boolean isPreexisting) { + PathMark(boolean isDirectory) { + this(isDirectory, false); + } + } + + + private record CopyPathSpec(Path srcRoot, Node child, Path destRoot) { + + CopyPathSpec { + Objects.requireNonNull(srcRoot); + Objects.requireNonNull(child); + Objects.requireNonNull(destRoot); + } + + Path resolvedSrcPath() { + return srcRoot.resolve(child.path()); + } + + Path resolvedDstPath() { + return destRoot.resolve(child.path()); + } + + PathMark createPathMark() { + return new PathMark(child.isDirectory()); + } + } + + private static final Path EMPTY_PATH = Path.of(""); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/RootedPath.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/RootedPath.java deleted file mode 100644 index 21d3b6b17b00..000000000000 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/RootedPath.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jpackage.internal.util; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.CopyOption; -import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Stream; - -/** - * A relative path (branch) rooted at the root. - */ -public sealed interface RootedPath { - - Path root(); - Path branch(); - - default Path fullPath() { - return root().resolve(branch()); - } - - public static Function toRootedPath(Path root) { - return path -> { - if (!path.startsWith(root)) { - throw new IllegalArgumentException(String.format("Expected path [%s] to start with [%s] root", path, root)); - } - return new Details.DefaultRootedPath(root, root.relativize(path), Files.isDirectory(path)); - }; - } - - public static void copy(Stream rootedPaths, Path dest, CopyOption...options) throws IOException { - Objects.requireNonNull(rootedPaths); - Objects.requireNonNull(dest); - - var marks = new HashMap(); - - // Preset marks for the preexisting paths. - Files.walkFileTree(dest, new FileVisitor() { - - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { - marks.put(dir, new Details.PathMark(true, true)); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - marks.put(file, new Details.PathMark(false, true)); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { - return FileVisitResult.TERMINATE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } - - }); - - var replacePreexisting = Set.of(options).contains(StandardCopyOption.REPLACE_EXISTING); - - Predicate canReplace = v -> { - return v.isPreexisting() && replacePreexisting; - }; - - try { - rootedPaths.sequential().map(Details.DefaultRootedPath.class::cast).forEach(rootedPath -> { - - final var dstPath = dest.resolve(rootedPath.branch()); - - var dstPathMark = marks.get(dstPath); - - if (!Optional.ofNullable(dstPathMark).map(canReplace::test).orElse(true)) { - // Destination path can not be replaced, bail out. - return; - } - - // Check the ancestors of the destination path. - for (var ancestor : Details.ancestorPaths(rootedPath.branch())) { - var mark = Optional.ofNullable(marks.get(dest.resolve(ancestor))); - - if (!mark.map(Details.PathMark::isDirectory).orElse(true)) { - // `ancestor` is a file, don't overwrite it. - return; - } - } - - dstPathMark = rootedPath.createPathMark(); - marks.put(dstPath, dstPathMark); - - try { - if (replacePreexisting && (rootedPath.isDirectory() != dstPathMark.isDirectory())) { - FileUtils.deleteRecursive(dstPath); - } - - if (rootedPath.isDirectory()) { - Files.createDirectories(dstPath); - } else { - Files.createDirectories(dstPath.getParent()); - Files.copy(rootedPath.fullPath(), dstPath, options); - } - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - }); - } catch (UncheckedIOException ex) { - throw ex.getCause(); - } - } - - static final class Details { - - private Details() { - } - - private record DefaultRootedPath(Path root, Path branch, boolean isDirectory) implements RootedPath { - - DefaultRootedPath { - Objects.requireNonNull(root); - Objects.requireNonNull(branch); - if (branch.isAbsolute()) { - throw new IllegalArgumentException(); - } - } - - PathMark createPathMark() { - return new PathMark(isDirectory); - } - } - - private record PathMark(boolean isDirectory, boolean isPreexisting) { - PathMark(boolean isDirectory) { - this(isDirectory, false); - } - } - - private static List ancestorPaths(Path path) { - var ancestors = new ArrayList(); - while ((path = path.getParent()) != null) { - ancestors.add(path); - } - return ancestors; - } - } -} diff --git a/src/jdk.security.auth/windows/native/libjaas/nt.c b/src/jdk.security.auth/windows/native/libjaas/nt.c index e41386c87ac1..b5f80715aec4 100644 --- a/src/jdk.security.auth/windows/native/libjaas/nt.c +++ b/src/jdk.security.auth/windows/native/libjaas/nt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -106,21 +106,21 @@ Java_com_sun_security_auth_module_NTSystem_getCurrent } if (getUser (tokenHandle, &userName, &domainName, &userSid, &domainSid) == FALSE) { - return; + goto cleanup; } if (debug) { printf("getting primary group\n"); } if (getPrimaryGroup(tokenHandle, &primaryGroup) == FALSE) { - return; + goto cleanup; } if (debug) { printf("getting supplementary groups\n"); } if (getGroups(tokenHandle, &numGroups, &groups) == FALSE) { - return; + goto cleanup; } // then set values into NTSystem @@ -578,6 +578,7 @@ BOOL getImpersonationToken(PHANDLE impersonationToken) { GetLastError()); DisplayErrorText(GetLastError()); } + CloseHandle(dupToken); return FALSE; } CloseHandle(dupToken); diff --git a/test/hotspot/gtest/aarch64/aarch64-asmtest.py b/test/hotspot/gtest/aarch64/aarch64-asmtest.py index f9eb3f7e7cc4..268464063458 100644 --- a/test/hotspot/gtest/aarch64/aarch64-asmtest.py +++ b/test/hotspot/gtest/aarch64/aarch64-asmtest.py @@ -1606,8 +1606,7 @@ def generate(kind, names): generate (CondBranchOp, ["EQ", "NE", "HS", "CS", "LO", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "AL", "NV" ]) -generate (ImmOp, ["svc", "hvc", "smc", "brk", "hlt", # "dcps1", "dcps2", "dcps3" - ]) +generate (ImmOp, ["svc", "hvc", "smc", "brk", "hlt", "udf"]) generate (Op, ["nop", "yield", "wfe", "sev", "sevl", "autia1716", "autiasp", "autiaz", "autib1716", "autibsp", "autibz", diff --git a/test/hotspot/gtest/aarch64/asmtest.out.h b/test/hotspot/gtest/aarch64/asmtest.out.h index 070e8376d3b6..2ca4a61a5eae 100644 --- a/test/hotspot/gtest/aarch64/asmtest.out.h +++ b/test/hotspot/gtest/aarch64/asmtest.out.h @@ -165,6 +165,7 @@ __ smc(9002); // smc #9002 __ brk(14843); // brk #14843 __ hlt(25964); // hlt #25964 + __ udf(28225); // udf #28225 // Op __ nop(); // nop @@ -190,761 +191,761 @@ __ sb(); // sb // OneRegOp - __ wfet(r26); // wfet x26 + __ wfet(r4); // wfet x4 // PostfixExceptionOp __ wfi(); // wfi __ xpaclri(); // xpaclri // SystemOp - __ dsb(Assembler::OSHST); // dsb OSHST - __ dmb(Assembler::ISHLD); // dmb ISHLD + __ dsb(Assembler::ISHLD); // dsb ISHLD + __ dmb(Assembler::ISHST); // dmb ISHST // OneRegOp - __ br(r20); // br x20 - __ blr(r10); // blr x10 - __ paciza(r27); // paciza x27 - __ pacizb(r8); // pacizb x8 - __ pacdza(r0); // pacdza x0 - __ pacdzb(r1); // pacdzb x1 - __ autiza(r21); // autiza x21 - __ autizb(r17); // autizb x17 + __ br(r10); // br x10 + __ blr(r27); // blr x27 + __ paciza(r8); // paciza x8 + __ pacizb(r0); // pacizb x0 + __ pacdza(r1); // pacdza x1 + __ pacdzb(r21); // pacdzb x21 + __ autiza(r17); // autiza x17 + __ autizb(r29); // autizb x29 __ autdza(r29); // autdza x29 - __ autdzb(r29); // autdzb x29 - __ xpacd(r28); // xpacd x28 - __ braaz(r1); // braaz x1 - __ brabz(r23); // brabz x23 - __ blraaz(r21); // blraaz x21 - __ blrabz(r20); // blrabz x20 + __ autdzb(r28); // autdzb x28 + __ xpacd(r1); // xpacd x1 + __ braaz(r23); // braaz x23 + __ brabz(r21); // brabz x21 + __ blraaz(r20); // blraaz x20 + __ blrabz(r22); // blrabz x22 // SystemOneRegOp - __ msr(3, 4, 4, 1, r22); // msr fpsr, x22 + __ msr(3, 4, 4, 1, r27); // msr fpsr, x27 // SystemOneRegOp - __ msr(3, 4, 2, 0, r27); // msr nzcv, x27 + __ msr(3, 4, 2, 0, r19); // msr nzcv, x19 // OneRegSystemOp - __ mrs(3, 4, 4, 1, r19); // mrs x19, fpsr + __ mrs(3, 4, 4, 1, r11); // mrs x11, fpsr // OneRegSystemOp - __ mrs(3, 4, 2, 0, r11); // mrs x11, nzcv + __ mrs(3, 4, 2, 0, r16); // mrs x16, nzcv // OneRegSystemOp - __ mrs(3, 0, 0, 7, r16); // mrs x16, dczid_el0 + __ mrs(3, 0, 0, 7, r6); // mrs x6, dczid_el0 // OneRegSystemOp - __ mrs(3, 0, 0, 1, r6); // mrs x6, ctr_el0 + __ mrs(3, 0, 0, 1, r17); // mrs x17, ctr_el0 // OneRegSystemOp - __ mrs(3, 14, 0, 6, r17); // mrs x17, cntvctss_el0 + __ mrs(3, 14, 0, 6, r0); // mrs x0, cntvctss_el0 // PostfixExceptionOneRegOp - __ xpaci(r0); // xpaci x0 + __ xpaci(r4); // xpaci x4 // LoadStoreExclusiveOp - __ stxr(r4, r10, r24); // stxr w4, x10, [x24] - __ stlxr(r22, r10, r19); // stlxr w22, x10, [x19] - __ ldxr(r1, r5); // ldxr x1, [x5] - __ ldaxr(r30, r8); // ldaxr x30, [x8] - __ stlr(r12, r17); // stlr x12, [x17] - __ ldar(r9, r14); // ldar x9, [x14] + __ stxr(r10, r24, r22); // stxr w10, x24, [x22] + __ stlxr(r10, r19, r1); // stlxr w10, x19, [x1] + __ ldxr(r5, r30); // ldxr x5, [x30] + __ ldaxr(r8, r12); // ldaxr x8, [x12] + __ stlr(r17, r9); // stlr x17, [x9] + __ ldar(r14, r7); // ldar x14, [x7] // LoadStoreExclusiveOp - __ stxrw(r7, r1, r5); // stxr w7, w1, [x5] - __ stlxrw(r16, r2, r12); // stlxr w16, w2, [x12] - __ ldxrw(r10, r12); // ldxr w10, [x12] - __ ldaxrw(r3, r28); // ldaxr w3, [x28] - __ stlrw(r14, r26); // stlr w14, [x26] - __ ldarw(r30, r10); // ldar w30, [x10] + __ stxrw(r1, r5, r16); // stxr w1, w5, [x16] + __ stlxrw(r2, r12, r10); // stlxr w2, w12, [x10] + __ ldxrw(r12, r3); // ldxr w12, [x3] + __ ldaxrw(r28, r14); // ldaxr w28, [x14] + __ stlrw(r26, r30); // stlr w26, [x30] + __ ldarw(r10, r14); // ldar w10, [x14] // LoadStoreExclusiveOp - __ stxrh(r14, r21, r13); // stxrh w14, w21, [x13] - __ stlxrh(r9, r22, r27); // stlxrh w9, w22, [x27] - __ ldxrh(r28, r19); // ldxrh w28, [x19] - __ ldaxrh(r11, r30); // ldaxrh w11, [x30] - __ stlrh(r19, r2); // stlrh w19, [x2] - __ ldarh(r2, r23); // ldarh w2, [x23] + __ stxrh(r21, r13, r9); // stxrh w21, w13, [x9] + __ stlxrh(r22, r27, r28); // stlxrh w22, w27, [x28] + __ ldxrh(r19, r11); // ldxrh w19, [x11] + __ ldaxrh(r30, r19); // ldaxrh w30, [x19] + __ stlrh(r2, r23); // stlrh w2, [x23] + __ ldarh(r1, r0); // ldarh w1, [x0] // LoadStoreExclusiveOp - __ stxrb(r1, r0, r12); // stxrb w1, w0, [x12] - __ stlxrb(r16, r13, r15); // stlxrb w16, w13, [x15] - __ ldxrb(r17, r21); // ldxrb w17, [x21] - __ ldaxrb(r13, r11); // ldaxrb w13, [x11] - __ stlrb(r30, r8); // stlrb w30, [x8] - __ ldarb(r24, r13); // ldarb w24, [x13] + __ stxrb(r12, r16, r13); // stxrb w12, w16, [x13] + __ stlxrb(r15, r17, r21); // stlxrb w15, w17, [x21] + __ ldxrb(r13, r11); // ldxrb w13, [x11] + __ ldaxrb(r30, r8); // ldaxrb w30, [x8] + __ stlrb(r24, r13); // stlrb w24, [x13] + __ ldarb(r11, r1); // ldarb w11, [x1] // LoadStoreExclusiveOp - __ ldxp(r11, r1, r26); // ldxp x11, x1, [x26] - __ ldaxp(r21, r27, r13); // ldaxp x21, x27, [x13] - __ stxp(r20, r3, r12, r6); // stxp w20, x3, x12, [x6] - __ stlxp(r1, r29, r6, r4); // stlxp w1, x29, x6, [x4] + __ ldxp(r26, r21, r27); // ldxp x26, x21, [x27] + __ ldaxp(r13, r20, r3); // ldaxp x13, x20, [x3] + __ stxp(r12, r6, r1, r29); // stxp w12, x6, x1, [x29] + __ stlxp(r6, r4, r11, r16); // stlxp w6, x4, x11, [x16] // LoadStoreExclusiveOp - __ ldxpw(r6, r11, r16); // ldxp w6, w11, [x16] - __ ldaxpw(r4, r30, r12); // ldaxp w4, w30, [x12] - __ stxpw(r21, r27, r15, r28); // stxp w21, w27, w15, [x28] - __ stlxpw(r9, r15, r20, r6); // stlxp w9, w15, w20, [x6] + __ ldxpw(r4, r30, r12); // ldxp w4, w30, [x12] + __ ldaxpw(r21, r27, r15); // ldaxp w21, w27, [x15] + __ stxpw(r28, r9, r15, r20); // stxp w28, w9, w15, [x20] + __ stlxpw(r6, r17, r10, r29); // stlxp w6, w17, w10, [x29] // base_plus_unscaled_offset // LoadStoreOp - __ str(r24, Address(r17, -125)); // str x24, [x17, -125] - __ strw(r1, Address(r26, 10)); // str w1, [x26, 10] - __ strb(r15, Address(r0, -17)); // strb w15, [x0, -17] - __ strh(r17, Address(r17, 13)); // strh w17, [x17, 13] - __ ldr(r5, Address(r25, 49)); // ldr x5, [x25, 49] - __ ldrw(r19, Address(r15, -116)); // ldr w19, [x15, -116] - __ ldrb(r20, Address(r3, 7)); // ldrb w20, [x3, 7] - __ ldrh(r19, Address(r4, -25)); // ldrh w19, [x4, -25] - __ ldrsb(r14, Address(r19, -6)); // ldrsb x14, [x19, -6] - __ ldrsh(r28, Address(r19, -53)); // ldrsh x28, [x19, -53] - __ ldrshw(r14, Address(r27, 13)); // ldrsh w14, [x27, 13] - __ ldrsw(r6, Address(r24, -120)); // ldrsw x6, [x24, -120] - __ ldrd(v18, Address(r2, 87)); // ldr d18, [x2, 87] - __ ldrs(v0, Address(r28, -48)); // ldr s0, [x28, -48] - __ strd(v31, Address(r28, 23)); // str d31, [x28, 23] - __ strs(v11, Address(r25, 43)); // str s11, [x25, 43] + __ str(r25, Address(r27, -243)); // str x25, [x27, -243] + __ strw(r4, Address(r2, 39)); // str w4, [x2, 39] + __ strb(r23, Address(r4, 14)); // strb w23, [x4, 14] + __ strh(r12, Address(r30, 23)); // strh w12, [x30, 23] + __ ldr(r26, Address(r17, 51)); // ldr x26, [x17, 51] + __ ldrw(r1, Address(r29, -50)); // ldr w1, [x29, -50] + __ ldrb(r17, Address(r1, -9)); // ldrb w17, [x1, -9] + __ ldrh(r10, Address(r11, -19)); // ldrh w10, [x11, -19] + __ ldrsb(r21, Address(r11, -9)); // ldrsb x21, [x11, -9] + __ ldrsh(r16, Address(r19, -52)); // ldrsh x16, [x19, -52] + __ ldrshw(r28, Address(r24, 11)); // ldrsh w28, [x24, 11] + __ ldrsw(r24, Address(r15, 53)); // ldrsw x24, [x15, 53] + __ ldrd(v3, Address(r21, -139)); // ldr d3, [x21, -139] + __ ldrs(v2, Address(r23, -123)); // ldr s2, [x23, -123] + __ strd(v6, Address(r2, -245)); // str d6, [x2, -245] + __ strs(v5, Address(r6, 52)); // str s5, [x6, 52] // pre // LoadStoreOp - __ str(r14, Address(__ pre(r8, -185))); // str x14, [x8, -185]! - __ strw(r25, Address(__ pre(r9, -93))); // str w25, [x9, -93]! - __ strb(r16, Address(__ pre(r23, -12))); // strb w16, [x23, -12]! - __ strh(r22, Address(__ pre(r9, -56))); // strh w22, [x9, -56]! - __ ldr(r11, Address(__ pre(r24, 109))); // ldr x11, [x24, 109]! - __ ldrw(r21, Address(__ pre(r19, 52))); // ldr w21, [x19, 52]! - __ ldrb(r6, Address(__ pre(r23, -2))); // ldrb w6, [x23, -2]! - __ ldrh(r7, Address(__ pre(r8, 21))); // ldrh w7, [x8, 21]! - __ ldrsb(r4, Address(__ pre(r12, -31))); // ldrsb x4, [x12, -31]! - __ ldrsh(r8, Address(__ pre(r11, -4))); // ldrsh x8, [x11, -4]! - __ ldrshw(r14, Address(__ pre(r21, -28))); // ldrsh w14, [x21, -28]! - __ ldrsw(r0, Address(__ pre(r15, -71))); // ldrsw x0, [x15, -71]! - __ ldrd(v27, Address(__ pre(r2, 29))); // ldr d27, [x2, 29]! - __ ldrs(v13, Address(__ pre(r21, 16))); // ldr s13, [x21, 16]! - __ strd(v12, Address(__ pre(r27, 16))); // str d12, [x27, 16]! - __ strs(v2, Address(__ pre(r25, -91))); // str s2, [x25, -91]! + __ str(r20, Address(__ pre(r5, -206))); // str x20, [x5, -206]! + __ strw(r8, Address(__ pre(r12, -98))); // str w8, [x12, -98]! + __ strb(r20, Address(__ pre(r2, -29))); // strb w20, [x2, -29]! + __ strh(r14, Address(__ pre(r29, -59))); // strh w14, [x29, -59]! + __ ldr(r13, Address(__ pre(r29, 8))); // ldr x13, [x29, 8]! + __ ldrw(r24, Address(__ pre(r19, -35))); // ldr w24, [x19, -35]! + __ ldrb(r3, Address(__ pre(r27, -10))); // ldrb w3, [x27, -10]! + __ ldrh(r17, Address(__ pre(r1, -9))); // ldrh w17, [x1, -9]! + __ ldrsb(r17, Address(__ pre(r19, -7))); // ldrsb x17, [x19, -7]! + __ ldrsh(r21, Address(__ pre(r11, -26))); // ldrsh x21, [x11, -26]! + __ ldrshw(r1, Address(__ pre(r9, -30))); // ldrsh w1, [x9, -30]! + __ ldrsw(r21, Address(__ pre(r23, -124))); // ldrsw x21, [x23, -124]! + __ ldrd(v24, Address(__ pre(r20, -17))); // ldr d24, [x20, -17]! + __ ldrs(v22, Address(__ pre(r8, -65))); // ldr s22, [x8, -65]! + __ strd(v6, Address(__ pre(r16, -86))); // str d6, [x16, -86]! + __ strs(v5, Address(__ pre(r29, -54))); // str s5, [x29, -54]! // post // LoadStoreOp - __ str(r10, Address(__ post(r13, -21))); // str x10, [x13], -21 - __ strw(r7, Address(__ post(r1, 50))); // str w7, [x1], 50 - __ strb(r10, Address(__ post(r3, 5))); // strb w10, [x3], 5 - __ strh(r5, Address(__ post(r6, -33))); // strh w5, [x6], -33 - __ ldr(r13, Address(__ post(r22, -158))); // ldr x13, [x22], -158 - __ ldrw(r13, Address(__ post(r2, -106))); // ldr w13, [x2], -106 - __ ldrb(r13, Address(__ post(r16, -24))); // ldrb w13, [x16], -24 - __ ldrh(r24, Address(__ post(r2, -22))); // ldrh w24, [x2], -22 - __ ldrsb(r3, Address(__ post(r23, -1))); // ldrsb x3, [x23], -1 - __ ldrsh(r19, Address(__ post(r8, -43))); // ldrsh x19, [x8], -43 - __ ldrshw(r2, Address(__ post(r23, -8))); // ldrsh w2, [x23], -8 - __ ldrsw(r19, Address(__ post(r28, -87))); // ldrsw x19, [x28], -87 - __ ldrd(v15, Address(__ post(r3, -81))); // ldr d15, [x3], -81 - __ ldrs(v12, Address(__ post(r29, -79))); // ldr s12, [x29], -79 - __ strd(v21, Address(__ post(r1, -124))); // str d21, [x1], -124 - __ strs(v7, Address(__ post(r9, -99))); // str s7, [x9], -99 + __ str(r29, Address(__ post(r28, -147))); // str x29, [x28], -147 + __ strw(r4, Address(__ post(r24, -87))); // str w4, [x24], -87 + __ strb(r13, Address(__ post(r9, -11))); // strb w13, [x9], -11 + __ strh(r26, Address(__ post(r7, -14))); // strh w26, [x7], -14 + __ ldr(r13, Address(__ post(r3, -229))); // ldr x13, [x3], -229 + __ ldrw(r1, Address(__ post(r5, 48))); // ldr w1, [x5], 48 + __ ldrb(r8, Address(__ post(r13, -17))); // ldrb w8, [x13], -17 + __ ldrh(r23, Address(__ post(r20, -53))); // ldrh w23, [x20], -53 + __ ldrsb(r20, Address(__ post(r6, -1))); // ldrsb x20, [x6], -1 + __ ldrsh(r9, Address(__ post(r17, -42))); // ldrsh x9, [x17], -42 + __ ldrshw(r21, Address(__ post(r6, -15))); // ldrsh w21, [x6], -15 + __ ldrsw(r10, Address(__ post(r13, -15))); // ldrsw x10, [x13], -15 + __ ldrd(v8, Address(__ post(r0, -66))); // ldr d8, [x0], -66 + __ ldrs(v10, Address(__ post(r17, -55))); // ldr s10, [x17], -55 + __ strd(v4, Address(__ post(r13, 2))); // str d4, [x13], 2 + __ strs(v13, Address(__ post(r0, -85))); // str s13, [x0], -85 // base_plus_reg // LoadStoreOp - __ str(r5, Address(r20, r2, Address::lsl(0))); // str x5, [x20, x2, lsl #0] - __ strw(r14, Address(r10, r30, Address::sxtw(2))); // str w14, [x10, w30, sxtw #2] - __ strb(r4, Address(r1, r28, Address::sxtw(0))); // strb w4, [x1, w28, sxtw #0] - __ strh(r5, Address(r10, r26, Address::sxtx(1))); // strh w5, [x10, x26, sxtx #1] - __ ldr(r22, Address(r2, r28, Address::lsl(3))); // ldr x22, [x2, x28, lsl #3] - __ ldrw(r12, Address(r0, r28, Address::lsl(2))); // ldr w12, [x0, x28, lsl #2] - __ ldrb(r8, Address(r8, r15, Address::sxtx(0))); // ldrb w8, [x8, x15, sxtx #0] - __ ldrh(r17, Address(r21, r14, Address::uxtw(1))); // ldrh w17, [x21, w14, uxtw #1] - __ ldrsb(r17, Address(r24, r8, Address::sxtx(0))); // ldrsb x17, [x24, x8, sxtx #0] - __ ldrsh(r10, Address(r10, r30, Address::sxtx(1))); // ldrsh x10, [x10, x30, sxtx #1] - __ ldrshw(r17, Address(r23, r0, Address::lsl(1))); // ldrsh w17, [x23, x0, lsl #1] - __ ldrsw(r25, Address(r30, r0, Address::lsl(2))); // ldrsw x25, [x30, x0, lsl #2] - __ ldrd(v5, Address(r24, r23, Address::uxtw(3))); // ldr d5, [x24, w23, uxtw #3] - __ ldrs(v22, Address(r3, r15, Address::lsl(2))); // ldr s22, [x3, x15, lsl #2] - __ strd(v4, Address(r29, r16, Address::sxtx(3))); // str d4, [x29, x16, sxtx #3] - __ strs(v7, Address(r20, r28, Address::sxtw(2))); // str s7, [x20, w28, sxtw #2] + __ str(r12, Address(r27, r6, Address::sxtw(0))); // str x12, [x27, w6, sxtw #0] + __ strw(r0, Address(r8, r16, Address::lsl(0))); // str w0, [x8, x16, lsl #0] + __ strb(r0, Address(r4, r26, Address::sxtx(0))); // strb w0, [x4, x26, sxtx #0] + __ strh(r14, Address(r25, r5, Address::sxtw(1))); // strh w14, [x25, w5, sxtw #1] + __ ldr(r9, Address(r4, r17, Address::uxtw(0))); // ldr x9, [x4, w17, uxtw #0] + __ ldrw(r27, Address(r4, r7, Address::lsl(0))); // ldr w27, [x4, x7, lsl #0] + __ ldrb(r15, Address(r17, r30, Address::sxtw(0))); // ldrb w15, [x17, w30, sxtw #0] + __ ldrh(r16, Address(r0, r22, Address::sxtw(0))); // ldrh w16, [x0, w22, sxtw #0] + __ ldrsb(r22, Address(r10, r30, Address::sxtx(0))); // ldrsb x22, [x10, x30, sxtx #0] + __ ldrsh(r29, Address(r21, r10, Address::sxtx(1))); // ldrsh x29, [x21, x10, sxtx #1] + __ ldrshw(r3, Address(r11, r19, Address::uxtw(0))); // ldrsh w3, [x11, w19, uxtw #0] + __ ldrsw(r13, Address(r28, r29, Address::uxtw(2))); // ldrsw x13, [x28, w29, uxtw #2] + __ ldrd(v24, Address(r29, r5, Address::sxtx(3))); // ldr d24, [x29, x5, sxtx #3] + __ ldrs(v6, Address(r8, r8, Address::sxtw(2))); // ldr s6, [x8, w8, sxtw #2] + __ strd(v30, Address(r24, r24, Address::sxtw(0))); // str d30, [x24, w24, sxtw #0] + __ strs(v20, Address(r17, r12, Address::sxtx(2))); // str s20, [x17, x12, sxtx #2] // base_plus_scaled_offset // LoadStoreOp - __ str(r27, Address(r0, 16360)); // str x27, [x0, 16360] - __ strw(r21, Address(r8, 7984)); // str w21, [x8, 7984] - __ strb(r17, Address(r29, 1795)); // strb w17, [x29, 1795] - __ strh(r27, Address(r2, 3636)); // strh w27, [x2, 3636] - __ ldr(r1, Address(r1, 12480)); // ldr x1, [x1, 12480] - __ ldrw(r29, Address(r17, 6320)); // ldr w29, [x17, 6320] - __ ldrb(r1, Address(r9, 1634)); // ldrb w1, [x9, 1634] - __ ldrh(r23, Address(r3, 3736)); // ldrh w23, [x3, 3736] - __ ldrsb(r21, Address(r19, 1857)); // ldrsb x21, [x19, 1857] - __ ldrsh(r19, Address(r7, 3180)); // ldrsh x19, [x7, 3180] - __ ldrshw(r10, Address(r1, 3560)); // ldrsh w10, [x1, 3560] - __ ldrsw(r10, Address(r20, 7428)); // ldrsw x10, [x20, 7428] - __ ldrd(v0, Address(r13, 14880)); // ldr d0, [x13, 14880] - __ ldrs(v11, Address(r27, 6356)); // ldr s11, [x27, 6356] - __ strd(v13, Address(r25, 13704)); // str d13, [x25, 13704] - __ strs(v20, Address(r0, 7580)); // str s20, [x0, 7580] + __ str(r13, Address(r19, 15936)); // str x13, [x19, 15936] + __ strw(r19, Address(r23, 6816)); // str w19, [x23, 6816] + __ strb(r23, Address(r29, 1566)); // strb w23, [x29, 1566] + __ strh(r22, Address(r11, 4024)); // strh w22, [x11, 4024] + __ ldr(r3, Address(r10, 15136)); // ldr x3, [x10, 15136] + __ ldrw(r8, Address(r16, 7804)); // ldr w8, [x16, 7804] + __ ldrb(r23, Address(r20, 1673)); // ldrb w23, [x20, 1673] + __ ldrh(r2, Address(r1, 3994)); // ldrh w2, [x1, 3994] + __ ldrsb(r4, Address(r17, 1801)); // ldrsb x4, [x17, 1801] + __ ldrsh(r20, Address(r27, 3600)); // ldrsh x20, [x27, 3600] + __ ldrshw(r25, Address(r14, 4048)); // ldrsh w25, [x14, 4048] + __ ldrsw(r26, Address(r10, 7512)); // ldrsw x26, [x10, 7512] + __ ldrd(v9, Address(r3, 13872)); // ldr d9, [x3, 13872] + __ ldrs(v28, Address(r12, 6460)); // ldr s28, [x12, 6460] + __ strd(v11, Address(r23, 14768)); // str d11, [x23, 14768] + __ strs(v15, Address(r3, 8012)); // str s15, [x3, 8012] // pcrel // LoadStoreOp - __ ldr(r26, __ pc()); // ldr x26, . - __ ldrw(r19, back); // ldr w19, back + __ ldr(r10, __ pc()); // ldr x10, . + __ ldrw(r16, __ pc()); // ldr w16, . // LoadStoreOp - __ prfm(Address(r8, -111)); // prfm PLDL1KEEP, [x8, -111] + __ prfm(Address(r4, 99)); // prfm PLDL1KEEP, [x4, 99] // LoadStoreOp - __ prfm(forth); // prfm PLDL1KEEP, forth + __ prfm(__ pc()); // prfm PLDL1KEEP, . // LoadStoreOp - __ prfm(Address(r7, r7, Address::uxtw(3))); // prfm PLDL1KEEP, [x7, w7, uxtw #3] + __ prfm(Address(r4, r17, Address::sxtx(0))); // prfm PLDL1KEEP, [x4, x17, sxtx #0] // LoadStoreOp - __ prfm(Address(r12, 12600)); // prfm PLDL1KEEP, [x12, 12600] + __ prfm(Address(r15, 13712)); // prfm PLDL1KEEP, [x15, 13712] // AddSubCarryOp - __ adcw(r24, r20, r11); // adc w24, w20, w11 - __ adcsw(r0, r13, r28); // adcs w0, w13, w28 - __ sbcw(r10, r7, r4); // sbc w10, w7, w4 - __ sbcsw(r15, r16, r2); // sbcs w15, w16, w2 - __ adc(r12, r20, r29); // adc x12, x20, x29 - __ adcs(r13, r13, r14); // adcs x13, x13, x14 - __ sbc(r6, r12, r20); // sbc x6, x12, x20 - __ sbcs(r12, r17, r25); // sbcs x12, x17, x25 + __ adcw(r28, r10, r7); // adc w28, w10, w7 + __ adcsw(r4, r15, r16); // adcs w4, w15, w16 + __ sbcw(r2, r12, r20); // sbc w2, w12, w20 + __ sbcsw(r29, r13, r13); // sbcs w29, w13, w13 + __ adc(r14, r6, r12); // adc x14, x6, x12 + __ adcs(r20, r12, r17); // adcs x20, x12, x17 + __ sbc(r25, r30, r27); // sbc x25, x30, x27 + __ sbcs(r11, r0, r17); // sbcs x11, x0, x17 // AddSubExtendedOp - __ addw(r30, r27, r11, ext::sxtb, 1); // add w30, w27, w11, sxtb #1 - __ addsw(r14, r7, r1, ext::sxtw, 2); // adds w14, w7, w1, sxtw #2 - __ sub(r29, r3, r27, ext::sxth, 1); // sub x29, x3, x27, sxth #1 - __ subsw(r0, r13, r26, ext::sxtx, 2); // subs w0, w13, w26, sxtx #2 - __ add(r22, r17, r5, ext::uxtx, 2); // add x22, x17, x5, uxtx #2 - __ adds(r17, r30, r8, ext::sxtx, 3); // adds x17, x30, x8, sxtx #3 - __ sub(r10, r19, r23, ext::sxtw, 3); // sub x10, x19, x23, sxtw #3 - __ subs(r6, r29, r5, ext::uxtw, 3); // subs x6, x29, x5, uxtw #3 + __ addw(r14, r7, r1, ext::sxtw, 2); // add w14, w7, w1, sxtw #2 + __ addsw(r29, r3, r27, ext::sxth, 1); // adds w29, w3, w27, sxth #1 + __ sub(r0, r13, r26, ext::sxtx, 2); // sub x0, x13, x26, sxtx #2 + __ subsw(r22, r17, r5, ext::uxtx, 2); // subs w22, w17, w5, uxtx #2 + __ add(r17, r30, r8, ext::sxtx, 3); // add x17, x30, x8, sxtx #3 + __ adds(r10, r19, r23, ext::sxtw, 3); // adds x10, x19, x23, sxtw #3 + __ sub(r6, r29, r5, ext::uxtw, 3); // sub x6, x29, x5, uxtw #3 + __ subs(r19, r9, r13, ext::uxtw, 3); // subs x19, x9, x13, uxtw #3 // ConditionalCompareOp - __ ccmnw(r19, r9, 4u, Assembler::HI); // ccmn w19, w9, #4, HI - __ ccmpw(r22, r10, 2u, Assembler::VC); // ccmp w22, w10, #2, VC - __ ccmn(r13, r12, 10u, Assembler::LS); // ccmn x13, x12, #10, LS - __ ccmp(r24, r16, 3u, Assembler::HS); // ccmp x24, x16, #3, HS + __ ccmnw(r22, r10, 2u, Assembler::VC); // ccmn w22, w10, #2, VC + __ ccmpw(r13, r12, 10u, Assembler::LS); // ccmp w13, w12, #10, LS + __ ccmn(r24, r16, 3u, Assembler::HS); // ccmn x24, x16, #3, HS + __ ccmp(r7, r16, 14u, Assembler::CC); // ccmp x7, x16, #14, CC // ConditionalCompareImmedOp - __ ccmnw(r7, 11, 13, Assembler::VS); // ccmn w7, #11, #13, VS - __ ccmpw(r27, 10, 11, Assembler::LS); // ccmp w27, #10, #11, LS - __ ccmn(r3, 13, 13, Assembler::LE); // ccmn x3, #13, #13, LE - __ ccmp(r26, 16, 5, Assembler::GT); // ccmp x26, #16, #5, GT + __ ccmnw(r22, 3, 5, Assembler::LS); // ccmn w22, #3, #5, LS + __ ccmpw(r29, 27, 6, Assembler::LT); // ccmp w29, #27, #6, LT + __ ccmn(r27, 10, 8, Assembler::CC); // ccmn x27, #10, #8, CC + __ ccmp(r21, 23, 15, Assembler::GT); // ccmp x21, #23, #15, GT // ConditionalSelectOp - __ cselw(r10, r21, r28, Assembler::LE); // csel w10, w21, w28, LE - __ csincw(r23, r9, r27, Assembler::LE); // csinc w23, w9, w27, LE - __ csinvw(r10, r29, r15, Assembler::LE); // csinv w10, w29, w15, LE - __ csnegw(r30, r25, r21, Assembler::HS); // csneg w30, w25, w21, HS - __ csel(r0, r17, r21, Assembler::GT); // csel x0, x17, x21, GT - __ csinc(r16, r21, r20, Assembler::CS); // csinc x16, x21, x20, CS - __ csinv(r19, r30, r3, Assembler::LS); // csinv x19, x30, x3, LS - __ csneg(r19, r11, r24, Assembler::EQ); // csneg x19, x11, x24, EQ + __ cselw(r9, r27, r30, Assembler::CC); // csel w9, w27, w30, CC + __ csincw(r29, r15, r29, Assembler::LE); // csinc w29, w15, w29, LE + __ csinvw(r25, r21, r4, Assembler::EQ); // csinv w25, w21, w4, EQ + __ csnegw(r17, r21, r29, Assembler::VS); // csneg w17, w21, w29, VS + __ csel(r21, r20, r6, Assembler::HI); // csel x21, x20, x6, HI + __ csinc(r30, r3, r21, Assembler::VC); // csinc x30, x3, x21, VC + __ csinv(r11, r24, r0, Assembler::GT); // csinv x11, x24, x0, GT + __ csneg(r25, r14, r3, Assembler::PL); // csneg x25, x14, x3, PL // TwoRegOp - __ rbitw(r27, r25); // rbit w27, w25 - __ rev16w(r14, r3); // rev16 w14, w3 - __ revw(r14, r17); // rev w14, w17 - __ clzw(r7, r15); // clz w7, w15 - __ clsw(r24, r28); // cls w24, w28 - __ rbit(r17, r25); // rbit x17, x25 - __ rev16(r2, r26); // rev16 x2, x26 - __ rev32(r28, r5); // rev32 x28, x5 - __ rev(r25, r26); // rev x25, x26 - __ clz(r27, r16); // clz x27, x16 - __ cls(r17, r6); // cls x17, x6 - __ pacia(r21, r12); // pacia x21, x12 - __ pacib(r0, r4); // pacib x0, x4 - __ pacda(r12, r27); // pacda x12, x27 - __ pacdb(r17, r28); // pacdb x17, x28 - __ autia(r28, r2); // autia x28, x2 - __ autib(r17, r10); // autib x17, x10 - __ autda(r15, r14); // autda x15, x14 - __ autdb(r14, r3); // autdb x14, x3 - __ braa(r25, r15); // braa x25, x15 - __ brab(r19, r14); // brab x19, x14 - __ blraa(r5, r16); // blraa x5, x16 - __ blrab(r4, r26); // blrab x4, x26 + __ rbitw(r17, r7); // rbit w17, w7 + __ rev16w(r15, r24); // rev16 w15, w24 + __ revw(r28, r17); // rev w28, w17 + __ clzw(r25, r2); // clz w25, w2 + __ clsw(r26, r28); // cls w26, w28 + __ rbit(r5, r25); // rbit x5, x25 + __ rev16(r26, r27); // rev16 x26, x27 + __ rev32(r16, r17); // rev32 x16, x17 + __ rev(r6, r21); // rev x6, x21 + __ clz(r12, r0); // clz x12, x0 + __ cls(r4, r12); // cls x4, x12 + __ pacia(r27, r17); // pacia x27, x17 + __ pacib(r28, r28); // pacib x28, x28 + __ pacda(r2, r17); // pacda x2, x17 + __ pacdb(r10, r15); // pacdb x10, x15 + __ autia(r14, r14); // autia x14, x14 + __ autib(r3, r25); // autib x3, x25 + __ autda(r15, r19); // autda x15, x19 + __ autdb(r14, r5); // autdb x14, x5 + __ braa(r16, r4); // braa x16, x4 + __ brab(r26, r25); // brab x26, x25 + __ blraa(r4, r2); // blraa x4, x2 + __ blrab(r2, r12); // blrab x2, x12 // ThreeRegOp - __ udivw(r25, r4, r2); // udiv w25, w4, w2 - __ sdivw(r2, r12, r29); // sdiv w2, w12, w29 - __ lslvw(r17, r8, r7); // lslv w17, w8, w7 - __ lsrvw(r3, r4, r25); // lsrv w3, w4, w25 - __ asrvw(r4, r26, r25); // asrv w4, w26, w25 - __ rorvw(r4, r17, r0); // rorv w4, w17, w0 - __ udiv(r26, r17, r23); // udiv x26, x17, x23 - __ sdiv(r15, r21, r28); // sdiv x15, x21, x28 - __ lslv(r17, r27, r10); // lslv x17, x27, x10 - __ lsrv(r3, r0, r7); // lsrv x3, x0, x7 - __ asrv(r25, r9, r6); // asrv x25, x9, x6 - __ rorv(r15, r29, r15); // rorv x15, x29, x15 - __ umulh(r10, r2, r17); // umulh x10, x2, x17 - __ smulh(r7, r11, r11); // smulh x7, x11, x11 + __ udivw(r29, r17, r8); // udiv w29, w17, w8 + __ sdivw(r7, r3, r4); // sdiv w7, w3, w4 + __ lslvw(r25, r4, r26); // lslv w25, w4, w26 + __ lsrvw(r25, r4, r17); // lsrv w25, w4, w17 + __ asrvw(r0, r26, r17); // asrv w0, w26, w17 + __ rorvw(r23, r15, r21); // rorv w23, w15, w21 + __ udiv(r28, r17, r27); // udiv x28, x17, x27 + __ sdiv(r10, r3, r0); // sdiv x10, x3, x0 + __ lslv(r7, r25, r9); // lslv x7, x25, x9 + __ lsrv(r6, r15, r29); // lsrv x6, x15, x29 + __ asrv(r15, r10, r2); // asrv x15, x10, x2 + __ rorv(r17, r7, r11); // rorv x17, x7, x11 + __ umulh(r11, r23, r7); // umulh x11, x23, x7 + __ smulh(r29, r23, r14); // smulh x29, x23, x14 // FourRegMulOp - __ maddw(r23, r7, r29, r23); // madd w23, w7, w29, w23 - __ msubw(r14, r27, r11, r11); // msub w14, w27, w11, w11 - __ madd(r4, r24, r12, r15); // madd x4, x24, x12, x15 - __ msub(r14, r20, r11, r28); // msub x14, x20, x11, x28 - __ smaddl(r13, r11, r12, r23); // smaddl x13, w11, w12, x23 - __ smsubl(r30, r26, r14, r9); // smsubl x30, w26, w14, x9 - __ umaddl(r13, r10, r7, r5); // umaddl x13, w10, w7, x5 - __ umsubl(r29, r15, r3, r11); // umsubl x29, w15, w3, x11 + __ maddw(r27, r11, r11, r4); // madd w27, w11, w11, w4 + __ msubw(r24, r12, r15, r14); // msub w24, w12, w15, w14 + __ madd(r20, r11, r28, r13); // madd x20, x11, x28, x13 + __ msub(r11, r12, r23, r30); // msub x11, x12, x23, x30 + __ smaddl(r26, r14, r9, r13); // smaddl x26, w14, w9, x13 + __ smsubl(r10, r7, r5, r29); // smsubl x10, w7, w5, x29 + __ umaddl(r15, r3, r11, r12); // umaddl x15, w3, w11, x12 + __ umsubl(r15, r30, r30, r17); // umsubl x15, w30, w30, x17 // ThreeRegFloatOp - __ fabdh(v12, v16, v31); // fabd h12, h16, h31 - __ fmulh(v31, v18, v19); // fmul h31, h18, h19 - __ fdivh(v21, v16, v15); // fdiv h21, h16, h15 - __ faddh(v10, v21, v2); // fadd h10, h21, h2 - __ fsubh(v10, v28, v7); // fsub h10, h28, h7 - __ fmaxh(v30, v31, v18); // fmax h30, h31, h18 - __ fminh(v1, v2, v6); // fmin h1, h2, h6 - __ fnmulh(v10, v3, v25); // fnmul h10, h3, h25 - __ fabds(v11, v7, v1); // fabd s11, s7, s1 - __ fmuls(v12, v0, v3); // fmul s12, s0, s3 - __ fdivs(v19, v29, v6); // fdiv s19, s29, s6 - __ fadds(v23, v6, v0); // fadd s23, s6, s0 - __ fsubs(v28, v27, v2); // fsub s28, s27, s2 - __ fmaxs(v5, v7, v29); // fmax s5, s7, s29 - __ fmins(v12, v25, v13); // fmin s12, s25, s13 - __ fnmuls(v12, v24, v19); // fnmul s12, s24, s19 - __ fabdd(v8, v18, v22); // fabd d8, d18, d22 - __ fmuld(v26, v21, v20); // fmul d26, d21, d20 - __ fdivd(v19, v2, v30); // fdiv d19, d2, d30 - __ faddd(v22, v8, v22); // fadd d22, d8, d22 - __ fsubd(v19, v21, v12); // fsub d19, d21, d12 - __ fmaxd(v18, v21, v6); // fmax d18, d21, d6 - __ fmind(v16, v3, v3); // fmin d16, d3, d3 - __ fnmuld(v29, v3, v28); // fnmul d29, d3, d28 + __ fabdh(v19, v21, v16); // fabd h19, h21, h16 + __ fmulh(v15, v10, v21); // fmul h15, h10, h21 + __ fdivh(v2, v10, v28); // fdiv h2, h10, h28 + __ faddh(v7, v30, v31); // fadd h7, h30, h31 + __ fsubh(v18, v1, v2); // fsub h18, h1, h2 + __ fmaxh(v6, v10, v3); // fmax h6, h10, h3 + __ fminh(v25, v11, v7); // fmin h25, h11, h7 + __ fnmulh(v1, v12, v0); // fnmul h1, h12, h0 + __ fabds(v3, v19, v29); // fabd s3, s19, s29 + __ fmuls(v6, v23, v6); // fmul s6, s23, s6 + __ fdivs(v0, v28, v27); // fdiv s0, s28, s27 + __ fadds(v2, v5, v7); // fadd s2, s5, s7 + __ fsubs(v29, v12, v25); // fsub s29, s12, s25 + __ fmaxs(v13, v12, v24); // fmax s13, s12, s24 + __ fmins(v19, v8, v18); // fmin s19, s8, s18 + __ fnmuls(v22, v26, v21); // fnmul s22, s26, s21 + __ fabdd(v20, v19, v2); // fabd d20, d19, d2 + __ fmuld(v30, v22, v8); // fmul d30, d22, d8 + __ fdivd(v22, v19, v21); // fdiv d22, d19, d21 + __ faddd(v12, v18, v21); // fadd d12, d18, d21 + __ fsubd(v6, v16, v3); // fsub d6, d16, d3 + __ fmaxd(v3, v29, v3); // fmax d3, d29, d3 + __ fmind(v28, v15, v14); // fmin d28, d15, d14 + __ fnmuld(v10, v13, v12); // fnmul d10, d13, d12 // FourRegFloatOp - __ fmaddh(v15, v14, v10, v13); // fmadd h15, h14, h10, h13 - __ fmadds(v12, v18, v10, v26); // fmadd s12, s18, s10, s26 - __ fmsubs(v7, v7, v15, v29); // fmsub s7, s7, s15, s29 - __ fnmadds(v0, v23, v0, v12); // fnmadd s0, s23, s0, s12 - __ fnmadds(v24, v14, v13, v8); // fnmadd s24, s14, s13, s8 - __ fmaddd(v15, v7, v9, v20); // fmadd d15, d7, d9, d20 - __ fmsubd(v19, v29, v31, v16); // fmsub d19, d29, d31, d16 - __ fnmaddd(v2, v9, v16, v21); // fnmadd d2, d9, d16, d21 - __ fnmaddd(v30, v4, v1, v27); // fnmadd d30, d4, d1, d27 + __ fmaddh(v18, v10, v26, v7); // fmadd h18, h10, h26, h7 + __ fmadds(v7, v15, v29, v0); // fmadd s7, s15, s29, s0 + __ fmsubs(v23, v0, v12, v24); // fmsub s23, s0, s12, s24 + __ fnmadds(v14, v13, v8, v15); // fnmadd s14, s13, s8, s15 + __ fnmadds(v7, v9, v20, v19); // fnmadd s7, s9, s20, s19 + __ fmaddd(v29, v31, v16, v2); // fmadd d29, d31, d16, d2 + __ fmsubd(v9, v16, v21, v30); // fmsub d9, d16, d21, d30 + __ fnmaddd(v4, v1, v27, v25); // fnmadd d4, d1, d27, d25 + __ fnmaddd(v24, v14, v21, v13); // fnmadd d24, d14, d21, d13 // TwoRegFloatOp - __ fmovs(v25, v24); // fmov s25, s24 - __ fabss(v14, v21); // fabs s14, s21 - __ fnegs(v13, v6); // fneg s13, s6 - __ fsqrts(v12, v25); // fsqrt s12, s25 - __ fcvts(v25, v30); // fcvt d25, s30 - __ fcvtsh(v28, v21); // fcvt h28, s21 - __ fcvths(v16, v23); // fcvt s16, h23 - __ fmovd(v5, v29); // fmov d5, d29 - __ fabsd(v22, v19); // fabs d22, d19 - __ fnegd(v13, v20); // fneg d13, d20 - __ fsqrtd(v19, v28); // fsqrt d19, d28 - __ fcvtd(v18, v6); // fcvt s18, d6 - __ fsqrth(v14, v7); // fsqrt h14, h7 + __ fmovs(v6, v12); // fmov s6, s12 + __ fabss(v25, v25); // fabs s25, s25 + __ fnegs(v30, v28); // fneg s30, s28 + __ fsqrts(v21, v16); // fsqrt s21, s16 + __ fcvts(v23, v5); // fcvt d23, s5 + __ fcvtsh(v29, v22); // fcvt h29, s22 + __ fcvths(v19, v13); // fcvt s19, h13 + __ fmovd(v20, v19); // fmov d20, d19 + __ fabsd(v28, v18); // fabs d28, d18 + __ fnegd(v6, v14); // fneg d6, d14 + __ fsqrtd(v7, v28); // fsqrt d7, d28 + __ fcvtd(v26, v17); // fcvt s26, d17 + __ fsqrth(v6, v1); // fsqrt h6, h1 // FloatConvertOp - __ fcvtzsw(r28, v26); // fcvtzs w28, s26 - __ fcvtzs(r17, v6); // fcvtzs x17, s6 - __ fcvtzdw(r1, v4); // fcvtzs w1, d4 - __ fcvtzd(r13, v21); // fcvtzs x13, d21 - __ scvtfws(v7, r21); // scvtf s7, w21 - __ scvtfs(v27, r23); // scvtf s27, x23 - __ scvtfwd(v13, r20); // scvtf d13, w20 - __ scvtfd(v31, r27); // scvtf d31, x27 - __ fcvtassw(r10, v21); // fcvtas w10, s21 - __ fcvtasd(r5, v17); // fcvtas x5, d17 - __ fcvtmssw(r11, v14); // fcvtms w11, s14 - __ fcvtmsd(r13, v21); // fcvtms x13, d21 - __ fmovs(r26, v14); // fmov w26, s14 - __ fmovd(r4, v24); // fmov x4, d24 - __ fmovs(v24, r29); // fmov s24, w29 - __ fmovd(v12, r14); // fmov d12, x14 + __ fcvtzsw(r4, v14); // fcvtzs w4, s14 + __ fcvtzs(r20, v7); // fcvtzs x20, s7 + __ fcvtzdw(r21, v27); // fcvtzs w21, d27 + __ fcvtzd(r23, v13); // fcvtzs x23, d13 + __ scvtfws(v20, r30); // scvtf s20, w30 + __ scvtfs(v28, r10); // scvtf s28, x10 + __ scvtfwd(v21, r5); // scvtf d21, w5 + __ scvtfd(v17, r11); // scvtf d17, x11 + __ fcvtassw(r13, v14); // fcvtas w13, s14 + __ fcvtasd(r20, v27); // fcvtas x20, d27 + __ fcvtmssw(r14, v4); // fcvtms w14, s4 + __ fcvtmsd(r23, v24); // fcvtms x23, d24 + __ fmovs(r29, v12); // fmov w29, s12 + __ fmovd(r14, v17); // fmov x14, d17 + __ fmovs(v28, r21); // fmov s28, w21 + __ fmovd(v0, r6); // fmov d0, x6 // TwoRegFloatOp - __ fcmps(v17, v28); // fcmp s17, s28 - __ fcmpd(v22, v0); // fcmp d22, d0 + __ fcmps(v27, v18); // fcmp s27, s18 + __ fcmpd(v27, v13); // fcmp d27, d13 __ fcmps(v6, 0.0); // fcmp s6, #0.0 - __ fcmpd(v27, 0.0); // fcmp d27, #0.0 + __ fcmpd(v0, 0.0); // fcmp d0, #0.0 // LoadStorePairOp - __ stpw(r27, r12, Address(r6, -32)); // stp w27, w12, [x6, #-32] - __ ldpw(r14, r11, Address(r19, -256)); // ldp w14, w11, [x19, #-256] - __ ldpsw(r0, r12, Address(r15, -48)); // ldpsw x0, x12, [x15, #-48] - __ stp(r9, r23, Address(r23, 32)); // stp x9, x23, [x23, #32] - __ ldp(r15, r4, Address(r26, -176)); // ldp x15, x4, [x26, #-176] + __ stpw(r4, r19, Address(r15, 128)); // stp w4, w19, [x15, #128] + __ ldpw(r14, r0, Address(r30, -112)); // ldp w14, w0, [x30, #-112] + __ ldpsw(r24, r7, Address(r23, -96)); // ldpsw x24, x7, [x23, #-96] + __ stp(r0, r26, Address(r15, 128)); // stp x0, x26, [x15, #128] + __ ldp(r26, r6, Address(r8, -208)); // ldp x26, x6, [x8, #-208] // LoadStorePairOp - __ stpw(r17, r8, Address(__ pre(r6, -160))); // stp w17, w8, [x6, #-160]! - __ ldpw(r7, r2, Address(__ pre(r4, -112))); // ldp w7, w2, [x4, #-112]! - __ ldpsw(r14, r9, Address(__ pre(r22, -16))); // ldpsw x14, x9, [x22, #-16]! - __ stp(r13, r20, Address(__ pre(r24, -256))); // stp x13, x20, [x24, #-256]! - __ ldp(r8, r11, Address(__ pre(r10, 96))); // ldp x8, x11, [x10, #96]! + __ stpw(r15, r10, Address(__ pre(r7, -112))); // stp w15, w10, [x7, #-112]! + __ ldpw(r1, r30, Address(__ pre(r14, -224))); // ldp w1, w30, [x14, #-224]! + __ ldpsw(r20, r29, Address(__ pre(r23, -144))); // ldpsw x20, x29, [x23, #-144]! + __ stp(r3, r13, Address(__ pre(r8, 96))); // stp x3, x13, [x8, #96]! + __ ldp(r5, r25, Address(__ pre(r16, -112))); // ldp x5, x25, [x16, #-112]! // LoadStorePairOp - __ stpw(r24, r5, Address(__ post(r16, -112))); // stp w24, w5, [x16], #-112 - __ ldpw(r0, r26, Address(__ post(r9, -128))); // ldp w0, w26, [x9], #-128 - __ ldpsw(r24, r2, Address(__ post(r17, -128))); // ldpsw x24, x2, [x17], #-128 - __ stp(r26, r17, Address(__ post(r14, -48))); // stp x26, x17, [x14], #-48 - __ ldp(r30, r21, Address(__ post(r29, 48))); // ldp x30, x21, [x29], #48 + __ stpw(r17, r5, Address(__ post(r0, -128))); // stp w17, w5, [x0], #-128 + __ ldpw(r19, r12, Address(__ post(r24, 80))); // ldp w19, w12, [x24], #80 + __ ldpsw(r17, r14, Address(__ post(r15, -240))); // ldpsw x17, x14, [x15], #-240 + __ stp(r10, r17, Address(__ post(r30, 48))); // stp x10, x17, [x30], #48 + __ ldp(r23, r10, Address(__ post(r8, 16))); // ldp x23, x10, [x8], #16 // LoadStorePairOp - __ stnpw(r17, r23, Address(r10, -112)); // stnp w17, w23, [x10, #-112] - __ ldnpw(r26, r6, Address(r30, -160)); // ldnp w26, w6, [x30, #-160] - __ stnp(r30, r8, Address(r20, 64)); // stnp x30, x8, [x20, #64] - __ ldnp(r22, r29, Address(r9, 48)); // ldnp x22, x29, [x9, #48] + __ stnpw(r10, r30, Address(r26, 128)); // stnp w10, w30, [x26, #128] + __ ldnpw(r20, r24, Address(r8, -176)); // ldnp w20, w24, [x8, #-176] + __ stnp(r25, r9, Address(r21, -224)); // stnp x25, x9, [x21, #-224] + __ ldnp(r3, r22, Address(r9, 112)); // ldnp x3, x22, [x9, #112] // LdStNEONOp - __ ld1(v13, __ T8B, Address(r1)); // ld1 {v13.8B}, [x1] - __ ld1(v1, v2, __ T16B, Address(__ post(r16, 32))); // ld1 {v1.16B, v2.16B}, [x16], 32 - __ ld1(v22, v23, v24, __ T1D, Address(__ post(r25, r19))); // ld1 {v22.1D, v23.1D, v24.1D}, [x25], x19 - __ ld1(v25, v26, v27, v28, __ T8H, Address(__ post(r26, 64))); // ld1 {v25.8H, v26.8H, v27.8H, v28.8H}, [x26], 64 - __ ld1r(v9, __ T8B, Address(r15)); // ld1r {v9.8B}, [x15] - __ ld1r(v12, __ T4S, Address(__ post(r25, 4))); // ld1r {v12.4S}, [x25], 4 - __ ld1r(v4, __ T1D, Address(__ post(r14, r29))); // ld1r {v4.1D}, [x14], x29 - __ ld2(v17, v18, __ T2D, Address(r17)); // ld2 {v17.2D, v18.2D}, [x17] - __ ld2(v23, v24, __ T4H, Address(__ post(r27, 16))); // ld2 {v23.4H, v24.4H}, [x27], 16 - __ ld2r(v2, v3, __ T16B, Address(r24)); // ld2r {v2.16B, v3.16B}, [x24] - __ ld2r(v11, v12, __ T2S, Address(__ post(r0, 8))); // ld2r {v11.2S, v12.2S}, [x0], 8 - __ ld2r(v2, v3, __ T2D, Address(__ post(r12, r22))); // ld2r {v2.2D, v3.2D}, [x12], x22 - __ ld3(v21, v22, v23, __ T4S, Address(__ post(r13, r13))); // ld3 {v21.4S, v22.4S, v23.4S}, [x13], x13 - __ ld3(v12, v13, v14, __ T2S, Address(r11)); // ld3 {v12.2S, v13.2S, v14.2S}, [x11] - __ ld3r(v18, v19, v20, __ T8H, Address(r14)); // ld3r {v18.8H, v19.8H, v20.8H}, [x14] - __ ld3r(v25, v26, v27, __ T4S, Address(__ post(r21, 12))); // ld3r {v25.4S, v26.4S, v27.4S}, [x21], 12 - __ ld3r(v20, v21, v22, __ T1D, Address(__ post(r16, r27))); // ld3r {v20.1D, v21.1D, v22.1D}, [x16], x27 - __ ld4(v0, v1, v2, v3, __ T8H, Address(__ post(r1, 64))); // ld4 {v0.8H, v1.8H, v2.8H, v3.8H}, [x1], 64 - __ ld4(v0, v1, v2, v3, __ T8B, Address(__ post(r27, r29))); // ld4 {v0.8B, v1.8B, v2.8B, v3.8B}, [x27], x29 - __ ld4r(v18, v19, v20, v21, __ T8B, Address(r17)); // ld4r {v18.8B, v19.8B, v20.8B, v21.8B}, [x17] - __ ld4r(v5, v6, v7, v8, __ T4H, Address(__ post(r24, 8))); // ld4r {v5.4H, v6.4H, v7.4H, v8.4H}, [x24], 8 - __ ld4r(v28, v29, v30, v31, __ T2S, Address(__ post(r5, r20))); // ld4r {v28.2S, v29.2S, v30.2S, v31.2S}, [x5], x20 + __ ld1(v31, __ T8B, Address(r30)); // ld1 {v31.8B}, [x30] + __ ld1(v21, v22, __ T16B, Address(__ post(r5, 32))); // ld1 {v21.16B, v22.16B}, [x5], 32 + __ ld1(v25, v26, v27, __ T1D, Address(__ post(r9, r16))); // ld1 {v25.1D, v26.1D, v27.1D}, [x9], x16 + __ ld1(v16, v17, v18, v19, __ T8H, Address(__ post(r12, 64))); // ld1 {v16.8H, v17.8H, v18.8H, v19.8H}, [x12], 64 + __ ld1r(v24, __ T8B, Address(r7)); // ld1r {v24.8B}, [x7] + __ ld1r(v27, __ T4S, Address(__ post(r16, 4))); // ld1r {v27.4S}, [x16], 4 + __ ld1r(v26, __ T1D, Address(__ post(r11, r7))); // ld1r {v26.1D}, [x11], x7 + __ ld2(v31, v0, __ T2D, Address(r12)); // ld2 {v31.2D, v0.2D}, [x12] + __ ld2(v16, v17, __ T4H, Address(__ post(r9, 16))); // ld2 {v16.4H, v17.4H}, [x9], 16 + __ ld2r(v31, v0, __ T16B, Address(r6)); // ld2r {v31.16B, v0.16B}, [x6] + __ ld2r(v7, v8, __ T2S, Address(__ post(r23, 8))); // ld2r {v7.2S, v8.2S}, [x23], 8 + __ ld2r(v4, v5, __ T2D, Address(__ post(r6, r1))); // ld2r {v4.2D, v5.2D}, [x6], x1 + __ ld3(v4, v5, v6, __ T4S, Address(__ post(r19, r15))); // ld3 {v4.4S, v5.4S, v6.4S}, [x19], x15 + __ ld3(v25, v26, v27, __ T2S, Address(r14)); // ld3 {v25.2S, v26.2S, v27.2S}, [x14] + __ ld3r(v26, v27, v28, __ T8H, Address(r28)); // ld3r {v26.8H, v27.8H, v28.8H}, [x28] + __ ld3r(v26, v27, v28, __ T4S, Address(__ post(r5, 12))); // ld3r {v26.4S, v27.4S, v28.4S}, [x5], 12 + __ ld3r(v2, v3, v4, __ T1D, Address(__ post(r14, r10))); // ld3r {v2.1D, v3.1D, v4.1D}, [x14], x10 + __ ld4(v30, v31, v0, v1, __ T8H, Address(__ post(r6, 64))); // ld4 {v30.8H, v31.8H, v0.8H, v1.8H}, [x6], 64 + __ ld4(v26, v27, v28, v29, __ T8B, Address(__ post(r11, r25))); // ld4 {v26.8B, v27.8B, v28.8B, v29.8B}, [x11], x25 + __ ld4r(v17, v18, v19, v20, __ T8B, Address(r12)); // ld4r {v17.8B, v18.8B, v19.8B, v20.8B}, [x12] + __ ld4r(v18, v19, v20, v21, __ T4H, Address(__ post(r10, 8))); // ld4r {v18.4H, v19.4H, v20.4H, v21.4H}, [x10], 8 + __ ld4r(v13, v14, v15, v16, __ T2S, Address(__ post(r29, r26))); // ld4r {v13.2S, v14.2S, v15.2S, v16.2S}, [x29], x26 // NEONReduceInstruction - __ addv(v1, __ T8B, v2); // addv b1, v2.8B - __ addv(v20, __ T16B, v21); // addv b20, v21.16B + __ addv(v10, __ T8B, v11); // addv b10, v11.8B + __ addv(v29, __ T16B, v30); // addv b29, v30.16B __ addv(v29, __ T4H, v30); // addv h29, v30.4H - __ addv(v16, __ T8H, v17); // addv h16, v17.8H - __ addv(v13, __ T4S, v14); // addv s13, v14.4S + __ addv(v19, __ T8H, v20); // addv h19, v20.8H + __ addv(v22, __ T4S, v23); // addv s22, v23.4S __ smaxv(v10, __ T8B, v11); // smaxv b10, v11.8B - __ smaxv(v29, __ T16B, v30); // smaxv b29, v30.16B - __ smaxv(v29, __ T4H, v30); // smaxv h29, v30.4H - __ smaxv(v19, __ T8H, v20); // smaxv h19, v20.8H - __ smaxv(v22, __ T4S, v23); // smaxv s22, v23.4S - __ fmaxv(v10, __ T4S, v11); // fmaxv s10, v11.4S - __ sminv(v4, __ T8B, v5); // sminv b4, v5.8B - __ uminv(v31, __ T8B, v0); // uminv b31, v0.8B - __ sminv(v21, __ T16B, v22); // sminv b21, v22.16B - __ uminv(v8, __ T16B, v9); // uminv b8, v9.16B - __ sminv(v31, __ T4H, v0); // sminv h31, v0.4H - __ uminv(v19, __ T4H, v20); // uminv h19, v20.4H - __ sminv(v10, __ T8H, v11); // sminv h10, v11.8H - __ uminv(v28, __ T8H, v29); // uminv h28, v29.8H - __ sminv(v2, __ T4S, v3); // sminv s2, v3.4S - __ uminv(v25, __ T4S, v26); // uminv s25, v26.4S - __ fminv(v5, __ T4S, v6); // fminv s5, v6.4S - __ fmaxp(v3, v4, __ S); // fmaxp s3, v4.2S - __ fmaxp(v8, v9, __ D); // fmaxp d8, v9.2D - __ fminp(v22, v23, __ S); // fminp s22, v23.2S - __ fminp(v19, v20, __ D); // fminp d19, v20.2D + __ smaxv(v4, __ T16B, v5); // smaxv b4, v5.16B + __ smaxv(v31, __ T4H, v0); // smaxv h31, v0.4H + __ smaxv(v21, __ T8H, v22); // smaxv h21, v22.8H + __ smaxv(v8, __ T4S, v9); // smaxv s8, v9.4S + __ fmaxv(v31, __ T4S, v0); // fmaxv s31, v0.4S + __ sminv(v19, __ T8B, v20); // sminv b19, v20.8B + __ uminv(v10, __ T8B, v11); // uminv b10, v11.8B + __ sminv(v28, __ T16B, v29); // sminv b28, v29.16B + __ uminv(v2, __ T16B, v3); // uminv b2, v3.16B + __ sminv(v25, __ T4H, v26); // sminv h25, v26.4H + __ uminv(v5, __ T4H, v6); // uminv h5, v6.4H + __ sminv(v3, __ T8H, v4); // sminv h3, v4.8H + __ uminv(v8, __ T8H, v9); // uminv h8, v9.8H + __ sminv(v22, __ T4S, v23); // sminv s22, v23.4S + __ uminv(v19, __ T4S, v20); // uminv s19, v20.4S + __ fminv(v13, __ T4S, v14); // fminv s13, v14.4S + __ fmaxp(v5, v6, __ S); // fmaxp s5, v6.2S + __ fmaxp(v29, v30, __ D); // fmaxp d29, v30.2D + __ fminp(v24, v25, __ S); // fminp s24, v25.2S + __ fminp(v21, v22, __ D); // fminp d21, v22.2D // NEONFloatCompareWithZero - __ fcm(Assembler::GT, v13, __ T2S, v14); // fcmgt v13.2S, v14.2S, #0.0 - __ fcm(Assembler::GT, v5, __ T4S, v6); // fcmgt v5.4S, v6.4S, #0.0 - __ fcm(Assembler::GT, v29, __ T2D, v30); // fcmgt v29.2D, v30.2D, #0.0 + __ fcm(Assembler::GT, v26, __ T2S, v27); // fcmgt v26.2S, v27.2S, #0.0 + __ fcm(Assembler::GT, v24, __ T4S, v25); // fcmgt v24.4S, v25.4S, #0.0 + __ fcm(Assembler::GT, v3, __ T2D, v4); // fcmgt v3.2D, v4.2D, #0.0 __ fcm(Assembler::GE, v24, __ T2S, v25); // fcmge v24.2S, v25.2S, #0.0 - __ fcm(Assembler::GE, v21, __ T4S, v22); // fcmge v21.4S, v22.4S, #0.0 - __ fcm(Assembler::GE, v26, __ T2D, v27); // fcmge v26.2D, v27.2D, #0.0 - __ fcm(Assembler::EQ, v24, __ T2S, v25); // fcmeq v24.2S, v25.2S, #0.0 - __ fcm(Assembler::EQ, v3, __ T4S, v4); // fcmeq v3.4S, v4.4S, #0.0 - __ fcm(Assembler::EQ, v24, __ T2D, v25); // fcmeq v24.2D, v25.2D, #0.0 - __ fcm(Assembler::LT, v26, __ T2S, v27); // fcmlt v26.2S, v27.2S, #0.0 - __ fcm(Assembler::LT, v23, __ T4S, v24); // fcmlt v23.4S, v24.4S, #0.0 - __ fcm(Assembler::LT, v15, __ T2D, v16); // fcmlt v15.2D, v16.2D, #0.0 - __ fcm(Assembler::LE, v21, __ T2S, v22); // fcmle v21.2S, v22.2S, #0.0 - __ fcm(Assembler::LE, v3, __ T4S, v4); // fcmle v3.4S, v4.4S, #0.0 - __ fcm(Assembler::LE, v24, __ T2D, v25); // fcmle v24.2D, v25.2D, #0.0 + __ fcm(Assembler::GE, v26, __ T4S, v27); // fcmge v26.4S, v27.4S, #0.0 + __ fcm(Assembler::GE, v23, __ T2D, v24); // fcmge v23.2D, v24.2D, #0.0 + __ fcm(Assembler::EQ, v15, __ T2S, v16); // fcmeq v15.2S, v16.2S, #0.0 + __ fcm(Assembler::EQ, v21, __ T4S, v22); // fcmeq v21.4S, v22.4S, #0.0 + __ fcm(Assembler::EQ, v3, __ T2D, v4); // fcmeq v3.2D, v4.2D, #0.0 + __ fcm(Assembler::LT, v24, __ T2S, v25); // fcmlt v24.2S, v25.2S, #0.0 + __ fcm(Assembler::LT, v8, __ T4S, v9); // fcmlt v8.4S, v9.4S, #0.0 + __ fcm(Assembler::LT, v25, __ T2D, v26); // fcmlt v25.2D, v26.2D, #0.0 + __ fcm(Assembler::LE, v20, __ T2S, v21); // fcmle v20.2S, v21.2S, #0.0 + __ fcm(Assembler::LE, v16, __ T4S, v17); // fcmle v16.4S, v17.4S, #0.0 + __ fcm(Assembler::LE, v17, __ T2D, v18); // fcmle v17.2D, v18.2D, #0.0 // TwoRegNEONOp - __ absr(v8, __ T8B, v9); // abs v8.8B, v9.8B - __ absr(v25, __ T16B, v26); // abs v25.16B, v26.16B - __ absr(v20, __ T4H, v21); // abs v20.4H, v21.4H - __ absr(v16, __ T8H, v17); // abs v16.8H, v17.8H - __ absr(v17, __ T2S, v18); // abs v17.2S, v18.2S - __ absr(v2, __ T4S, v3); // abs v2.4S, v3.4S - __ absr(v1, __ T2D, v2); // abs v1.2D, v2.2D - __ fabs(v0, __ T2S, v1); // fabs v0.2S, v1.2S - __ fabs(v24, __ T4S, v25); // fabs v24.4S, v25.4S - __ fabs(v4, __ T2D, v5); // fabs v4.2D, v5.2D - __ fabs(v3, __ T4H, v4); // fabs v3.4H, v4.4H - __ fabs(v12, __ T8H, v13); // fabs v12.8H, v13.8H - __ fneg(v31, __ T2S, v0); // fneg v31.2S, v0.2S - __ fneg(v28, __ T4S, v29); // fneg v28.4S, v29.4S - __ fneg(v10, __ T2D, v11); // fneg v10.2D, v11.2D - __ fneg(v26, __ T4H, v27); // fneg v26.4H, v27.4H - __ fneg(v2, __ T8H, v3); // fneg v2.8H, v3.8H - __ fsqrt(v12, __ T2S, v13); // fsqrt v12.2S, v13.2S - __ fsqrt(v18, __ T4S, v19); // fsqrt v18.4S, v19.4S - __ fsqrt(v31, __ T2D, v0); // fsqrt v31.2D, v0.2D - __ fsqrt(v1, __ T4H, v2); // fsqrt v1.4H, v2.4H - __ fsqrt(v13, __ T8H, v14); // fsqrt v13.8H, v14.8H - __ notr(v29, __ T8B, v30); // not v29.8B, v30.8B - __ notr(v0, __ T16B, v1); // not v0.16B, v1.16B + __ absr(v2, __ T8B, v3); // abs v2.8B, v3.8B + __ absr(v1, __ T16B, v2); // abs v1.16B, v2.16B + __ absr(v0, __ T4H, v1); // abs v0.4H, v1.4H + __ absr(v24, __ T8H, v25); // abs v24.8H, v25.8H + __ absr(v4, __ T2S, v5); // abs v4.2S, v5.2S + __ absr(v3, __ T4S, v4); // abs v3.4S, v4.4S + __ absr(v12, __ T2D, v13); // abs v12.2D, v13.2D + __ fabs(v31, __ T2S, v0); // fabs v31.2S, v0.2S + __ fabs(v28, __ T4S, v29); // fabs v28.4S, v29.4S + __ fabs(v10, __ T2D, v11); // fabs v10.2D, v11.2D + __ fabs(v26, __ T4H, v27); // fabs v26.4H, v27.4H + __ fabs(v2, __ T8H, v3); // fabs v2.8H, v3.8H + __ fneg(v12, __ T2S, v13); // fneg v12.2S, v13.2S + __ fneg(v18, __ T4S, v19); // fneg v18.4S, v19.4S + __ fneg(v31, __ T2D, v0); // fneg v31.2D, v0.2D + __ fneg(v1, __ T4H, v2); // fneg v1.4H, v2.4H + __ fneg(v13, __ T8H, v14); // fneg v13.8H, v14.8H + __ fsqrt(v29, __ T2S, v30); // fsqrt v29.2S, v30.2S + __ fsqrt(v0, __ T4S, v1); // fsqrt v0.4S, v1.4S + __ fsqrt(v19, __ T2D, v20); // fsqrt v19.2D, v20.2D + __ fsqrt(v12, __ T4H, v13); // fsqrt v12.4H, v13.4H + __ fsqrt(v17, __ T8H, v18); // fsqrt v17.8H, v18.8H + __ notr(v22, __ T8B, v23); // not v22.8B, v23.8B + __ notr(v13, __ T16B, v14); // not v13.16B, v14.16B // ThreeRegNEONOp - __ andr(v19, __ T8B, v20, v21); // and v19.8B, v20.8B, v21.8B - __ andr(v12, __ T16B, v13, v14); // and v12.16B, v13.16B, v14.16B - __ orr(v17, __ T8B, v18, v19); // orr v17.8B, v18.8B, v19.8B - __ orr(v22, __ T16B, v23, v24); // orr v22.16B, v23.16B, v24.16B - __ eor(v13, __ T8B, v14, v15); // eor v13.8B, v14.8B, v15.8B + __ andr(v28, __ T8B, v29, v30); // and v28.8B, v29.8B, v30.8B + __ andr(v30, __ T16B, v31, v0); // and v30.16B, v31.16B, v0.16B + __ orr(v31, __ T8B, v0, v1); // orr v31.8B, v0.8B, v1.8B + __ orr(v1, __ T16B, v2, v3); // orr v1.16B, v2.16B, v3.16B + __ eor(v26, __ T8B, v27, v28); // eor v26.8B, v27.8B, v28.8B __ eor(v28, __ T16B, v29, v30); // eor v28.16B, v29.16B, v30.16B - __ addv(v30, __ T8B, v31, v0); // add v30.8B, v31.8B, v0.8B - __ addv(v31, __ T16B, v0, v1); // add v31.16B, v0.16B, v1.16B - __ addv(v1, __ T4H, v2, v3); // add v1.4H, v2.4H, v3.4H - __ addv(v26, __ T8H, v27, v28); // add v26.8H, v27.8H, v28.8H - __ addv(v28, __ T2S, v29, v30); // add v28.2S, v29.2S, v30.2S - __ addv(v4, __ T4S, v5, v6); // add v4.4S, v5.4S, v6.4S - __ addv(v30, __ T2D, v31, v0); // add v30.2D, v31.2D, v0.2D - __ sqaddv(v4, __ T8B, v5, v6); // sqadd v4.8B, v5.8B, v6.8B - __ sqaddv(v6, __ T16B, v7, v8); // sqadd v6.16B, v7.16B, v8.16B - __ sqaddv(v30, __ T4H, v31, v0); // sqadd v30.4H, v31.4H, v0.4H - __ sqaddv(v26, __ T8H, v27, v28); // sqadd v26.8H, v27.8H, v28.8H - __ sqaddv(v18, __ T2S, v19, v20); // sqadd v18.2S, v19.2S, v20.2S - __ sqaddv(v9, __ T4S, v10, v11); // sqadd v9.4S, v10.4S, v11.4S - __ sqaddv(v8, __ T2D, v9, v10); // sqadd v8.2D, v9.2D, v10.2D - __ uqaddv(v12, __ T8B, v13, v14); // uqadd v12.8B, v13.8B, v14.8B + __ addv(v4, __ T8B, v5, v6); // add v4.8B, v5.8B, v6.8B + __ addv(v30, __ T16B, v31, v0); // add v30.16B, v31.16B, v0.16B + __ addv(v4, __ T4H, v5, v6); // add v4.4H, v5.4H, v6.4H + __ addv(v6, __ T8H, v7, v8); // add v6.8H, v7.8H, v8.8H + __ addv(v30, __ T2S, v31, v0); // add v30.2S, v31.2S, v0.2S + __ addv(v26, __ T4S, v27, v28); // add v26.4S, v27.4S, v28.4S + __ addv(v18, __ T2D, v19, v20); // add v18.2D, v19.2D, v20.2D + __ sqaddv(v9, __ T8B, v10, v11); // sqadd v9.8B, v10.8B, v11.8B + __ sqaddv(v8, __ T16B, v9, v10); // sqadd v8.16B, v9.16B, v10.16B + __ sqaddv(v12, __ T4H, v13, v14); // sqadd v12.4H, v13.4H, v14.4H + __ sqaddv(v0, __ T8H, v1, v2); // sqadd v0.8H, v1.8H, v2.8H + __ sqaddv(v20, __ T2S, v21, v22); // sqadd v20.2S, v21.2S, v22.2S + __ sqaddv(v1, __ T4S, v2, v3); // sqadd v1.4S, v2.4S, v3.4S + __ sqaddv(v24, __ T2D, v25, v26); // sqadd v24.2D, v25.2D, v26.2D + __ uqaddv(v2, __ T8B, v3, v4); // uqadd v2.8B, v3.8B, v4.8B __ uqaddv(v0, __ T16B, v1, v2); // uqadd v0.16B, v1.16B, v2.16B - __ uqaddv(v20, __ T4H, v21, v22); // uqadd v20.4H, v21.4H, v22.4H - __ uqaddv(v1, __ T8H, v2, v3); // uqadd v1.8H, v2.8H, v3.8H - __ uqaddv(v24, __ T2S, v25, v26); // uqadd v24.2S, v25.2S, v26.2S - __ uqaddv(v2, __ T4S, v3, v4); // uqadd v2.4S, v3.4S, v4.4S - __ uqaddv(v0, __ T2D, v1, v2); // uqadd v0.2D, v1.2D, v2.2D - __ fadd(v9, __ T2S, v10, v11); // fadd v9.2S, v10.2S, v11.2S - __ fadd(v24, __ T4S, v25, v26); // fadd v24.4S, v25.4S, v26.4S - __ fadd(v26, __ T2D, v27, v28); // fadd v26.2D, v27.2D, v28.2D - __ fadd(v16, __ T4H, v17, v18); // fadd v16.4H, v17.4H, v18.4H - __ fadd(v30, __ T8H, v31, v0); // fadd v30.8H, v31.8H, v0.8H - __ subv(v3, __ T8B, v4, v5); // sub v3.8B, v4.8B, v5.8B - __ subv(v10, __ T16B, v11, v12); // sub v10.16B, v11.16B, v12.16B - __ subv(v23, __ T4H, v24, v25); // sub v23.4H, v24.4H, v25.4H - __ subv(v10, __ T8H, v11, v12); // sub v10.8H, v11.8H, v12.8H - __ subv(v4, __ T2S, v5, v6); // sub v4.2S, v5.2S, v6.2S - __ subv(v18, __ T4S, v19, v20); // sub v18.4S, v19.4S, v20.4S - __ subv(v2, __ T2D, v3, v4); // sub v2.2D, v3.2D, v4.2D - __ sqsubv(v11, __ T8B, v12, v13); // sqsub v11.8B, v12.8B, v13.8B - __ sqsubv(v8, __ T16B, v9, v10); // sqsub v8.16B, v9.16B, v10.16B - __ sqsubv(v10, __ T4H, v11, v12); // sqsub v10.4H, v11.4H, v12.4H - __ sqsubv(v15, __ T8H, v16, v17); // sqsub v15.8H, v16.8H, v17.8H - __ sqsubv(v17, __ T2S, v18, v19); // sqsub v17.2S, v18.2S, v19.2S - __ sqsubv(v2, __ T4S, v3, v4); // sqsub v2.4S, v3.4S, v4.4S - __ sqsubv(v10, __ T2D, v11, v12); // sqsub v10.2D, v11.2D, v12.2D - __ uqsubv(v12, __ T8B, v13, v14); // uqsub v12.8B, v13.8B, v14.8B - __ uqsubv(v12, __ T16B, v13, v14); // uqsub v12.16B, v13.16B, v14.16B - __ uqsubv(v15, __ T4H, v16, v17); // uqsub v15.4H, v16.4H, v17.4H - __ uqsubv(v13, __ T8H, v14, v15); // uqsub v13.8H, v14.8H, v15.8H - __ uqsubv(v2, __ T2S, v3, v4); // uqsub v2.2S, v3.2S, v4.2S - __ uqsubv(v7, __ T4S, v8, v9); // uqsub v7.4S, v8.4S, v9.4S - __ uqsubv(v20, __ T2D, v21, v22); // uqsub v20.2D, v21.2D, v22.2D - __ fsub(v26, __ T2S, v27, v28); // fsub v26.2S, v27.2S, v28.2S - __ fsub(v16, __ T4S, v17, v18); // fsub v16.4S, v17.4S, v18.4S - __ fsub(v4, __ T2D, v5, v6); // fsub v4.2D, v5.2D, v6.2D - __ fsub(v2, __ T4H, v3, v4); // fsub v2.4H, v3.4H, v4.4H - __ fsub(v4, __ T8H, v5, v6); // fsub v4.8H, v5.8H, v6.8H - __ mulv(v12, __ T8B, v13, v14); // mul v12.8B, v13.8B, v14.8B - __ mulv(v18, __ T16B, v19, v20); // mul v18.16B, v19.16B, v20.16B - __ mulv(v21, __ T4H, v22, v23); // mul v21.4H, v22.4H, v23.4H - __ mulv(v16, __ T8H, v17, v18); // mul v16.8H, v17.8H, v18.8H - __ mulv(v18, __ T2S, v19, v20); // mul v18.2S, v19.2S, v20.2S - __ mulv(v11, __ T4S, v12, v13); // mul v11.4S, v12.4S, v13.4S - __ fabd(v21, __ T2S, v22, v23); // fabd v21.2S, v22.2S, v23.2S - __ fabd(v23, __ T4S, v24, v25); // fabd v23.4S, v24.4S, v25.4S - __ fabd(v12, __ T2D, v13, v14); // fabd v12.2D, v13.2D, v14.2D - __ fabd(v26, __ T4H, v27, v28); // fabd v26.4H, v27.4H, v28.4H - __ fabd(v23, __ T8H, v24, v25); // fabd v23.8H, v24.8H, v25.8H - __ faddp(v28, __ T2S, v29, v30); // faddp v28.2S, v29.2S, v30.2S - __ faddp(v14, __ T4S, v15, v16); // faddp v14.4S, v15.4S, v16.4S - __ faddp(v11, __ T2D, v12, v13); // faddp v11.2D, v12.2D, v13.2D - __ faddp(v24, __ T4H, v25, v26); // faddp v24.4H, v25.4H, v26.4H - __ faddp(v1, __ T8H, v2, v3); // faddp v1.8H, v2.8H, v3.8H - __ fmul(v12, __ T2S, v13, v14); // fmul v12.2S, v13.2S, v14.2S - __ fmul(v31, __ T4S, v0, v1); // fmul v31.4S, v0.4S, v1.4S - __ fmul(v10, __ T2D, v11, v12); // fmul v10.2D, v11.2D, v12.2D - __ fmul(v16, __ T4H, v17, v18); // fmul v16.4H, v17.4H, v18.4H - __ fmul(v7, __ T8H, v8, v9); // fmul v7.8H, v8.8H, v9.8H - __ mlav(v2, __ T4H, v3, v4); // mla v2.4H, v3.4H, v4.4H + __ uqaddv(v9, __ T4H, v10, v11); // uqadd v9.4H, v10.4H, v11.4H + __ uqaddv(v24, __ T8H, v25, v26); // uqadd v24.8H, v25.8H, v26.8H + __ uqaddv(v26, __ T2S, v27, v28); // uqadd v26.2S, v27.2S, v28.2S + __ uqaddv(v16, __ T4S, v17, v18); // uqadd v16.4S, v17.4S, v18.4S + __ uqaddv(v30, __ T2D, v31, v0); // uqadd v30.2D, v31.2D, v0.2D + __ fadd(v3, __ T2S, v4, v5); // fadd v3.2S, v4.2S, v5.2S + __ fadd(v10, __ T4S, v11, v12); // fadd v10.4S, v11.4S, v12.4S + __ fadd(v23, __ T2D, v24, v25); // fadd v23.2D, v24.2D, v25.2D + __ fadd(v10, __ T4H, v11, v12); // fadd v10.4H, v11.4H, v12.4H + __ fadd(v4, __ T8H, v5, v6); // fadd v4.8H, v5.8H, v6.8H + __ subv(v18, __ T8B, v19, v20); // sub v18.8B, v19.8B, v20.8B + __ subv(v2, __ T16B, v3, v4); // sub v2.16B, v3.16B, v4.16B + __ subv(v11, __ T4H, v12, v13); // sub v11.4H, v12.4H, v13.4H + __ subv(v8, __ T8H, v9, v10); // sub v8.8H, v9.8H, v10.8H + __ subv(v10, __ T2S, v11, v12); // sub v10.2S, v11.2S, v12.2S + __ subv(v15, __ T4S, v16, v17); // sub v15.4S, v16.4S, v17.4S + __ subv(v17, __ T2D, v18, v19); // sub v17.2D, v18.2D, v19.2D + __ sqsubv(v2, __ T8B, v3, v4); // sqsub v2.8B, v3.8B, v4.8B + __ sqsubv(v10, __ T16B, v11, v12); // sqsub v10.16B, v11.16B, v12.16B + __ sqsubv(v12, __ T4H, v13, v14); // sqsub v12.4H, v13.4H, v14.4H + __ sqsubv(v12, __ T8H, v13, v14); // sqsub v12.8H, v13.8H, v14.8H + __ sqsubv(v15, __ T2S, v16, v17); // sqsub v15.2S, v16.2S, v17.2S + __ sqsubv(v13, __ T4S, v14, v15); // sqsub v13.4S, v14.4S, v15.4S + __ sqsubv(v2, __ T2D, v3, v4); // sqsub v2.2D, v3.2D, v4.2D + __ uqsubv(v7, __ T8B, v8, v9); // uqsub v7.8B, v8.8B, v9.8B + __ uqsubv(v20, __ T16B, v21, v22); // uqsub v20.16B, v21.16B, v22.16B + __ uqsubv(v26, __ T4H, v27, v28); // uqsub v26.4H, v27.4H, v28.4H + __ uqsubv(v16, __ T8H, v17, v18); // uqsub v16.8H, v17.8H, v18.8H + __ uqsubv(v4, __ T2S, v5, v6); // uqsub v4.2S, v5.2S, v6.2S + __ uqsubv(v2, __ T4S, v3, v4); // uqsub v2.4S, v3.4S, v4.4S + __ uqsubv(v4, __ T2D, v5, v6); // uqsub v4.2D, v5.2D, v6.2D + __ fsub(v12, __ T2S, v13, v14); // fsub v12.2S, v13.2S, v14.2S + __ fsub(v18, __ T4S, v19, v20); // fsub v18.4S, v19.4S, v20.4S + __ fsub(v21, __ T2D, v22, v23); // fsub v21.2D, v22.2D, v23.2D + __ fsub(v16, __ T4H, v17, v18); // fsub v16.4H, v17.4H, v18.4H + __ fsub(v18, __ T8H, v19, v20); // fsub v18.8H, v19.8H, v20.8H + __ mulv(v11, __ T8B, v12, v13); // mul v11.8B, v12.8B, v13.8B + __ mulv(v21, __ T16B, v22, v23); // mul v21.16B, v22.16B, v23.16B + __ mulv(v23, __ T4H, v24, v25); // mul v23.4H, v24.4H, v25.4H + __ mulv(v12, __ T8H, v13, v14); // mul v12.8H, v13.8H, v14.8H + __ mulv(v26, __ T2S, v27, v28); // mul v26.2S, v27.2S, v28.2S + __ mulv(v23, __ T4S, v24, v25); // mul v23.4S, v24.4S, v25.4S + __ fabd(v28, __ T2S, v29, v30); // fabd v28.2S, v29.2S, v30.2S + __ fabd(v14, __ T4S, v15, v16); // fabd v14.4S, v15.4S, v16.4S + __ fabd(v11, __ T2D, v12, v13); // fabd v11.2D, v12.2D, v13.2D + __ fabd(v24, __ T4H, v25, v26); // fabd v24.4H, v25.4H, v26.4H + __ fabd(v1, __ T8H, v2, v3); // fabd v1.8H, v2.8H, v3.8H + __ faddp(v12, __ T2S, v13, v14); // faddp v12.2S, v13.2S, v14.2S + __ faddp(v31, __ T4S, v0, v1); // faddp v31.4S, v0.4S, v1.4S + __ faddp(v10, __ T2D, v11, v12); // faddp v10.2D, v11.2D, v12.2D + __ faddp(v16, __ T4H, v17, v18); // faddp v16.4H, v17.4H, v18.4H + __ faddp(v7, __ T8H, v8, v9); // faddp v7.8H, v8.8H, v9.8H + __ fmul(v2, __ T2S, v3, v4); // fmul v2.2S, v3.2S, v4.2S + __ fmul(v3, __ T4S, v4, v5); // fmul v3.4S, v4.4S, v5.4S + __ fmul(v13, __ T2D, v14, v15); // fmul v13.2D, v14.2D, v15.2D + __ fmul(v19, __ T4H, v20, v21); // fmul v19.4H, v20.4H, v21.4H + __ fmul(v17, __ T8H, v18, v19); // fmul v17.8H, v18.8H, v19.8H + __ mlav(v16, __ T4H, v17, v18); // mla v16.4H, v17.4H, v18.4H __ mlav(v3, __ T8H, v4, v5); // mla v3.8H, v4.8H, v5.8H - __ mlav(v13, __ T2S, v14, v15); // mla v13.2S, v14.2S, v15.2S - __ mlav(v19, __ T4S, v20, v21); // mla v19.4S, v20.4S, v21.4S - __ fmla(v17, __ T2S, v18, v19); // fmla v17.2S, v18.2S, v19.2S - __ fmla(v16, __ T4S, v17, v18); // fmla v16.4S, v17.4S, v18.4S - __ fmla(v3, __ T2D, v4, v5); // fmla v3.2D, v4.2D, v5.2D - __ fmla(v1, __ T4H, v2, v3); // fmla v1.4H, v2.4H, v3.4H - __ fmla(v11, __ T8H, v12, v13); // fmla v11.8H, v12.8H, v13.8H + __ mlav(v1, __ T2S, v2, v3); // mla v1.2S, v2.2S, v3.2S + __ mlav(v11, __ T4S, v12, v13); // mla v11.4S, v12.4S, v13.4S + __ fmla(v30, __ T2S, v31, v0); // fmla v30.2S, v31.2S, v0.2S + __ fmla(v5, __ T4S, v6, v7); // fmla v5.4S, v6.4S, v7.4S + __ fmla(v8, __ T2D, v9, v10); // fmla v8.2D, v9.2D, v10.2D + __ fmla(v15, __ T4H, v16, v17); // fmla v15.4H, v16.4H, v17.4H + __ fmla(v29, __ T8H, v30, v31); // fmla v29.8H, v30.8H, v31.8H __ mlsv(v30, __ T4H, v31, v0); // mls v30.4H, v31.4H, v0.4H - __ mlsv(v5, __ T8H, v6, v7); // mls v5.8H, v6.8H, v7.8H - __ mlsv(v8, __ T2S, v9, v10); // mls v8.2S, v9.2S, v10.2S - __ mlsv(v15, __ T4S, v16, v17); // mls v15.4S, v16.4S, v17.4S - __ fmls(v29, __ T2S, v30, v31); // fmls v29.2S, v30.2S, v31.2S - __ fmls(v30, __ T4S, v31, v0); // fmls v30.4S, v31.4S, v0.4S - __ fmls(v0, __ T2D, v1, v2); // fmls v0.2D, v1.2D, v2.2D - __ fmls(v20, __ T4H, v21, v22); // fmls v20.4H, v21.4H, v22.4H - __ fmls(v7, __ T8H, v8, v9); // fmls v7.8H, v8.8H, v9.8H - __ fdiv(v20, __ T2S, v21, v22); // fdiv v20.2S, v21.2S, v22.2S - __ fdiv(v23, __ T4S, v24, v25); // fdiv v23.4S, v24.4S, v25.4S - __ fdiv(v28, __ T2D, v29, v30); // fdiv v28.2D, v29.2D, v30.2D - __ fdiv(v21, __ T4H, v22, v23); // fdiv v21.4H, v22.4H, v23.4H - __ fdiv(v27, __ T8H, v28, v29); // fdiv v27.8H, v28.8H, v29.8H - __ maxv(v25, __ T8B, v26, v27); // smax v25.8B, v26.8B, v27.8B + __ mlsv(v0, __ T8H, v1, v2); // mls v0.8H, v1.8H, v2.8H + __ mlsv(v20, __ T2S, v21, v22); // mls v20.2S, v21.2S, v22.2S + __ mlsv(v7, __ T4S, v8, v9); // mls v7.4S, v8.4S, v9.4S + __ fmls(v20, __ T2S, v21, v22); // fmls v20.2S, v21.2S, v22.2S + __ fmls(v23, __ T4S, v24, v25); // fmls v23.4S, v24.4S, v25.4S + __ fmls(v28, __ T2D, v29, v30); // fmls v28.2D, v29.2D, v30.2D + __ fmls(v21, __ T4H, v22, v23); // fmls v21.4H, v22.4H, v23.4H + __ fmls(v27, __ T8H, v28, v29); // fmls v27.8H, v28.8H, v29.8H + __ fdiv(v25, __ T2S, v26, v27); // fdiv v25.2S, v26.2S, v27.2S + __ fdiv(v5, __ T4S, v6, v7); // fdiv v5.4S, v6.4S, v7.4S + __ fdiv(v1, __ T2D, v2, v3); // fdiv v1.2D, v2.2D, v3.2D + __ fdiv(v23, __ T4H, v24, v25); // fdiv v23.4H, v24.4H, v25.4H + __ fdiv(v16, __ T8H, v17, v18); // fdiv v16.8H, v17.8H, v18.8H + __ maxv(v31, __ T8B, v0, v1); // smax v31.8B, v0.8B, v1.8B __ maxv(v5, __ T16B, v6, v7); // smax v5.16B, v6.16B, v7.16B - __ maxv(v1, __ T4H, v2, v3); // smax v1.4H, v2.4H, v3.4H - __ maxv(v23, __ T8H, v24, v25); // smax v23.8H, v24.8H, v25.8H - __ maxv(v16, __ T2S, v17, v18); // smax v16.2S, v17.2S, v18.2S - __ maxv(v31, __ T4S, v0, v1); // smax v31.4S, v0.4S, v1.4S - __ umaxv(v5, __ T8B, v6, v7); // umax v5.8B, v6.8B, v7.8B - __ umaxv(v12, __ T16B, v13, v14); // umax v12.16B, v13.16B, v14.16B - __ umaxv(v9, __ T4H, v10, v11); // umax v9.4H, v10.4H, v11.4H - __ umaxv(v28, __ T8H, v29, v30); // umax v28.8H, v29.8H, v30.8H - __ umaxv(v15, __ T2S, v16, v17); // umax v15.2S, v16.2S, v17.2S - __ umaxv(v29, __ T4S, v30, v31); // umax v29.4S, v30.4S, v31.4S - __ smaxp(v22, __ T8B, v23, v24); // smaxp v22.8B, v23.8B, v24.8B - __ smaxp(v31, __ T16B, v0, v1); // smaxp v31.16B, v0.16B, v1.16B - __ smaxp(v19, __ T4H, v20, v21); // smaxp v19.4H, v20.4H, v21.4H - __ smaxp(v31, __ T8H, v0, v1); // smaxp v31.8H, v0.8H, v1.8H - __ smaxp(v5, __ T2S, v6, v7); // smaxp v5.2S, v6.2S, v7.2S - __ smaxp(v14, __ T4S, v15, v16); // smaxp v14.4S, v15.4S, v16.4S - __ fmax(v18, __ T2S, v19, v20); // fmax v18.2S, v19.2S, v20.2S - __ fmax(v31, __ T4S, v0, v1); // fmax v31.4S, v0.4S, v1.4S - __ fmax(v18, __ T2D, v19, v20); // fmax v18.2D, v19.2D, v20.2D - __ fmax(v27, __ T4H, v28, v29); // fmax v27.4H, v28.4H, v29.4H - __ fmax(v20, __ T8H, v21, v22); // fmax v20.8H, v21.8H, v22.8H - __ minv(v16, __ T8B, v17, v18); // smin v16.8B, v17.8B, v18.8B - __ minv(v12, __ T16B, v13, v14); // smin v12.16B, v13.16B, v14.16B - __ minv(v11, __ T4H, v12, v13); // smin v11.4H, v12.4H, v13.4H - __ minv(v9, __ T8H, v10, v11); // smin v9.8H, v10.8H, v11.8H - __ minv(v6, __ T2S, v7, v8); // smin v6.2S, v7.2S, v8.2S - __ minv(v30, __ T4S, v31, v0); // smin v30.4S, v31.4S, v0.4S - __ uminv(v17, __ T8B, v18, v19); // umin v17.8B, v18.8B, v19.8B - __ uminv(v27, __ T16B, v28, v29); // umin v27.16B, v28.16B, v29.16B - __ uminv(v28, __ T4H, v29, v30); // umin v28.4H, v29.4H, v30.4H - __ uminv(v30, __ T8H, v31, v0); // umin v30.8H, v31.8H, v0.8H - __ uminv(v7, __ T2S, v8, v9); // umin v7.2S, v8.2S, v9.2S - __ uminv(v10, __ T4S, v11, v12); // umin v10.4S, v11.4S, v12.4S - __ sminp(v20, __ T8B, v21, v22); // sminp v20.8B, v21.8B, v22.8B - __ sminp(v10, __ T16B, v11, v12); // sminp v10.16B, v11.16B, v12.16B - __ sminp(v4, __ T4H, v5, v6); // sminp v4.4H, v5.4H, v6.4H - __ sminp(v24, __ T8H, v25, v26); // sminp v24.8H, v25.8H, v26.8H - __ sminp(v17, __ T2S, v18, v19); // sminp v17.2S, v18.2S, v19.2S - __ sminp(v17, __ T4S, v18, v19); // sminp v17.4S, v18.4S, v19.4S - __ uminp(v22, __ T8B, v23, v24); // uminp v22.8B, v23.8B, v24.8B - __ uminp(v3, __ T16B, v4, v5); // uminp v3.16B, v4.16B, v5.16B - __ uminp(v29, __ T4H, v30, v31); // uminp v29.4H, v30.4H, v31.4H - __ uminp(v15, __ T8H, v16, v17); // uminp v15.8H, v16.8H, v17.8H - __ uminp(v22, __ T2S, v23, v24); // uminp v22.2S, v23.2S, v24.2S - __ uminp(v19, __ T4S, v20, v21); // uminp v19.4S, v20.4S, v21.4S - __ umaxp(v19, __ T8B, v20, v21); // umaxp v19.8B, v20.8B, v21.8B - __ umaxp(v22, __ T16B, v23, v24); // umaxp v22.16B, v23.16B, v24.16B - __ umaxp(v2, __ T4H, v3, v4); // umaxp v2.4H, v3.4H, v4.4H - __ umaxp(v15, __ T8H, v16, v17); // umaxp v15.8H, v16.8H, v17.8H - __ umaxp(v6, __ T2S, v7, v8); // umaxp v6.2S, v7.2S, v8.2S - __ umaxp(v12, __ T4S, v13, v14); // umaxp v12.4S, v13.4S, v14.4S - __ sqdmulh(v16, __ T4H, v17, v18); // sqdmulh v16.4H, v17.4H, v18.4H - __ sqdmulh(v11, __ T8H, v12, v13); // sqdmulh v11.8H, v12.8H, v13.8H - __ sqdmulh(v13, __ T2S, v14, v15); // sqdmulh v13.2S, v14.2S, v15.2S - __ sqdmulh(v23, __ T4S, v24, v25); // sqdmulh v23.4S, v24.4S, v25.4S - __ shsubv(v1, __ T8B, v2, v3); // shsub v1.8B, v2.8B, v3.8B - __ shsubv(v30, __ T16B, v31, v0); // shsub v30.16B, v31.16B, v0.16B - __ shsubv(v19, __ T4H, v20, v21); // shsub v19.4H, v20.4H, v21.4H - __ shsubv(v5, __ T8H, v6, v7); // shsub v5.8H, v6.8H, v7.8H - __ shsubv(v17, __ T2S, v18, v19); // shsub v17.2S, v18.2S, v19.2S - __ shsubv(v2, __ T4S, v3, v4); // shsub v2.4S, v3.4S, v4.4S - __ fmin(v16, __ T2S, v17, v18); // fmin v16.2S, v17.2S, v18.2S - __ fmin(v22, __ T4S, v23, v24); // fmin v22.4S, v23.4S, v24.4S - __ fmin(v13, __ T2D, v14, v15); // fmin v13.2D, v14.2D, v15.2D - __ fmin(v10, __ T4H, v11, v12); // fmin v10.4H, v11.4H, v12.4H - __ fmin(v21, __ T8H, v22, v23); // fmin v21.8H, v22.8H, v23.8H - __ facgt(v29, __ T2S, v30, v31); // facgt v29.2S, v30.2S, v31.2S - __ facgt(v27, __ T4S, v28, v29); // facgt v27.4S, v28.4S, v29.4S - __ facgt(v12, __ T2D, v13, v14); // facgt v12.2D, v13.2D, v14.2D - __ facgt(v27, __ T4H, v28, v29); // facgt v27.4H, v28.4H, v29.4H - __ facgt(v3, __ T8H, v4, v5); // facgt v3.8H, v4.8H, v5.8H + __ maxv(v12, __ T4H, v13, v14); // smax v12.4H, v13.4H, v14.4H + __ maxv(v9, __ T8H, v10, v11); // smax v9.8H, v10.8H, v11.8H + __ maxv(v28, __ T2S, v29, v30); // smax v28.2S, v29.2S, v30.2S + __ maxv(v15, __ T4S, v16, v17); // smax v15.4S, v16.4S, v17.4S + __ umaxv(v29, __ T8B, v30, v31); // umax v29.8B, v30.8B, v31.8B + __ umaxv(v22, __ T16B, v23, v24); // umax v22.16B, v23.16B, v24.16B + __ umaxv(v31, __ T4H, v0, v1); // umax v31.4H, v0.4H, v1.4H + __ umaxv(v19, __ T8H, v20, v21); // umax v19.8H, v20.8H, v21.8H + __ umaxv(v31, __ T2S, v0, v1); // umax v31.2S, v0.2S, v1.2S + __ umaxv(v5, __ T4S, v6, v7); // umax v5.4S, v6.4S, v7.4S + __ smaxp(v14, __ T8B, v15, v16); // smaxp v14.8B, v15.8B, v16.8B + __ smaxp(v18, __ T16B, v19, v20); // smaxp v18.16B, v19.16B, v20.16B + __ smaxp(v31, __ T4H, v0, v1); // smaxp v31.4H, v0.4H, v1.4H + __ smaxp(v18, __ T8H, v19, v20); // smaxp v18.8H, v19.8H, v20.8H + __ smaxp(v27, __ T2S, v28, v29); // smaxp v27.2S, v28.2S, v29.2S + __ smaxp(v20, __ T4S, v21, v22); // smaxp v20.4S, v21.4S, v22.4S + __ fmax(v16, __ T2S, v17, v18); // fmax v16.2S, v17.2S, v18.2S + __ fmax(v12, __ T4S, v13, v14); // fmax v12.4S, v13.4S, v14.4S + __ fmax(v11, __ T2D, v12, v13); // fmax v11.2D, v12.2D, v13.2D + __ fmax(v9, __ T4H, v10, v11); // fmax v9.4H, v10.4H, v11.4H + __ fmax(v6, __ T8H, v7, v8); // fmax v6.8H, v7.8H, v8.8H + __ minv(v30, __ T8B, v31, v0); // smin v30.8B, v31.8B, v0.8B + __ minv(v17, __ T16B, v18, v19); // smin v17.16B, v18.16B, v19.16B + __ minv(v27, __ T4H, v28, v29); // smin v27.4H, v28.4H, v29.4H + __ minv(v28, __ T8H, v29, v30); // smin v28.8H, v29.8H, v30.8H + __ minv(v30, __ T2S, v31, v0); // smin v30.2S, v31.2S, v0.2S + __ minv(v7, __ T4S, v8, v9); // smin v7.4S, v8.4S, v9.4S + __ uminv(v10, __ T8B, v11, v12); // umin v10.8B, v11.8B, v12.8B + __ uminv(v20, __ T16B, v21, v22); // umin v20.16B, v21.16B, v22.16B + __ uminv(v10, __ T4H, v11, v12); // umin v10.4H, v11.4H, v12.4H + __ uminv(v4, __ T8H, v5, v6); // umin v4.8H, v5.8H, v6.8H + __ uminv(v24, __ T2S, v25, v26); // umin v24.2S, v25.2S, v26.2S + __ uminv(v17, __ T4S, v18, v19); // umin v17.4S, v18.4S, v19.4S + __ sminp(v17, __ T8B, v18, v19); // sminp v17.8B, v18.8B, v19.8B + __ sminp(v22, __ T16B, v23, v24); // sminp v22.16B, v23.16B, v24.16B + __ sminp(v3, __ T4H, v4, v5); // sminp v3.4H, v4.4H, v5.4H + __ sminp(v29, __ T8H, v30, v31); // sminp v29.8H, v30.8H, v31.8H + __ sminp(v15, __ T2S, v16, v17); // sminp v15.2S, v16.2S, v17.2S + __ sminp(v22, __ T4S, v23, v24); // sminp v22.4S, v23.4S, v24.4S + __ uminp(v19, __ T8B, v20, v21); // uminp v19.8B, v20.8B, v21.8B + __ uminp(v19, __ T16B, v20, v21); // uminp v19.16B, v20.16B, v21.16B + __ uminp(v22, __ T4H, v23, v24); // uminp v22.4H, v23.4H, v24.4H + __ uminp(v2, __ T8H, v3, v4); // uminp v2.8H, v3.8H, v4.8H + __ uminp(v15, __ T2S, v16, v17); // uminp v15.2S, v16.2S, v17.2S + __ uminp(v6, __ T4S, v7, v8); // uminp v6.4S, v7.4S, v8.4S + __ umaxp(v12, __ T8B, v13, v14); // umaxp v12.8B, v13.8B, v14.8B + __ umaxp(v16, __ T16B, v17, v18); // umaxp v16.16B, v17.16B, v18.16B + __ umaxp(v11, __ T4H, v12, v13); // umaxp v11.4H, v12.4H, v13.4H + __ umaxp(v13, __ T8H, v14, v15); // umaxp v13.8H, v14.8H, v15.8H + __ umaxp(v23, __ T2S, v24, v25); // umaxp v23.2S, v24.2S, v25.2S + __ umaxp(v1, __ T4S, v2, v3); // umaxp v1.4S, v2.4S, v3.4S + __ sqdmulh(v30, __ T4H, v31, v0); // sqdmulh v30.4H, v31.4H, v0.4H + __ sqdmulh(v19, __ T8H, v20, v21); // sqdmulh v19.8H, v20.8H, v21.8H + __ sqdmulh(v5, __ T2S, v6, v7); // sqdmulh v5.2S, v6.2S, v7.2S + __ sqdmulh(v17, __ T4S, v18, v19); // sqdmulh v17.4S, v18.4S, v19.4S + __ shsubv(v2, __ T8B, v3, v4); // shsub v2.8B, v3.8B, v4.8B + __ shsubv(v16, __ T16B, v17, v18); // shsub v16.16B, v17.16B, v18.16B + __ shsubv(v22, __ T4H, v23, v24); // shsub v22.4H, v23.4H, v24.4H + __ shsubv(v13, __ T8H, v14, v15); // shsub v13.8H, v14.8H, v15.8H + __ shsubv(v10, __ T2S, v11, v12); // shsub v10.2S, v11.2S, v12.2S + __ shsubv(v21, __ T4S, v22, v23); // shsub v21.4S, v22.4S, v23.4S + __ fmin(v29, __ T2S, v30, v31); // fmin v29.2S, v30.2S, v31.2S + __ fmin(v27, __ T4S, v28, v29); // fmin v27.4S, v28.4S, v29.4S + __ fmin(v12, __ T2D, v13, v14); // fmin v12.2D, v13.2D, v14.2D + __ fmin(v27, __ T4H, v28, v29); // fmin v27.4H, v28.4H, v29.4H + __ fmin(v3, __ T8H, v4, v5); // fmin v3.8H, v4.8H, v5.8H + __ facgt(v1, __ T2S, v2, v3); // facgt v1.2S, v2.2S, v3.2S + __ facgt(v31, __ T4S, v0, v1); // facgt v31.4S, v0.4S, v1.4S + __ facgt(v24, __ T2D, v25, v26); // facgt v24.2D, v25.2D, v26.2D + __ facgt(v19, __ T4H, v20, v21); // facgt v19.4H, v20.4H, v21.4H + __ facgt(v17, __ T8H, v18, v19); // facgt v17.8H, v18.8H, v19.8H // VectorScalarNEONInstruction - __ fmlavs(v15, __ T2S, v0, v1, 0); // fmla v15.2S, v0.2S, v1.S[0] - __ mulvs(v9, __ T4S, v10, v11, 3); // mul v9.4S, v10.4S, v11.S[3] - __ fmlavs(v4, __ T2D, v5, v6, 1); // fmla v4.2D, v5.2D, v6.D[1] - __ fmlsvs(v13, __ T2S, v14, v15, 1); // fmls v13.2S, v14.2S, v15.S[1] - __ mulvs(v3, __ T4S, v4, v5, 1); // mul v3.4S, v4.4S, v5.S[1] - __ fmlsvs(v11, __ T2D, v12, v13, 1); // fmls v11.2D, v12.2D, v13.D[1] - __ fmulxvs(v12, __ T2S, v13, v14, 1); // fmulx v12.2S, v13.2S, v14.S[1] - __ mulvs(v15, __ T4S, v0, v1, 0); // mul v15.4S, v0.4S, v1.S[0] - __ fmulxvs(v9, __ T2D, v10, v11, 1); // fmulx v9.2D, v10.2D, v11.D[1] - __ mulvs(v11, __ T4H, v12, v13, 1); // mul v11.4H, v12.4H, v13.H[1] - __ mulvs(v1, __ T8H, v2, v3, 4); // mul v1.8H, v2.8H, v3.H[4] - __ mulvs(v0, __ T2S, v1, v2, 1); // mul v0.2S, v1.2S, v2.S[1] - __ mulvs(v13, __ T4S, v14, v15, 3); // mul v13.4S, v14.4S, v15.S[3] + __ fmlavs(v14, __ T2S, v15, v16, 0); // fmla v14.2S, v15.2S, v16.S[0] + __ mulvs(v7, __ T4S, v8, v9, 3); // mul v7.4S, v8.4S, v9.S[3] + __ fmlavs(v10, __ T2D, v11, v12, 0); // fmla v10.2D, v11.2D, v12.D[0] + __ fmlsvs(v15, __ T2S, v0, v1, 1); // fmls v15.2S, v0.2S, v1.S[1] + __ mulvs(v1, __ T4S, v2, v3, 3); // mul v1.4S, v2.4S, v3.S[3] + __ fmlsvs(v13, __ T2D, v14, v15, 1); // fmls v13.2D, v14.2D, v15.D[1] + __ fmulxvs(v5, __ T2S, v6, v7, 1); // fmulx v5.2S, v6.2S, v7.S[1] + __ mulvs(v9, __ T4S, v10, v11, 2); // mul v9.4S, v10.4S, v11.S[2] + __ fmulxvs(v9, __ T2D, v10, v11, 0); // fmulx v9.2D, v10.2D, v11.D[0] + __ mulvs(v12, __ T4H, v13, v14, 0); // mul v12.4H, v13.4H, v14.H[0] + __ mulvs(v11, __ T8H, v12, v13, 6); // mul v11.8H, v12.8H, v13.H[6] + __ mulvs(v9, __ T2S, v10, v11, 0); // mul v9.2S, v10.2S, v11.S[0] + __ mulvs(v2, __ T4S, v3, v4, 1); // mul v2.4S, v3.4S, v4.S[1] // NEONVectorCompare - __ cm(Assembler::GT, v23, __ T8B, v24, v25); // cmgt v23.8B, v24.8B, v25.8B - __ cm(Assembler::GT, v2, __ T16B, v3, v4); // cmgt v2.16B, v3.16B, v4.16B - __ cm(Assembler::GT, v18, __ T4H, v19, v20); // cmgt v18.4H, v19.4H, v20.4H - __ cm(Assembler::GT, v12, __ T8H, v13, v14); // cmgt v12.8H, v13.8H, v14.8H - __ cm(Assembler::GT, v4, __ T2S, v5, v6); // cmgt v4.2S, v5.2S, v6.2S - __ cm(Assembler::GT, v28, __ T4S, v29, v30); // cmgt v28.4S, v29.4S, v30.4S - __ cm(Assembler::GT, v30, __ T2D, v31, v0); // cmgt v30.2D, v31.2D, v0.2D + __ cm(Assembler::GT, v28, __ T8B, v29, v30); // cmgt v28.8B, v29.8B, v30.8B + __ cm(Assembler::GT, v30, __ T16B, v31, v0); // cmgt v30.16B, v31.16B, v0.16B + __ cm(Assembler::GT, v29, __ T4H, v30, v31); // cmgt v29.4H, v30.4H, v31.4H + __ cm(Assembler::GT, v16, __ T8H, v17, v18); // cmgt v16.8H, v17.8H, v18.8H + __ cm(Assembler::GT, v27, __ T2S, v28, v29); // cmgt v27.2S, v28.2S, v29.2S + __ cm(Assembler::GT, v6, __ T4S, v7, v8); // cmgt v6.4S, v7.4S, v8.4S + __ cm(Assembler::GT, v9, __ T2D, v10, v11); // cmgt v9.2D, v10.2D, v11.2D __ cm(Assembler::GE, v29, __ T8B, v30, v31); // cmge v29.8B, v30.8B, v31.8B - __ cm(Assembler::GE, v16, __ T16B, v17, v18); // cmge v16.16B, v17.16B, v18.16B - __ cm(Assembler::GE, v27, __ T4H, v28, v29); // cmge v27.4H, v28.4H, v29.4H - __ cm(Assembler::GE, v6, __ T8H, v7, v8); // cmge v6.8H, v7.8H, v8.8H - __ cm(Assembler::GE, v9, __ T2S, v10, v11); // cmge v9.2S, v10.2S, v11.2S - __ cm(Assembler::GE, v29, __ T4S, v30, v31); // cmge v29.4S, v30.4S, v31.4S - __ cm(Assembler::GE, v18, __ T2D, v19, v20); // cmge v18.2D, v19.2D, v20.2D - __ cm(Assembler::EQ, v7, __ T8B, v8, v9); // cmeq v7.8B, v8.8B, v9.8B - __ cm(Assembler::EQ, v4, __ T16B, v5, v6); // cmeq v4.16B, v5.16B, v6.16B - __ cm(Assembler::EQ, v7, __ T4H, v8, v9); // cmeq v7.4H, v8.4H, v9.4H - __ cm(Assembler::EQ, v15, __ T8H, v16, v17); // cmeq v15.8H, v16.8H, v17.8H - __ cm(Assembler::EQ, v9, __ T2S, v10, v11); // cmeq v9.2S, v10.2S, v11.2S - __ cm(Assembler::EQ, v23, __ T4S, v24, v25); // cmeq v23.4S, v24.4S, v25.4S - __ cm(Assembler::EQ, v8, __ T2D, v9, v10); // cmeq v8.2D, v9.2D, v10.2D - __ cm(Assembler::HI, v2, __ T8B, v3, v4); // cmhi v2.8B, v3.8B, v4.8B - __ cm(Assembler::HI, v28, __ T16B, v29, v30); // cmhi v28.16B, v29.16B, v30.16B - __ cm(Assembler::HI, v21, __ T4H, v22, v23); // cmhi v21.4H, v22.4H, v23.4H - __ cm(Assembler::HI, v31, __ T8H, v0, v1); // cmhi v31.8H, v0.8H, v1.8H - __ cm(Assembler::HI, v5, __ T2S, v6, v7); // cmhi v5.2S, v6.2S, v7.2S - __ cm(Assembler::HI, v27, __ T4S, v28, v29); // cmhi v27.4S, v28.4S, v29.4S - __ cm(Assembler::HI, v0, __ T2D, v1, v2); // cmhi v0.2D, v1.2D, v2.2D - __ cm(Assembler::HS, v17, __ T8B, v18, v19); // cmhs v17.8B, v18.8B, v19.8B - __ cm(Assembler::HS, v15, __ T16B, v16, v17); // cmhs v15.16B, v16.16B, v17.16B - __ cm(Assembler::HS, v4, __ T4H, v5, v6); // cmhs v4.4H, v5.4H, v6.4H - __ cm(Assembler::HS, v26, __ T8H, v27, v28); // cmhs v26.8H, v27.8H, v28.8H - __ cm(Assembler::HS, v8, __ T2S, v9, v10); // cmhs v8.2S, v9.2S, v10.2S - __ cm(Assembler::HS, v28, __ T4S, v29, v30); // cmhs v28.4S, v29.4S, v30.4S - __ cm(Assembler::HS, v22, __ T2D, v23, v24); // cmhs v22.2D, v23.2D, v24.2D - __ fcm(Assembler::EQ, v27, __ T2S, v28, v29); // fcmeq v27.2S, v28.2S, v29.2S - __ fcm(Assembler::EQ, v27, __ T4S, v28, v29); // fcmeq v27.4S, v28.4S, v29.4S - __ fcm(Assembler::EQ, v25, __ T2D, v26, v27); // fcmeq v25.2D, v26.2D, v27.2D - __ fcm(Assembler::GT, v23, __ T2S, v24, v25); // fcmgt v23.2S, v24.2S, v25.2S - __ fcm(Assembler::GT, v0, __ T4S, v1, v2); // fcmgt v0.4S, v1.4S, v2.4S - __ fcm(Assembler::GT, v4, __ T2D, v5, v6); // fcmgt v4.2D, v5.2D, v6.2D - __ fcm(Assembler::GE, v6, __ T2S, v7, v8); // fcmge v6.2S, v7.2S, v8.2S - __ fcm(Assembler::GE, v18, __ T4S, v19, v20); // fcmge v18.4S, v19.4S, v20.4S - __ fcm(Assembler::GE, v0, __ T2D, v1, v2); // fcmge v0.2D, v1.2D, v2.2D + __ cm(Assembler::GE, v18, __ T16B, v19, v20); // cmge v18.16B, v19.16B, v20.16B + __ cm(Assembler::GE, v7, __ T4H, v8, v9); // cmge v7.4H, v8.4H, v9.4H + __ cm(Assembler::GE, v4, __ T8H, v5, v6); // cmge v4.8H, v5.8H, v6.8H + __ cm(Assembler::GE, v7, __ T2S, v8, v9); // cmge v7.2S, v8.2S, v9.2S + __ cm(Assembler::GE, v15, __ T4S, v16, v17); // cmge v15.4S, v16.4S, v17.4S + __ cm(Assembler::GE, v9, __ T2D, v10, v11); // cmge v9.2D, v10.2D, v11.2D + __ cm(Assembler::EQ, v23, __ T8B, v24, v25); // cmeq v23.8B, v24.8B, v25.8B + __ cm(Assembler::EQ, v8, __ T16B, v9, v10); // cmeq v8.16B, v9.16B, v10.16B + __ cm(Assembler::EQ, v2, __ T4H, v3, v4); // cmeq v2.4H, v3.4H, v4.4H + __ cm(Assembler::EQ, v28, __ T8H, v29, v30); // cmeq v28.8H, v29.8H, v30.8H + __ cm(Assembler::EQ, v21, __ T2S, v22, v23); // cmeq v21.2S, v22.2S, v23.2S + __ cm(Assembler::EQ, v31, __ T4S, v0, v1); // cmeq v31.4S, v0.4S, v1.4S + __ cm(Assembler::EQ, v5, __ T2D, v6, v7); // cmeq v5.2D, v6.2D, v7.2D + __ cm(Assembler::HI, v27, __ T8B, v28, v29); // cmhi v27.8B, v28.8B, v29.8B + __ cm(Assembler::HI, v0, __ T16B, v1, v2); // cmhi v0.16B, v1.16B, v2.16B + __ cm(Assembler::HI, v17, __ T4H, v18, v19); // cmhi v17.4H, v18.4H, v19.4H + __ cm(Assembler::HI, v15, __ T8H, v16, v17); // cmhi v15.8H, v16.8H, v17.8H + __ cm(Assembler::HI, v4, __ T2S, v5, v6); // cmhi v4.2S, v5.2S, v6.2S + __ cm(Assembler::HI, v26, __ T4S, v27, v28); // cmhi v26.4S, v27.4S, v28.4S + __ cm(Assembler::HI, v8, __ T2D, v9, v10); // cmhi v8.2D, v9.2D, v10.2D + __ cm(Assembler::HS, v28, __ T8B, v29, v30); // cmhs v28.8B, v29.8B, v30.8B + __ cm(Assembler::HS, v22, __ T16B, v23, v24); // cmhs v22.16B, v23.16B, v24.16B + __ cm(Assembler::HS, v27, __ T4H, v28, v29); // cmhs v27.4H, v28.4H, v29.4H + __ cm(Assembler::HS, v27, __ T8H, v28, v29); // cmhs v27.8H, v28.8H, v29.8H + __ cm(Assembler::HS, v25, __ T2S, v26, v27); // cmhs v25.2S, v26.2S, v27.2S + __ cm(Assembler::HS, v23, __ T4S, v24, v25); // cmhs v23.4S, v24.4S, v25.4S + __ cm(Assembler::HS, v0, __ T2D, v1, v2); // cmhs v0.2D, v1.2D, v2.2D + __ fcm(Assembler::EQ, v4, __ T2S, v5, v6); // fcmeq v4.2S, v5.2S, v6.2S + __ fcm(Assembler::EQ, v6, __ T4S, v7, v8); // fcmeq v6.4S, v7.4S, v8.4S + __ fcm(Assembler::EQ, v18, __ T2D, v19, v20); // fcmeq v18.2D, v19.2D, v20.2D + __ fcm(Assembler::GT, v0, __ T2S, v1, v2); // fcmgt v0.2S, v1.2S, v2.2S + __ fcm(Assembler::GT, v4, __ T4S, v5, v6); // fcmgt v4.4S, v5.4S, v6.4S + __ fcm(Assembler::GT, v15, __ T2D, v16, v17); // fcmgt v15.2D, v16.2D, v17.2D + __ fcm(Assembler::GE, v1, __ T2S, v2, v3); // fcmge v1.2S, v2.2S, v3.2S + __ fcm(Assembler::GE, v10, __ T4S, v11, v12); // fcmge v10.4S, v11.4S, v12.4S + __ fcm(Assembler::GE, v7, __ T2D, v8, v9); // fcmge v7.2D, v8.2D, v9.2D // SVEComparisonWithZero - __ sve_fcm(Assembler::EQ, p2, __ S, p2, z15, 0.0); // fcmeq p2.s, p2/z, z15.s, #0.0 - __ sve_fcm(Assembler::GT, p3, __ S, p7, z5, 0.0); // fcmgt p3.s, p7/z, z5.s, #0.0 - __ sve_fcm(Assembler::GE, p3, __ D, p5, z20, 0.0); // fcmge p3.d, p5/z, z20.d, #0.0 - __ sve_fcm(Assembler::LT, p3, __ S, p4, z11, 0.0); // fcmlt p3.s, p4/z, z11.s, #0.0 - __ sve_fcm(Assembler::LE, p15, __ D, p0, z6, 0.0); // fcmle p15.d, p0/z, z6.d, #0.0 - __ sve_fcm(Assembler::NE, p6, __ D, p0, z30, 0.0); // fcmne p6.d, p0/z, z30.d, #0.0 + __ sve_fcm(Assembler::EQ, p2, __ D, p1, z10, 0.0); // fcmeq p2.d, p1/z, z10.d, #0.0 + __ sve_fcm(Assembler::GT, p10, __ D, p1, z23, 0.0); // fcmgt p10.d, p1/z, z23.d, #0.0 + __ sve_fcm(Assembler::GE, p5, __ D, p7, z8, 0.0); // fcmge p5.d, p7/z, z8.d, #0.0 + __ sve_fcm(Assembler::LT, p3, __ S, p3, z17, 0.0); // fcmlt p3.s, p3/z, z17.s, #0.0 + __ sve_fcm(Assembler::LE, p15, __ S, p6, z29, 0.0); // fcmle p15.s, p6/z, z29.s, #0.0 + __ sve_fcm(Assembler::NE, p11, __ S, p3, z29, 0.0); // fcmne p11.s, p3/z, z29.s, #0.0 // SVEComparisonWithImm - __ sve_cmp(Assembler::EQ, p13, __ D, p3, z22, -3); // cmpeq p13.d, p3/z, z22.d, #-3 - __ sve_cmp(Assembler::GT, p14, __ D, p1, z17, -14); // cmpgt p14.d, p1/z, z17.d, #-14 - __ sve_cmp(Assembler::GE, p7, __ S, p2, z10, 11); // cmpge p7.s, p2/z, z10.s, #11 - __ sve_cmp(Assembler::LT, p11, __ B, p5, z12, 1); // cmplt p11.b, p5/z, z12.b, #1 - __ sve_cmp(Assembler::LE, p2, __ S, p4, z1, 2); // cmple p2.s, p4/z, z1.s, #2 - __ sve_cmp(Assembler::NE, p6, __ H, p0, z14, 1); // cmpne p6.h, p0/z, z14.h, #1 - __ sve_cmp(Assembler::HS, p1, __ S, p1, z21, 25); // cmphs p1.s, p1/z, z21.s, #25 - __ sve_cmp(Assembler::HI, p3, __ H, p7, z19, 70); // cmphi p3.h, p7/z, z19.h, #70 - __ sve_cmp(Assembler::LS, p8, __ B, p7, z6, 12); // cmpls p8.b, p7/z, z6.b, #12 - __ sve_cmp(Assembler::LO, p2, __ S, p5, z6, 55); // cmplo p2.s, p5/z, z6.s, #55 + __ sve_cmp(Assembler::EQ, p14, __ D, p1, z17, -14); // cmpeq p14.d, p1/z, z17.d, #-14 + __ sve_cmp(Assembler::GT, p7, __ S, p2, z10, 11); // cmpgt p7.s, p2/z, z10.s, #11 + __ sve_cmp(Assembler::GE, p11, __ B, p5, z12, 1); // cmpge p11.b, p5/z, z12.b, #1 + __ sve_cmp(Assembler::LT, p2, __ S, p4, z1, 2); // cmplt p2.s, p4/z, z1.s, #2 + __ sve_cmp(Assembler::LE, p6, __ H, p0, z14, 1); // cmple p6.h, p0/z, z14.h, #1 + __ sve_cmp(Assembler::NE, p1, __ S, p1, z21, -10); // cmpne p1.s, p1/z, z21.s, #-10 + __ sve_cmp(Assembler::HS, p3, __ H, p7, z19, 70); // cmphs p3.h, p7/z, z19.h, #70 + __ sve_cmp(Assembler::HI, p8, __ B, p7, z6, 12); // cmphi p8.b, p7/z, z6.b, #12 + __ sve_cmp(Assembler::LS, p2, __ S, p5, z6, 55); // cmpls p2.s, p5/z, z6.s, #55 + __ sve_cmp(Assembler::LO, p6, __ H, p6, z20, 81); // cmplo p6.h, p6/z, z20.h, #81 // SpecialCases __ ccmn(zr, zr, 3u, Assembler::LE); // ccmn xzr, xzr, #3, LE @@ -1220,244 +1221,244 @@ __ fmovd(v0, -1.0625); // fmov d0, #-1.0625 // LSEOp - __ swp(Assembler::xword, r12, r20, r8); // swp x12, x20, [x8] - __ ldadd(Assembler::xword, r25, r20, r19); // ldadd x25, x20, [x19] - __ ldbic(Assembler::xword, r0, r11, r24); // ldclr x0, x11, [x24] - __ ldeor(Assembler::xword, r6, r20, sp); // ldeor x6, x20, [sp] - __ ldorr(Assembler::xword, r14, r16, r6); // ldset x14, x16, [x6] - __ ldsmin(Assembler::xword, r0, r7, r15); // ldsmin x0, x7, [x15] - __ ldsmax(Assembler::xword, r19, r26, r9); // ldsmax x19, x26, [x9] - __ ldumin(Assembler::xword, r10, r23, r21); // ldumin x10, x23, [x21] - __ ldumax(Assembler::xword, r22, r28, r2); // ldumax x22, x28, [x2] + __ swp(Assembler::xword, r19, r0, r11); // swp x19, x0, [x11] + __ ldadd(Assembler::xword, r24, r6, r20); // ldadd x24, x6, [x20] + __ ldbic(Assembler::xword, zr, r14, r16); // ldclr xzr, x14, [x16] + __ ldeor(Assembler::xword, r6, r0, r7); // ldeor x6, x0, [x7] + __ ldorr(Assembler::xword, r15, r19, r26); // ldset x15, x19, [x26] + __ ldsmin(Assembler::xword, r9, r10, r23); // ldsmin x9, x10, [x23] + __ ldsmax(Assembler::xword, r21, r22, r28); // ldsmax x21, x22, [x28] + __ ldumin(Assembler::xword, r2, r3, r15); // ldumin x2, x3, [x15] + __ ldumax(Assembler::xword, r19, r20, r7); // ldumax x19, x20, [x7] // LSEOp - __ swpa(Assembler::xword, r3, r15, r19); // swpa x3, x15, [x19] - __ ldadda(Assembler::xword, r20, r7, r4); // ldadda x20, x7, [x4] - __ ldbica(Assembler::xword, r29, r7, r0); // ldclra x29, x7, [x0] - __ ldeora(Assembler::xword, r9, r16, r20); // ldeora x9, x16, [x20] - __ ldorra(Assembler::xword, r23, r4, r16); // ldseta x23, x4, [x16] - __ ldsmina(Assembler::xword, r10, r23, r11); // ldsmina x10, x23, [x11] - __ ldsmaxa(Assembler::xword, r25, r6, sp); // ldsmaxa x25, x6, [sp] - __ ldumina(Assembler::xword, r16, r13, r23); // ldumina x16, x13, [x23] - __ ldumaxa(Assembler::xword, r12, r1, r14); // ldumaxa x12, x1, [x14] + __ swpa(Assembler::xword, r4, r29, r7); // swpa x4, x29, [x7] + __ ldadda(Assembler::xword, r0, r9, r16); // ldadda x0, x9, [x16] + __ ldbica(Assembler::xword, r20, r23, r4); // ldclra x20, x23, [x4] + __ ldeora(Assembler::xword, r16, r10, r23); // ldeora x16, x10, [x23] + __ ldorra(Assembler::xword, r11, r25, r6); // ldseta x11, x25, [x6] + __ ldsmina(Assembler::xword, zr, r16, r13); // ldsmina xzr, x16, [x13] + __ ldsmaxa(Assembler::xword, r23, r12, r1); // ldsmaxa x23, x12, [x1] + __ ldumina(Assembler::xword, r14, r9, r21); // ldumina x14, x9, [x21] + __ ldumaxa(Assembler::xword, r16, r26, r15); // ldumaxa x16, x26, [x15] // LSEOp - __ swpal(Assembler::xword, r9, r21, r16); // swpal x9, x21, [x16] - __ ldaddal(Assembler::xword, r26, r15, r4); // ldaddal x26, x15, [x4] - __ ldbical(Assembler::xword, r4, r16, r8); // ldclral x4, x16, [x8] - __ ldeoral(Assembler::xword, r6, r30, r4); // ldeoral x6, x30, [x4] - __ ldorral(Assembler::xword, r29, r17, r29); // ldsetal x29, x17, [x29] - __ ldsminal(Assembler::xword, r26, r9, r15); // ldsminal x26, x9, [x15] - __ ldsmaxal(Assembler::xword, r2, r11, r29); // ldsmaxal x2, x11, [x29] - __ lduminal(Assembler::xword, r3, r7, r1); // lduminal x3, x7, [x1] - __ ldumaxal(Assembler::xword, r27, r21, r15); // ldumaxal x27, x21, [x15] + __ swpal(Assembler::xword, r4, r4, r15); // swpal x4, x4, [x15] + __ ldaddal(Assembler::xword, r8, r6, r30); // ldaddal x8, x6, [x30] + __ ldbical(Assembler::xword, r4, r29, r17); // ldclral x4, x29, [x17] + __ ldeoral(Assembler::xword, r29, r26, r9); // ldeoral x29, x26, [x9] + __ ldorral(Assembler::xword, r15, r2, r11); // ldsetal x15, x2, [x11] + __ ldsminal(Assembler::xword, r29, r3, r7); // ldsminal x29, x3, [x7] + __ ldsmaxal(Assembler::xword, r1, r27, r21); // ldsmaxal x1, x27, [x21] + __ lduminal(Assembler::xword, r16, r14, r8); // lduminal x16, x14, [x8] + __ ldumaxal(Assembler::xword, r16, r22, r25); // ldumaxal x16, x22, [x25] // LSEOp - __ swpl(Assembler::xword, r14, r8, r15); // swpl x14, x8, [x15] - __ ldaddl(Assembler::xword, r22, r25, r5); // ldaddl x22, x25, [x5] - __ ldbicl(Assembler::xword, r20, r21, r15); // ldclrl x20, x21, [x15] - __ ldeorl(Assembler::xword, r23, r16, r30); // ldeorl x23, x16, [x30] - __ ldorrl(Assembler::xword, r20, r20, r0); // ldsetl x20, x20, [x0] - __ ldsminl(Assembler::xword, r4, r19, r24); // ldsminl x4, x19, [x24] - __ ldsmaxl(Assembler::xword, r4, r20, r4); // ldsmaxl x4, x20, [x4] - __ lduminl(Assembler::xword, r24, r26, r19); // lduminl x24, x26, [x19] - __ ldumaxl(Assembler::xword, r2, r8, r8); // ldumaxl x2, x8, [x8] + __ swpl(Assembler::xword, r5, r20, r21); // swpl x5, x20, [x21] + __ ldaddl(Assembler::xword, r16, r23, r16); // ldaddl x16, x23, [x16] + __ ldbicl(Assembler::xword, r30, r20, r20); // ldclrl x30, x20, [x20] + __ ldeorl(Assembler::xword, r0, r4, r19); // ldeorl x0, x4, [x19] + __ ldorrl(Assembler::xword, r24, r4, r20); // ldsetl x24, x4, [x20] + __ ldsminl(Assembler::xword, r4, r24, r26); // ldsminl x4, x24, [x26] + __ ldsmaxl(Assembler::xword, r19, r2, r8); // ldsmaxl x19, x2, [x8] + __ lduminl(Assembler::xword, r8, r14, r24); // lduminl x8, x14, [x24] + __ ldumaxl(Assembler::xword, r16, zr, r22); // ldumaxl x16, xzr, [x22] // LSEOp - __ swp(Assembler::word, r14, r24, r15); // swp w14, w24, [x15] - __ ldadd(Assembler::word, zr, r22, r4); // ldadd wzr, w22, [x4] - __ ldbic(Assembler::word, zr, r1, r10); // ldclr wzr, w1, [x10] - __ ldeor(Assembler::word, r20, r12, r0); // ldeor w20, w12, [x0] - __ ldorr(Assembler::word, r9, r7, r24); // ldset w9, w7, [x24] - __ ldsmin(Assembler::word, r16, r4, r27); // ldsmin w16, w4, [x27] - __ ldsmax(Assembler::word, r6, r10, r27); // ldsmax w6, w10, [x27] - __ ldumin(Assembler::word, r24, r13, r16); // ldumin w24, w13, [x16] - __ ldumax(Assembler::word, zr, r22, r22); // ldumax wzr, w22, [x22] + __ swp(Assembler::word, r4, zr, r1); // swp w4, wzr, [x1] + __ ldadd(Assembler::word, r10, r20, r12); // ldadd w10, w20, [x12] + __ ldbic(Assembler::word, r0, r9, r7); // ldclr w0, w9, [x7] + __ ldeor(Assembler::word, r24, r16, r4); // ldeor w24, w16, [x4] + __ ldorr(Assembler::word, r27, r6, r10); // ldset w27, w6, [x10] + __ ldsmin(Assembler::word, r27, r24, r13); // ldsmin w27, w24, [x13] + __ ldsmax(Assembler::word, r16, zr, r22); // ldsmax w16, wzr, [x22] + __ ldumin(Assembler::word, r22, r20, sp); // ldumin w22, w20, [sp] + __ ldumax(Assembler::word, r29, r9, r14); // ldumax w29, w9, [x14] // LSEOp - __ swpa(Assembler::word, r20, zr, r29); // swpa w20, wzr, [x29] - __ ldadda(Assembler::word, r9, r14, r20); // ldadda w9, w14, [x20] - __ ldbica(Assembler::word, r7, r20, r28); // ldclra w7, w20, [x28] - __ ldeora(Assembler::word, r9, r11, r14); // ldeora w9, w11, [x14] - __ ldorra(Assembler::word, r12, r20, r1); // ldseta w12, w20, [x1] - __ ldsmina(Assembler::word, r24, r9, r19); // ldsmina w24, w9, [x19] - __ ldsmaxa(Assembler::word, r13, r19, r15); // ldsmaxa w13, w19, [x15] - __ ldumina(Assembler::word, r16, r5, r0); // ldumina w16, w5, [x0] - __ ldumaxa(Assembler::word, r3, r12, r8); // ldumaxa w3, w12, [x8] + __ swpa(Assembler::word, r20, r7, r20); // swpa w20, w7, [x20] + __ ldadda(Assembler::word, r28, r9, r11); // ldadda w28, w9, [x11] + __ ldbica(Assembler::word, r14, r12, r20); // ldclra w14, w12, [x20] + __ ldeora(Assembler::word, r1, r24, r9); // ldeora w1, w24, [x9] + __ ldorra(Assembler::word, r19, r13, r19); // ldseta w19, w13, [x19] + __ ldsmina(Assembler::word, r16, r16, r5); // ldsmina w16, w16, [x5] + __ ldsmaxa(Assembler::word, r0, r3, r12); // ldsmaxa w0, w3, [x12] + __ ldumina(Assembler::word, r8, r15, r15); // ldumina w8, w15, [x15] + __ ldumaxa(Assembler::word, r16, r4, r15); // ldumaxa w16, w4, [x15] // LSEOp - __ swpal(Assembler::word, r15, r15, r16); // swpal w15, w15, [x16] - __ ldaddal(Assembler::word, r4, r15, r30); // ldaddal w4, w15, [x30] - __ ldbical(Assembler::word, r5, r0, r10); // ldclral w5, w0, [x10] - __ ldeoral(Assembler::word, r22, r27, r3); // ldeoral w22, w27, [x3] - __ ldorral(Assembler::word, r0, r9, r19); // ldsetal w0, w9, [x19] - __ ldsminal(Assembler::word, r29, r10, r24); // ldsminal w29, w10, [x24] - __ ldsmaxal(Assembler::word, r4, r20, r7); // ldsmaxal w4, w20, [x7] - __ lduminal(Assembler::word, r24, r29, r14); // lduminal w24, w29, [x14] - __ ldumaxal(Assembler::word, r21, r11, r27); // ldumaxal w21, w11, [x27] + __ swpal(Assembler::word, r30, r5, r0); // swpal w30, w5, [x0] + __ ldaddal(Assembler::word, r10, r22, r27); // ldaddal w10, w22, [x27] + __ ldbical(Assembler::word, r3, r0, r9); // ldclral w3, w0, [x9] + __ ldeoral(Assembler::word, r19, r29, r10); // ldeoral w19, w29, [x10] + __ ldorral(Assembler::word, r24, r4, r20); // ldsetal w24, w4, [x20] + __ ldsminal(Assembler::word, r7, r24, r29); // ldsminal w7, w24, [x29] + __ ldsmaxal(Assembler::word, r14, r21, r11); // ldsmaxal w14, w21, [x11] + __ lduminal(Assembler::word, r27, r13, r15); // lduminal w27, w13, [x15] + __ ldumaxal(Assembler::word, zr, r17, r14); // ldumaxal wzr, w17, [x14] // LSEOp - __ swpl(Assembler::word, r13, r16, sp); // swpl w13, w16, [sp] - __ ldaddl(Assembler::word, r17, r14, r3); // ldaddl w17, w14, [x3] - __ ldbicl(Assembler::word, r30, r16, r22); // ldclrl w30, w16, [x22] - __ ldeorl(Assembler::word, r20, r7, r20); // ldeorl w20, w7, [x20] - __ ldorrl(Assembler::word, r3, r1, r26); // ldsetl w3, w1, [x26] - __ ldsminl(Assembler::word, r19, r9, r16); // ldsminl w19, w9, [x16] - __ ldsmaxl(Assembler::word, r17, r21, r0); // ldsmaxl w17, w21, [x0] - __ lduminl(Assembler::word, r4, r2, r24); // lduminl w4, w2, [x24] - __ ldumaxl(Assembler::word, r14, r6, r11); // ldumaxl w14, w6, [x11] + __ swpl(Assembler::word, r3, r30, r16); // swpl w3, w30, [x16] + __ ldaddl(Assembler::word, r22, r20, r7); // ldaddl w22, w20, [x7] + __ ldbicl(Assembler::word, r20, r3, r1); // ldclrl w20, w3, [x1] + __ ldeorl(Assembler::word, r26, r19, r9); // ldeorl w26, w19, [x9] + __ ldorrl(Assembler::word, r16, r17, r21); // ldsetl w16, w17, [x21] + __ ldsminl(Assembler::word, r0, r4, r2); // ldsminl w0, w4, [x2] + __ ldsmaxl(Assembler::word, r24, r14, r6); // ldsmaxl w24, w14, [x6] + __ lduminl(Assembler::word, r11, r21, r14); // lduminl w11, w21, [x14] + __ ldumaxl(Assembler::word, r17, r30, r12); // ldumaxl w17, w30, [x12] // SHA3SIMDOp - __ bcax(v21, __ T16B, v14, v17, v30); // bcax v21.16B, v14.16B, v17.16B, v30.16B - __ eor3(v12, __ T16B, v3, v3, v23); // eor3 v12.16B, v3.16B, v3.16B, v23.16B - __ rax1(v9, __ T2D, v3, v24); // rax1 v9.2D, v3.2D, v24.2D - __ xar(v28, __ T2D, v3, v19, 47); // xar v28.2D, v3.2D, v19.2D, #47 + __ bcax(v3, __ T16B, v3, v23, v9); // bcax v3.16B, v3.16B, v23.16B, v9.16B + __ eor3(v3, __ T16B, v24, v28, v3); // eor3 v3.16B, v24.16B, v28.16B, v3.16B + __ rax1(v19, __ T2D, v23, v7); // rax1 v19.2D, v23.2D, v7.2D + __ xar(v26, __ T2D, v21, v14, 10); // xar v26.2D, v21.2D, v14.2D, #10 // SHA512SIMDOp - __ sha512h(v7, __ T2D, v26, v21); // sha512h q7, q26, v21.2D - __ sha512h2(v14, __ T2D, v5, v8); // sha512h2 q14, q5, v8.2D - __ sha512su0(v26, __ T2D, v5); // sha512su0 v26.2D, v5.2D - __ sha512su1(v22, __ T2D, v18, v17); // sha512su1 v22.2D, v18.2D, v17.2D + __ sha512h(v8, __ T2D, v26, v5); // sha512h q8, q26, v5.2D + __ sha512h2(v22, __ T2D, v18, v17); // sha512h2 q22, q18, v17.2D + __ sha512su0(v0, __ T2D, v3); // sha512su0 v0.2D, v3.2D + __ sha512su1(v9, __ T2D, v20, v12); // sha512su1 v9.2D, v20.2D, v12.2D // SVEBinaryImmOp - __ sve_add(z0, __ B, 79u); // add z0.b, z0.b, #0x4f - __ sve_sub(z20, __ H, 65u); // sub z20.h, z20.h, #0x41 - __ sve_and(z12, __ H, 33279u); // and z12.h, z12.h, #0x81ff - __ sve_eor(z11, __ H, 49663u); // eor z11.h, z11.h, #0xc1ff - __ sve_orr(z31, __ S, 2147484159u); // orr z31.s, z31.s, #0x800001ff + __ sve_add(z8, __ H, 118u); // add z8.h, z8.h, #0x76 + __ sve_sub(z19, __ S, 94u); // sub z19.s, z19.s, #0x5e + __ sve_and(z13, __ D, 18446744073709289487u); // and z13.d, z13.d, #0xfffffffffffc000f + __ sve_eor(z19, __ H, 32256u); // eor z19.h, z19.h, #0x7e00 + __ sve_orr(z27, __ S, 4261413375u); // orr z27.s, z27.s, #0xfe0001ff // SVEBinaryImmOp - __ sve_add(z15, __ D, 188u); // add z15.d, z15.d, #0xbc - __ sve_sub(z28, __ S, 64u); // sub z28.s, z28.s, #0x40 - __ sve_and(z8, __ B, 243u); // and z8.b, z8.b, #0xf3 - __ sve_eor(z10, __ B, 239u); // eor z10.b, z10.b, #0xef - __ sve_orr(z22, __ S, 32768u); // orr z22.s, z22.s, #0x8000 + __ sve_add(z8, __ H, 41u); // add z8.h, z8.h, #0x29 + __ sve_sub(z28, __ D, 82u); // sub z28.d, z28.d, #0x52 + __ sve_and(z0, __ H, 57343u); // and z0.h, z0.h, #0xdfff + __ sve_eor(z21, __ B, 191u); // eor z21.b, z21.b, #0xbf + __ sve_orr(z26, __ B, 254u); // orr z26.b, z26.b, #0xfe // SVEBinaryImmOp - __ sve_add(z23, __ D, 46u); // add z23.d, z23.d, #0x2e - __ sve_sub(z26, __ D, 154u); // sub z26.d, z26.d, #0x9a - __ sve_and(z17, __ B, 128u); // and z17.b, z17.b, #0x80 - __ sve_eor(z30, __ H, 49663u); // eor z30.h, z30.h, #0xc1ff - __ sve_orr(z2, __ D, 18444492273897963519u); // orr z2.d, z2.d, #0xfff80000001fffff + __ sve_add(z19, __ S, 8u); // add z19.s, z19.s, #0x8 + __ sve_sub(z13, __ H, 244u); // sub z13.h, z13.h, #0xf4 + __ sve_and(z14, __ B, 1u); // and z14.b, z14.b, #0x1 + __ sve_eor(z31, __ S, 4227858559u); // eor z31.s, z31.s, #0xfc00007f + __ sve_orr(z30, __ H, 56u); // orr z30.h, z30.h, #0x38 // SVEBinaryImmOp - __ sve_add(z22, __ D, 103u); // add z22.d, z22.d, #0x67 - __ sve_sub(z8, __ B, 5u); // sub z8.b, z8.b, #0x5 - __ sve_and(z15, __ S, 1u); // and z15.s, z15.s, #0x1 - __ sve_eor(z19, __ D, 18446532967477018623u); // eor z19.d, z19.d, #0xffff3fffffffffff - __ sve_orr(z13, __ S, 7168u); // orr z13.s, z13.s, #0x1c00 + __ sve_add(z0, __ H, 190u); // add z0.h, z0.h, #0xbe + __ sve_sub(z23, __ B, 157u); // sub z23.b, z23.b, #0x9d + __ sve_and(z26, __ D, 576456354256912384u); // and z26.d, z26.d, #0x7fffc0000000000 + __ sve_eor(z22, __ S, 496u); // eor z22.s, z22.s, #0x1f0 + __ sve_orr(z11, __ S, 4042322160u); // orr z11.s, z11.s, #0xf0f0f0f0 // SVEBinaryImmOp - __ sve_add(z1, __ H, 164u); // add z1.h, z1.h, #0xa4 - __ sve_sub(z12, __ S, 194u); // sub z12.s, z12.s, #0xc2 - __ sve_and(z24, __ H, 33279u); // and z24.h, z24.h, #0x81ff - __ sve_eor(z20, __ S, 917504u); // eor z20.s, z20.s, #0xe0000 - __ sve_orr(z21, __ H, 57343u); // orr z21.h, z21.h, #0xdfff + __ sve_add(z24, __ D, 72u); // add z24.d, z24.d, #0x48 + __ sve_sub(z31, __ S, 160u); // sub z31.s, z31.s, #0xa0 + __ sve_and(z20, __ S, 4164941887u); // and z20.s, z20.s, #0xf83ff83f + __ sve_eor(z13, __ D, 18446744073709289487u); // eor z13.d, z13.d, #0xfffffffffffc000f + __ sve_orr(z31, __ D, 17870287719452639231u); // orr z31.d, z31.d, #0xf80003ffffffffff // SVEBinaryImmOp - __ sve_add(z31, __ D, 213u); // add z31.d, z31.d, #0xd5 - __ sve_sub(z18, __ S, 120u); // sub z18.s, z18.s, #0x78 - __ sve_and(z11, __ H, 51199u); // and z11.h, z11.h, #0xc7ff - __ sve_eor(z5, __ B, 128u); // eor z5.b, z5.b, #0x80 - __ sve_orr(z2, __ B, 124u); // orr z2.b, z2.b, #0x7c + __ sve_add(z15, __ H, 107u); // add z15.h, z15.h, #0x6b + __ sve_sub(z29, __ S, 43u); // sub z29.s, z29.s, #0x2b + __ sve_and(z1, __ H, 56u); // and z1.h, z1.h, #0x38 + __ sve_eor(z7, __ H, 49155u); // eor z7.h, z7.h, #0xc003 + __ sve_orr(z4, __ D, 66977792u); // orr z4.d, z4.d, #0x3fe0000 // SVEVectorOp - __ sve_add(z19, __ H, z4, z26); // add z19.h, z4.h, z26.h - __ sve_sub(z2, __ B, z3, z30); // sub z2.b, z3.b, z30.b - __ sve_fadd(z20, __ D, z5, z20); // fadd z20.d, z5.d, z20.d - __ sve_fmul(z29, __ S, z13, z13); // fmul z29.s, z13.s, z13.s - __ sve_fsub(z14, __ S, z30, z1); // fsub z14.s, z30.s, z1.s - __ sve_sqadd(z28, __ D, z3, z3); // sqadd z28.d, z3.d, z3.d - __ sve_sqsub(z9, __ B, z25, z9); // sqsub z9.b, z25.b, z9.b - __ sve_uqadd(z26, __ B, z10, z14); // uqadd z26.b, z10.b, z14.b - __ sve_uqsub(z20, __ D, z26, z7); // uqsub z20.d, z26.d, z7.d - __ sve_abs(z20, __ D, p4, z6); // abs z20.d, p4/m, z6.d - __ sve_add(z13, __ H, p0, z29); // add z13.h, p0/m, z13.h, z29.h - __ sve_and(z9, __ B, p0, z1); // and z9.b, p0/m, z9.b, z1.b - __ sve_asr(z27, __ B, p6, z15); // asr z27.b, p6/m, z27.b, z15.b - __ sve_bic(z4, __ D, p7, z17); // bic z4.d, p7/m, z4.d, z17.d - __ sve_clz(z2, __ B, p0, z24); // clz z2.b, p0/m, z24.b - __ sve_cnt(z26, __ B, p7, z13); // cnt z26.b, p7/m, z13.b - __ sve_eor(z22, __ D, p3, z16); // eor z22.d, p3/m, z22.d, z16.d - __ sve_lsl(z17, __ D, p1, z11); // lsl z17.d, p1/m, z17.d, z11.d - __ sve_lsr(z16, __ B, p0, z16); // lsr z16.b, p0/m, z16.b, z16.b - __ sve_mul(z28, __ D, p1, z23); // mul z28.d, p1/m, z28.d, z23.d - __ sve_sdiv(z28, __ D, p4, z10); // sdiv z28.d, p4/m, z28.d, z10.d - __ sve_udiv(z17, __ D, p7, z7); // udiv z17.d, p7/m, z17.d, z7.d - __ sve_neg(z4, __ H, p3, z24); // neg z4.h, p3/m, z24.h - __ sve_not(z9, __ B, p2, z11); // not z9.b, p2/m, z11.b - __ sve_orr(z4, __ S, p5, z22); // orr z4.s, p5/m, z4.s, z22.s - __ sve_rbit(z4, __ H, p0, z15); // rbit z4.h, p0/m, z15.h - __ sve_revb(z4, __ D, p7, z26); // revb z4.d, p7/m, z26.d - __ sve_smax(z5, __ H, p5, z26); // smax z5.h, p5/m, z5.h, z26.h - __ sve_smin(z31, __ B, p0, z25); // smin z31.b, p0/m, z31.b, z25.b - __ sve_umax(z8, __ S, p1, z3); // umax z8.s, p1/m, z8.s, z3.s - __ sve_umin(z7, __ D, p6, z24); // umin z7.d, p6/m, z7.d, z24.d - __ sve_sub(z24, __ B, p7, z17); // sub z24.b, p7/m, z24.b, z17.b - __ sve_fabs(z10, __ S, p3, z30); // fabs z10.s, p3/m, z30.s - __ sve_fadd(z8, __ S, p6, z29); // fadd z8.s, p6/m, z8.s, z29.s - __ sve_fdiv(z31, __ D, p5, z31); // fdiv z31.d, p5/m, z31.d, z31.d - __ sve_fmax(z0, __ D, p5, z7); // fmax z0.d, p5/m, z0.d, z7.d - __ sve_fmin(z29, __ S, p6, z22); // fmin z29.s, p6/m, z29.s, z22.s - __ sve_fmul(z29, __ S, p6, z20); // fmul z29.s, p6/m, z29.s, z20.s - __ sve_fneg(z6, __ S, p4, z18); // fneg z6.s, p4/m, z18.s - __ sve_frintm(z26, __ S, p5, z8); // frintm z26.s, p5/m, z8.s - __ sve_frintn(z19, __ S, p2, z28); // frintn z19.s, p2/m, z28.s - __ sve_frintp(z17, __ D, p1, z30); // frintp z17.d, p1/m, z30.d - __ sve_fsqrt(z24, __ D, p7, z14); // fsqrt z24.d, p7/m, z14.d - __ sve_fsub(z14, __ D, p4, z10); // fsub z14.d, p4/m, z14.d, z10.d - __ sve_fmad(z11, __ S, p6, z0, z11); // fmad z11.s, p6/m, z0.s, z11.s - __ sve_fmla(z28, __ D, p5, z23, z20); // fmla z28.d, p5/m, z23.d, z20.d - __ sve_fmls(z23, __ S, p5, z29, z24); // fmls z23.s, p5/m, z29.s, z24.s - __ sve_fmsb(z27, __ S, p1, z23, z13); // fmsb z27.s, p1/m, z23.s, z13.s - __ sve_fnmad(z4, __ D, p3, z31, z26); // fnmad z4.d, p3/m, z31.d, z26.d - __ sve_fnmsb(z20, __ D, p1, z2, z29); // fnmsb z20.d, p1/m, z2.d, z29.d - __ sve_fnmla(z0, __ S, p7, z23, z3); // fnmla z0.s, p7/m, z23.s, z3.s - __ sve_fnmls(z5, __ D, p2, z28, z13); // fnmls z5.d, p2/m, z28.d, z13.d - __ sve_mla(z13, __ H, p3, z8, z10); // mla z13.h, p3/m, z8.h, z10.h - __ sve_mls(z9, __ S, p4, z0, z29); // mls z9.s, p4/m, z0.s, z29.s - __ sve_and(z16, z13, z23); // and z16.d, z13.d, z23.d - __ sve_eor(z23, z30, z13); // eor z23.d, z30.d, z13.d - __ sve_orr(z25, z22, z0); // orr z25.d, z22.d, z0.d - __ sve_bic(z25, z30, z11); // bic z25.d, z30.d, z11.d - __ sve_uzp1(z14, __ H, z23, z22); // uzp1 z14.h, z23.h, z22.h - __ sve_uzp2(z5, __ H, z18, z0); // uzp2 z5.h, z18.h, z0.h - __ sve_fabd(z9, __ D, p0, z3); // fabd z9.d, p0/m, z9.d, z3.d - __ sve_bext(z14, __ H, z4, z29); // bext z14.h, z4.h, z29.h - __ sve_bdep(z14, __ D, z22, z4); // bdep z14.d, z22.d, z4.d - __ sve_bsl(z27, z15, z22); // bsl z27.d, z27.d, z15.d, z22.d - __ sve_eor3(z31, z24, z11); // eor3 z31.d, z31.d, z24.d, z11.d - __ sve_sqadd(z12, __ B, p4, z28); // sqadd z12.b, p4/m, z12.b, z28.b - __ sve_sqsub(z28, __ D, p4, z4); // sqsub z28.d, p4/m, z28.d, z4.d - __ sve_uqadd(z6, __ S, p0, z15); // uqadd z6.s, p0/m, z6.s, z15.s - __ sve_uqsub(z1, __ S, p5, z18); // uqsub z1.s, p5/m, z1.s, z18.s + __ sve_add(z3, __ S, z30, z1); // add z3.s, z30.s, z1.s + __ sve_sub(z5, __ D, z20, z31); // sub z5.d, z20.d, z31.d + __ sve_fadd(z13, __ S, z13, z9); // fadd z13.s, z13.s, z9.s + __ sve_fmul(z30, __ D, z1, z15); // fmul z30.d, z1.d, z15.d + __ sve_fsub(z3, __ S, z3, z26); // fsub z3.s, z3.s, z26.s + __ sve_sqadd(z25, __ D, z9, z1); // sqadd z25.d, z9.d, z1.d + __ sve_sqsub(z10, __ S, z14, z1); // sqsub z10.s, z14.s, z1.s + __ sve_uqadd(z26, __ S, z7, z29); // uqadd z26.s, z7.s, z29.s + __ sve_uqsub(z17, __ H, z6, z28); // uqsub z17.h, z6.h, z28.h + __ sve_abs(z1, __ H, p7, z11); // abs z1.h, p7/m, z11.h + __ sve_add(z1, __ D, p0, z1); // add z1.d, p0/m, z1.d, z1.d + __ sve_and(z27, __ B, p3, z2); // and z27.b, p3/m, z27.b, z2.b + __ sve_asr(z30, __ B, p4, z25); // asr z30.b, p4/m, z30.b, z25.b + __ sve_bic(z2, __ D, p6, z3); // bic z2.d, p6/m, z2.d, z3.d + __ sve_clz(z29, __ S, p3, z3); // clz z29.s, p3/m, z3.s + __ sve_cnt(z14, __ S, p4, z28); // cnt z14.s, p4/m, z28.s + __ sve_eor(z4, __ S, p2, z27); // eor z4.s, p2/m, z4.s, z27.s + __ sve_lsl(z2, __ D, p4, z1); // lsl z2.d, p4/m, z2.d, z1.d + __ sve_lsr(z7, __ D, p5, z31); // lsr z7.d, p5/m, z7.d, z31.d + __ sve_mul(z16, __ S, p2, z22); // mul z16.s, p2/m, z16.s, z22.s + __ sve_sdiv(z29, __ S, p1, z22); // sdiv z29.s, p1/m, z29.s, z22.s + __ sve_udiv(z12, __ S, p6, z11); // udiv z12.s, p6/m, z12.s, z11.s + __ sve_neg(z11, __ B, p2, z0); // neg z11.b, p2/m, z0.b + __ sve_not(z23, __ B, p5, z20); // not z23.b, p5/m, z20.b + __ sve_orr(z3, __ B, p3, z15); // orr z3.b, p3/m, z3.b, z15.b + __ sve_rbit(z30, __ B, p6, z27); // rbit z30.b, p6/m, z27.b + __ sve_revb(z21, __ D, p6, z10); // revb z21.d, p6/m, z10.d + __ sve_smax(z3, __ H, p6, z4); // smax z3.h, p6/m, z3.h, z4.h + __ sve_smin(z6, __ B, p0, z21); // smin z6.b, p0/m, z6.b, z21.b + __ sve_umax(z25, __ D, p6, z30); // umax z25.d, p6/m, z25.d, z30.d + __ sve_umin(z31, __ H, p4, z1); // umin z31.h, p4/m, z31.h, z1.h + __ sve_sub(z12, __ H, p7, z13); // sub z12.h, p7/m, z12.h, z13.h + __ sve_fabs(z25, __ D, p7, z1); // fabs z25.d, p7/m, z1.d + __ sve_fadd(z23, __ S, p7, z20); // fadd z23.s, p7/m, z23.s, z20.s + __ sve_fdiv(z21, __ D, p1, z31); // fdiv z21.d, p1/m, z21.d, z31.d + __ sve_fmax(z27, __ D, p5, z8); // fmax z27.d, p5/m, z27.d, z8.d + __ sve_fmin(z26, __ S, p5, z5); // fmin z26.s, p5/m, z26.s, z5.s + __ sve_fmul(z18, __ D, p4, z13); // fmul z18.d, p4/m, z18.d, z13.d + __ sve_fneg(z21, __ D, p2, z0); // fneg z21.d, p2/m, z0.d + __ sve_frintm(z10, __ D, p7, z7); // frintm z10.d, p7/m, z7.d + __ sve_frintn(z6, __ D, p7, z20); // frintn z6.d, p7/m, z20.d + __ sve_frintp(z28, __ S, p3, z17); // frintp z28.s, p3/m, z17.s + __ sve_fsqrt(z19, __ S, p2, z26); // fsqrt z19.s, p2/m, z26.s + __ sve_fsub(z24, __ S, p0, z11); // fsub z24.s, p0/m, z24.s, z11.s + __ sve_fmad(z28, __ D, p5, z23, z20); // fmad z28.d, p5/m, z23.d, z20.d + __ sve_fmla(z23, __ S, p5, z29, z24); // fmla z23.s, p5/m, z29.s, z24.s + __ sve_fmls(z27, __ S, p1, z23, z13); // fmls z27.s, p1/m, z23.s, z13.s + __ sve_fmsb(z4, __ D, p3, z31, z26); // fmsb z4.d, p3/m, z31.d, z26.d + __ sve_fnmad(z20, __ D, p1, z2, z29); // fnmad z20.d, p1/m, z2.d, z29.d + __ sve_fnmsb(z0, __ S, p7, z23, z3); // fnmsb z0.s, p7/m, z23.s, z3.s + __ sve_fnmla(z5, __ D, p2, z28, z13); // fnmla z5.d, p2/m, z28.d, z13.d + __ sve_fnmls(z13, __ S, p3, z8, z10); // fnmls z13.s, p3/m, z8.s, z10.s + __ sve_mla(z9, __ S, p4, z0, z29); // mla z9.s, p4/m, z0.s, z29.s + __ sve_mls(z16, __ S, p3, z23, z24); // mls z16.s, p3/m, z23.s, z24.s + __ sve_and(z30, z13, z2); // and z30.d, z13.d, z2.d + __ sve_eor(z22, z0, z15); // eor z22.d, z0.d, z15.d + __ sve_orr(z30, z11, z15); // orr z30.d, z11.d, z15.d + __ sve_bic(z23, z22, z15); // bic z23.d, z22.d, z15.d + __ sve_uzp1(z18, __ H, z0, z11); // uzp1 z18.h, z0.h, z11.h + __ sve_uzp2(z2, __ H, z3, z25); // uzp2 z2.h, z3.h, z25.h + __ sve_fabd(z4, __ S, p7, z10); // fabd z4.s, p7/m, z4.s, z10.s + __ sve_bext(z22, __ D, z4, z25); // bext z22.d, z4.d, z25.d + __ sve_bdep(z15, __ D, z22, z23); // bdep z15.d, z22.d, z23.d + __ sve_bsl(z24, z11, z16); // bsl z24.d, z24.d, z11.d, z16.d + __ sve_eor3(z17, z28, z3); // eor3 z17.d, z17.d, z28.d, z3.d + __ sve_sqadd(z16, __ B, p1, z29); // sqadd z16.b, p1/m, z16.b, z29.b + __ sve_sqsub(z0, __ B, p3, z18); // sqsub z0.b, p3/m, z0.b, z18.b + __ sve_uqadd(z20, __ B, p4, z18); // uqadd z20.b, p4/m, z20.b, z18.b + __ sve_uqsub(z11, __ H, p1, z14); // uqsub z11.h, p1/m, z11.h, z14.h // SVEReductionOp - __ sve_andv(v2, __ H, p2, z4); // andv h2, p2, z4.h - __ sve_orv(v11, __ S, p2, z28); // orv s11, p2, z28.s - __ sve_eorv(v3, __ H, p5, z31); // eorv h3, p5, z31.h - __ sve_smaxv(v24, __ H, p5, z15); // smaxv h24, p5, z15.h - __ sve_sminv(v6, __ H, p3, z8); // sminv h6, p3, z8.h - __ sve_umaxv(v21, __ D, p7, z4); // umaxv d21, p7, z4.d - __ sve_uminv(v24, __ B, p5, z6); // uminv b24, p5, z6.b - __ sve_fminv(v4, __ D, p2, z9); // fminv d4, p2, z9.d - __ sve_fmaxv(v10, __ D, p1, z31); // fmaxv d10, p1, z31.d - __ sve_fadda(v25, __ D, p3, z3); // fadda d25, p3, d25, z3.d - __ sve_uaddv(v14, __ H, p2, z2); // uaddv d14, p2, z2.h + __ sve_andv(v10, __ B, p7, z19); // andv b10, p7, z19.b + __ sve_orv(v21, __ D, p7, z11); // orv d21, p7, z11.d + __ sve_eorv(v21, __ B, p3, z12); // eorv b21, p3, z12.b + __ sve_smaxv(v13, __ S, p2, z15); // smaxv s13, p2, z15.s + __ sve_sminv(v28, __ D, p1, z25); // sminv d28, p1, z25.d + __ sve_umaxv(v20, __ B, p1, z2); // umaxv b20, p1, z2.b + __ sve_uminv(v10, __ H, p2, z25); // uminv h10, p2, z25.h + __ sve_fminv(v5, __ D, p7, z22); // fminv d5, p7, z22.d + __ sve_fmaxv(v15, __ S, p0, z18); // fmaxv s15, p0, z18.s + __ sve_fadda(v10, __ S, p0, z10); // fadda s10, p0, s10, z10.s + __ sve_uaddv(v11, __ H, p5, z3); // uaddv d11, p5, z3.h // AddWideNEONOp - __ saddwv(v8, v9, __ T8H, v10, __ T8B); // saddw v8.8H, v9.8H, v10.8B - __ saddwv2(v11, v12, __ T8H, v13, __ T16B); // saddw2 v11.8H, v12.8H, v13.16B - __ saddwv(v22, v23, __ T4S, v24, __ T4H); // saddw v22.4S, v23.4S, v24.4H - __ saddwv2(v3, v4, __ T4S, v5, __ T8H); // saddw2 v3.4S, v4.4S, v5.8H - __ saddwv(v12, v13, __ T2D, v14, __ T2S); // saddw v12.2D, v13.2D, v14.2S - __ saddwv2(v24, v25, __ T2D, v26, __ T4S); // saddw2 v24.2D, v25.2D, v26.4S - __ uaddwv(v9, v10, __ T8H, v11, __ T8B); // uaddw v9.8H, v10.8H, v11.8B - __ uaddwv2(v27, v28, __ T8H, v29, __ T16B); // uaddw2 v27.8H, v28.8H, v29.16B - __ uaddwv(v27, v28, __ T4S, v29, __ T4H); // uaddw v27.4S, v28.4S, v29.4H - __ uaddwv2(v6, v7, __ T4S, v8, __ T8H); // uaddw2 v6.4S, v7.4S, v8.8H - __ uaddwv(v20, v21, __ T2D, v22, __ T2S); // uaddw v20.2D, v21.2D, v22.2S - __ uaddwv2(v20, v21, __ T2D, v22, __ T4S); // uaddw2 v20.2D, v21.2D, v22.4S + __ saddwv(v24, v25, __ T8H, v26, __ T8B); // saddw v24.8H, v25.8H, v26.8B + __ saddwv2(v9, v10, __ T8H, v11, __ T16B); // saddw2 v9.8H, v10.8H, v11.16B + __ saddwv(v27, v28, __ T4S, v29, __ T4H); // saddw v27.4S, v28.4S, v29.4H + __ saddwv2(v27, v28, __ T4S, v29, __ T8H); // saddw2 v27.4S, v28.4S, v29.8H + __ saddwv(v6, v7, __ T2D, v8, __ T2S); // saddw v6.2D, v7.2D, v8.2S + __ saddwv2(v20, v21, __ T2D, v22, __ T4S); // saddw2 v20.2D, v21.2D, v22.4S + __ uaddwv(v20, v21, __ T8H, v22, __ T8B); // uaddw v20.8H, v21.8H, v22.8B + __ uaddwv2(v5, v6, __ T8H, v7, __ T16B); // uaddw2 v5.8H, v6.8H, v7.16B + __ uaddwv(v17, v18, __ T4S, v19, __ T4H); // uaddw v17.4S, v18.4S, v19.4H + __ uaddwv2(v15, v16, __ T4S, v17, __ T8H); // uaddw2 v15.4S, v16.4S, v17.8H + __ uaddwv(v7, v8, __ T2D, v9, __ T2S); // uaddw v7.2D, v8.2D, v9.2S + __ uaddwv2(v22, v23, __ T2D, v24, __ T4S); // uaddw2 v22.2D, v23.2D, v24.4S __ bind(forth); @@ -1476,315 +1477,315 @@ 0x9101a1a0, 0xb10a5cc8, 0xd10810aa, 0xf10fd061, 0x120cb166, 0x321764bc, 0x52174681, 0x720c0227, 0x9241018e, 0xb25a2969, 0xd278b411, 0xf26aad01, - 0x14000000, 0x17ffffd7, 0x140004d2, 0x94000000, - 0x97ffffd4, 0x940004cf, 0x3400000a, 0x34fffa2a, - 0x3400998a, 0x35000008, 0x35fff9c8, 0x35009928, - 0xb400000b, 0xb4fff96b, 0xb40098cb, 0xb500001d, - 0xb5fff91d, 0xb500987d, 0x10000013, 0x10fff8b3, - 0x10009813, 0x90000013, 0x36300016, 0x3637f836, - 0x36309796, 0x3758000c, 0x375ff7cc, 0x3758972c, + 0x14000000, 0x17ffffd7, 0x140004d3, 0x94000000, + 0x97ffffd4, 0x940004d0, 0x3400000a, 0x34fffa2a, + 0x340099aa, 0x35000008, 0x35fff9c8, 0x35009948, + 0xb400000b, 0xb4fff96b, 0xb40098eb, 0xb500001d, + 0xb5fff91d, 0xb500989d, 0x10000013, 0x10fff8b3, + 0x10009833, 0x90000013, 0x36300016, 0x3637f836, + 0x363097b6, 0x3758000c, 0x375ff7cc, 0x3758974c, 0x128313a0, 0x528a32c7, 0x7289173b, 0x92ab3acc, 0xd2a0bf94, 0xf2c285e8, 0x9358722f, 0x330e652f, 0x53067f3b, 0x93577c53, 0xb34a1aac, 0xd35a4016, 0x13946c63, 0x93c3dbc8, 0x54000000, 0x54fff5a0, - 0x54009500, 0x54000001, 0x54fff541, 0x540094a1, - 0x54000002, 0x54fff4e2, 0x54009442, 0x54000002, - 0x54fff482, 0x540093e2, 0x54000003, 0x54fff423, - 0x54009383, 0x54000003, 0x54fff3c3, 0x54009323, - 0x54000004, 0x54fff364, 0x540092c4, 0x54000005, - 0x54fff305, 0x54009265, 0x54000006, 0x54fff2a6, - 0x54009206, 0x54000007, 0x54fff247, 0x540091a7, - 0x54000008, 0x54fff1e8, 0x54009148, 0x54000009, - 0x54fff189, 0x540090e9, 0x5400000a, 0x54fff12a, - 0x5400908a, 0x5400000b, 0x54fff0cb, 0x5400902b, - 0x5400000c, 0x54fff06c, 0x54008fcc, 0x5400000d, - 0x54fff00d, 0x54008f6d, 0x5400000e, 0x54ffefae, - 0x54008f0e, 0x5400000f, 0x54ffef4f, 0x54008eaf, + 0x54009520, 0x54000001, 0x54fff541, 0x540094c1, + 0x54000002, 0x54fff4e2, 0x54009462, 0x54000002, + 0x54fff482, 0x54009402, 0x54000003, 0x54fff423, + 0x540093a3, 0x54000003, 0x54fff3c3, 0x54009343, + 0x54000004, 0x54fff364, 0x540092e4, 0x54000005, + 0x54fff305, 0x54009285, 0x54000006, 0x54fff2a6, + 0x54009226, 0x54000007, 0x54fff247, 0x540091c7, + 0x54000008, 0x54fff1e8, 0x54009168, 0x54000009, + 0x54fff189, 0x54009109, 0x5400000a, 0x54fff12a, + 0x540090aa, 0x5400000b, 0x54fff0cb, 0x5400904b, + 0x5400000c, 0x54fff06c, 0x54008fec, 0x5400000d, + 0x54fff00d, 0x54008f8d, 0x5400000e, 0x54ffefae, + 0x54008f2e, 0x5400000f, 0x54ffef4f, 0x54008ecf, 0xd40658e1, 0xd4014d22, 0xd4046543, 0xd4273f60, - 0xd44cad80, 0xd503201f, 0xd503203f, 0xd503205f, - 0xd503209f, 0xd50320bf, 0xd503219f, 0xd50323bf, - 0xd503239f, 0xd50321df, 0xd50323ff, 0xd50323df, - 0xd503211f, 0xd503233f, 0xd503231f, 0xd503215f, - 0xd503237f, 0xd503235f, 0xd69f03e0, 0xd6bf03e0, - 0xd5033fdf, 0xd50330ff, 0xd503101a, 0xd503207f, - 0xd50320ff, 0xd503329f, 0xd50339bf, 0xd61f0280, - 0xd63f0140, 0xdac123fb, 0xdac127e8, 0xdac12be0, - 0xdac12fe1, 0xdac133f5, 0xdac137f1, 0xdac13bfd, - 0xdac13ffd, 0xdac147fc, 0xd61f083f, 0xd61f0eff, - 0xd63f0abf, 0xd63f0e9f, 0xd51b4436, 0xd51b421b, - 0xd53b4433, 0xd53b420b, 0xd53b00f0, 0xd53b0026, - 0xd53be0d1, 0xdac143e0, 0xc8047f0a, 0xc816fe6a, - 0xc85f7ca1, 0xc85ffd1e, 0xc89ffe2c, 0xc8dffdc9, - 0x88077ca1, 0x8810fd82, 0x885f7d8a, 0x885fff83, - 0x889fff4e, 0x88dffd5e, 0x480e7db5, 0x4809ff76, - 0x485f7e7c, 0x485fffcb, 0x489ffc53, 0x48dffee2, - 0x08017d80, 0x0810fded, 0x085f7eb1, 0x085ffd6d, - 0x089ffd1e, 0x08dffdb8, 0xc87f074b, 0xc87fedb5, - 0xc83430c3, 0xc821989d, 0x887f2e06, 0x887ff984, - 0x88353f9b, 0x8829d0cf, 0xf8183238, 0xb800a341, - 0x381ef00f, 0x7800d231, 0xf8431325, 0xb858c1f3, - 0x39401c74, 0x785e7093, 0x389fa26e, 0x789cb27c, - 0x78c0d36e, 0xb8988306, 0xfc457052, 0xbc5d0380, - 0xfc01739f, 0xbc02b32b, 0xf8147d0e, 0xb81a3d39, - 0x381f4ef0, 0x781c8d36, 0xf846df0b, 0xb8434e75, - 0x385feee6, 0x78415d07, 0x389e1d84, 0x789fcd68, - 0x78de4eae, 0xb89b9de0, 0xfc41dc5b, 0xbc410ead, - 0xfc010f6c, 0xbc1a5f22, 0xf81eb5aa, 0xb8032427, - 0x3800546a, 0x781df4c5, 0xf85626cd, 0xb859644d, - 0x385e860d, 0x785ea458, 0x389ff6e3, 0x789d5513, - 0x78df86e2, 0xb89a9793, 0xfc5af46f, 0xbc5b17ac, - 0xfc184435, 0xbc19d527, 0xf8226a85, 0xb83ed94e, - 0x383cd824, 0x783af945, 0xf87c7856, 0xb87c780c, - 0x386ff908, 0x786e5ab1, 0x38a8fb11, 0x78bef94a, - 0x78e07af1, 0xb8a07bd9, 0xfc775b05, 0xbc6f7876, - 0xfc30fba4, 0xbc3cda87, 0xf91ff41b, 0xb91f3115, - 0x391c0fb1, 0x791c685b, 0xf9586021, 0xb958b23d, - 0x39598921, 0x795d3077, 0x399d0675, 0x7998d8f3, - 0x79dbd02a, 0xb99d068a, 0xfd5d11a0, 0xbd58d76b, - 0xfd1ac72d, 0xbd1d9c14, 0x5800001a, 0x18ffda33, - 0xf8991100, 0xd8007960, 0xf8a758e0, 0xf9989d80, - 0x1a0b0298, 0x3a1c01a0, 0x5a0400ea, 0x7a02020f, - 0x9a1d028c, 0xba0e01ad, 0xda140186, 0xfa19022c, - 0x0b2b877e, 0x2b21c8ee, 0xcb3ba47d, 0x6b3ae9a0, - 0x8b256a36, 0xab28efd1, 0xcb37ce6a, 0xeb254fa6, - 0x3a498264, 0x7a4a72c2, 0xba4c91aa, 0xfa502303, - 0x3a4b68ed, 0x7a4a9b6b, 0xba4dd86d, 0xfa50cb45, - 0x1a9cd2aa, 0x1a9bd537, 0x5a8fd3aa, 0x5a95273e, - 0x9a95c220, 0x9a9426b0, 0xda8393d3, 0xda980573, - 0x5ac0033b, 0x5ac0046e, 0x5ac00a2e, 0x5ac011e7, - 0x5ac01798, 0xdac00331, 0xdac00742, 0xdac008bc, - 0xdac00f59, 0xdac0121b, 0xdac014d1, 0xdac10195, - 0xdac10480, 0xdac10b6c, 0xdac10f91, 0xdac1105c, - 0xdac11551, 0xdac119cf, 0xdac11c6e, 0xd71f0b2f, - 0xd71f0e6e, 0xd73f08b0, 0xd73f0c9a, 0x1ac20899, - 0x1add0d82, 0x1ac72111, 0x1ad92483, 0x1ad92b44, - 0x1ac02e24, 0x9ad70a3a, 0x9adc0eaf, 0x9aca2371, - 0x9ac72403, 0x9ac62939, 0x9acf2faf, 0x9bd17c4a, - 0x9b4b7d67, 0x1b1d5cf7, 0x1b0baf6e, 0x9b0c3f04, - 0x9b0bf28e, 0x9b2c5d6d, 0x9b2ea75e, 0x9ba7154d, - 0x9ba3adfd, 0x7edf160c, 0x1ef30a5f, 0x1eef1a15, - 0x1ee22aaa, 0x1ee73b8a, 0x1ef24bfe, 0x1ee65841, - 0x1ef9886a, 0x7ea1d4eb, 0x1e23080c, 0x1e261bb3, - 0x1e2028d7, 0x1e223b7c, 0x1e3d48e5, 0x1e2d5b2c, - 0x1e338b0c, 0x7ef6d648, 0x1e740aba, 0x1e7e1853, - 0x1e762916, 0x1e6c3ab3, 0x1e664ab2, 0x1e635870, - 0x1e7c887d, 0x1fca35cf, 0x1f0a6a4c, 0x1f0ff4e7, - 0x1f2032e0, 0x1f2d21d8, 0x1f4950ef, 0x1f5fc3b3, - 0x1f705522, 0x1f616c9e, 0x1e204319, 0x1e20c2ae, - 0x1e2140cd, 0x1e21c32c, 0x1e22c3d9, 0x1e23c2bc, - 0x1ee242f0, 0x1e6043a5, 0x1e60c276, 0x1e61428d, - 0x1e61c393, 0x1e6240d2, 0x1ee1c0ee, 0x1e38035c, - 0x9e3800d1, 0x1e780081, 0x9e7802ad, 0x1e2202a7, - 0x9e2202fb, 0x1e62028d, 0x9e62037f, 0x1e2402aa, - 0x9e640225, 0x1e3001cb, 0x9e7002ad, 0x1e2601da, - 0x9e660304, 0x1e2703b8, 0x9e6701cc, 0x1e3c2220, - 0x1e6022c0, 0x1e2020c8, 0x1e602368, 0x293c30db, - 0x29602e6e, 0x697a31e0, 0xa9025ee9, 0xa975134f, - 0x29ac20d1, 0x29f20887, 0x69fe26ce, 0xa9b0530d, - 0xa9c62d48, 0x28b21618, 0x28f06920, 0x68f00a38, - 0xa8bd45da, 0xa8c357be, 0x28325d51, 0x286c1bda, - 0xa804229e, 0xa8437536, 0x0c40702d, 0x4cdfa201, - 0x0cd36f36, 0x4cdf2759, 0x0d40c1e9, 0x4ddfcb2c, - 0x0dddcdc4, 0x4c408e31, 0x0cdf8777, 0x4d60c302, - 0x0dffc80b, 0x4df6cd82, 0x4ccd49b5, 0x0c40496c, - 0x4d40e5d2, 0x4ddfeab9, 0x0ddbee14, 0x4cdf0420, - 0x0cdd0360, 0x0d60e232, 0x0dffe705, 0x0df4e8bc, - 0x0e31b841, 0x4e31bab4, 0x0e71bbdd, 0x4e71ba30, - 0x4eb1b9cd, 0x0e30a96a, 0x4e30abdd, 0x0e70abdd, - 0x4e70aa93, 0x4eb0aaf6, 0x6e30f96a, 0x0e31a8a4, - 0x2e31a81f, 0x4e31aad5, 0x6e31a928, 0x0e71a81f, - 0x2e71aa93, 0x4e71a96a, 0x6e71abbc, 0x4eb1a862, - 0x6eb1ab59, 0x6eb0f8c5, 0x7e30f883, 0x7e70f928, - 0x7eb0faf6, 0x7ef0fa93, 0x0ea0c9cd, 0x4ea0c8c5, - 0x4ee0cbdd, 0x2ea0cb38, 0x6ea0cad5, 0x6ee0cb7a, - 0x0ea0db38, 0x4ea0d883, 0x4ee0db38, 0x0ea0eb7a, - 0x4ea0eb17, 0x4ee0ea0f, 0x2ea0dad5, 0x6ea0d883, - 0x6ee0db38, 0x0e20b928, 0x4e20bb59, 0x0e60bab4, - 0x4e60ba30, 0x0ea0ba51, 0x4ea0b862, 0x4ee0b841, - 0x0ea0f820, 0x4ea0fb38, 0x4ee0f8a4, 0x0ef8f883, - 0x4ef8f9ac, 0x2ea0f81f, 0x6ea0fbbc, 0x6ee0f96a, - 0x2ef8fb7a, 0x6ef8f862, 0x2ea1f9ac, 0x6ea1fa72, - 0x6ee1f81f, 0x2ef9f841, 0x6ef9f9cd, 0x2e205bdd, - 0x6e205820, 0x0e351e93, 0x4e2e1dac, 0x0eb31e51, - 0x4eb81ef6, 0x2e2f1dcd, 0x6e3e1fbc, 0x0e2087fe, - 0x4e21841f, 0x0e638441, 0x4e7c877a, 0x0ebe87bc, - 0x4ea684a4, 0x4ee087fe, 0x0e260ca4, 0x4e280ce6, - 0x0e600ffe, 0x4e7c0f7a, 0x0eb40e72, 0x4eab0d49, - 0x4eea0d28, 0x2e2e0dac, 0x6e220c20, 0x2e760eb4, - 0x6e630c41, 0x2eba0f38, 0x6ea40c62, 0x6ee20c20, - 0x0e2bd549, 0x4e3ad738, 0x4e7cd77a, 0x0e521630, - 0x4e4017fe, 0x2e258483, 0x6e2c856a, 0x2e798717, - 0x6e6c856a, 0x2ea684a4, 0x6eb48672, 0x6ee48462, - 0x0e2d2d8b, 0x4e2a2d28, 0x0e6c2d6a, 0x4e712e0f, - 0x0eb32e51, 0x4ea42c62, 0x4eec2d6a, 0x2e2e2dac, - 0x6e2e2dac, 0x2e712e0f, 0x6e6f2dcd, 0x2ea42c62, - 0x6ea92d07, 0x6ef62eb4, 0x0ebcd77a, 0x4eb2d630, - 0x4ee6d4a4, 0x0ec41462, 0x4ec614a4, 0x0e2e9dac, - 0x4e349e72, 0x0e779ed5, 0x4e729e30, 0x0eb49e72, - 0x4ead9d8b, 0x2eb7d6d5, 0x6eb9d717, 0x6eeed5ac, - 0x2edc177a, 0x6ed91717, 0x2e3ed7bc, 0x6e30d5ee, - 0x6e6dd58b, 0x2e5a1738, 0x6e431441, 0x2e2eddac, - 0x6e21dc1f, 0x6e6cdd6a, 0x2e521e30, 0x6e491d07, - 0x0e649462, 0x4e659483, 0x0eaf95cd, 0x4eb59693, - 0x0e33ce51, 0x4e32ce30, 0x4e65cc83, 0x0e430c41, - 0x4e4d0d8b, 0x2e6097fe, 0x6e6794c5, 0x2eaa9528, - 0x6eb1960f, 0x0ebfcfdd, 0x4ea0cffe, 0x4ee2cc20, - 0x0ed60eb4, 0x4ec90d07, 0x2e36feb4, 0x6e39ff17, - 0x6e7effbc, 0x2e573ed5, 0x6e5d3f9b, 0x0e3b6759, - 0x4e2764c5, 0x0e636441, 0x4e796717, 0x0eb26630, - 0x4ea1641f, 0x2e2764c5, 0x6e2e65ac, 0x2e6b6549, - 0x6e7e67bc, 0x2eb1660f, 0x6ebf67dd, 0x0e38a6f6, - 0x4e21a41f, 0x0e75a693, 0x4e61a41f, 0x0ea7a4c5, - 0x4eb0a5ee, 0x0e34f672, 0x4e21f41f, 0x4e74f672, - 0x0e5d379b, 0x4e5636b4, 0x0e326e30, 0x4e2e6dac, - 0x0e6d6d8b, 0x4e6b6d49, 0x0ea86ce6, 0x4ea06ffe, - 0x2e336e51, 0x6e3d6f9b, 0x2e7e6fbc, 0x6e606ffe, - 0x2ea96d07, 0x6eac6d6a, 0x0e36aeb4, 0x4e2cad6a, - 0x0e66aca4, 0x4e7aaf38, 0x0eb3ae51, 0x4eb3ae51, - 0x2e38aef6, 0x6e25ac83, 0x2e7fafdd, 0x6e71ae0f, - 0x2eb8aef6, 0x6eb5ae93, 0x2e35a693, 0x6e38a6f6, - 0x2e64a462, 0x6e71a60f, 0x2ea8a4e6, 0x6eaea5ac, - 0x0e72b630, 0x4e6db58b, 0x0eafb5cd, 0x4eb9b717, - 0x0e232441, 0x4e2027fe, 0x0e752693, 0x4e6724c5, - 0x0eb32651, 0x4ea42462, 0x0eb2f630, 0x4eb8f6f6, - 0x4eeff5cd, 0x0ecc356a, 0x4ed736d5, 0x2ebfefdd, - 0x6ebdef9b, 0x6eeeedac, 0x2edd2f9b, 0x6ec52c83, - 0x0f81100f, 0x4fab8949, 0x4fc618a4, 0x0faf51cd, - 0x4fa58083, 0x4fcd598b, 0x2fae91ac, 0x4f81800f, - 0x6fcb9949, 0x0f5d818b, 0x4f438841, 0x0fa28020, - 0x4faf89cd, 0x0e393717, 0x4e243462, 0x0e743672, - 0x4e6e35ac, 0x0ea634a4, 0x4ebe37bc, 0x4ee037fe, - 0x0e3f3fdd, 0x4e323e30, 0x0e7d3f9b, 0x4e683ce6, - 0x0eab3d49, 0x4ebf3fdd, 0x4ef43e72, 0x2e298d07, - 0x6e268ca4, 0x2e698d07, 0x6e718e0f, 0x2eab8d49, - 0x6eb98f17, 0x6eea8d28, 0x2e243462, 0x6e3e37bc, - 0x2e7736d5, 0x6e61341f, 0x2ea734c5, 0x6ebd379b, - 0x6ee23420, 0x2e333e51, 0x6e313e0f, 0x2e663ca4, - 0x6e7c3f7a, 0x2eaa3d28, 0x6ebe3fbc, 0x6ef83ef6, - 0x0e3de79b, 0x4e3de79b, 0x4e7be759, 0x2eb9e717, - 0x6ea2e420, 0x6ee6e4a4, 0x2e28e4e6, 0x6e34e672, - 0x6e62e420, 0x659229e2, 0x65903cb3, 0x65d03683, - 0x65913163, 0x65d120df, 0x65d323c6, 0x25dd8ecd, - 0x25d2063e, 0x258b0947, 0x2501358b, 0x25823032, - 0x254181d6, 0x24a646a1, 0x24719e73, 0x24233cd8, - 0x24adf4c2, 0xba5fd3e3, 0x3a5f03e5, 0xfa411be4, - 0x7a42cbe2, 0x93df03ff, 0xc820ffff, 0x8822fc7f, - 0xc8247cbf, 0x88267fff, 0x4e010fe0, 0x5e040420, - 0x4e081fe1, 0x4e0c1fe1, 0x4e0a1fe1, 0x4e071fe1, - 0x4e042c20, 0x4e062c20, 0x4e052c20, 0x4e083c20, - 0x0e0c3c20, 0x0e0a3c20, 0x0e073c20, 0x9eae0020, - 0x0f03f409, 0x6f03f40e, 0x4cc0ac3f, 0x0ea1b820, - 0x0ef9b820, 0x4ef9b820, 0x4e21c862, 0x0e79c862, - 0x4e79c862, 0x4e61b8a4, 0x0e79b8a4, 0x4e79b8a4, - 0x05a08020, 0x05104fe0, 0x05505001, 0x05906fe2, - 0x05d03005, 0x05101fea, 0x05901feb, 0x0590cc0b, - 0x0590de0b, 0x04b0e3e0, 0x0470e7e1, 0x042f9c20, - 0x043f9c35, 0x047f9c20, 0x04ff9c20, 0x04299420, - 0x04319160, 0x0461943e, 0x04a19020, 0x04038100, - 0x040381a0, 0x040387e1, 0x04438be2, 0x04c38fe3, - 0x040181e0, 0x04018100, 0x04018621, 0x04418b22, - 0x04418822, 0x04818c23, 0x040081e0, 0x04008120, - 0x04008761, 0x04008621, 0x04408822, 0x04808c23, - 0x042053ff, 0x047f5401, 0x25208028, 0x2538cfe0, - 0x2578d001, 0x25b8efe2, 0x25f8f007, 0x2538dfea, - 0x25b8dfeb, 0xa400a3e0, 0xa420a7e0, 0xa4484be0, - 0xa467afe0, 0xa4a8a7ea, 0xa547a814, 0xa4084ffe, - 0xa55c53e0, 0xa5e1540b, 0xe400fbf6, 0xe408ffff, - 0xe420e7e0, 0xe4484be0, 0xe460efe0, 0xe547e400, - 0xe4014be0, 0xe4a84fe0, 0xe5f15000, 0x858043e0, - 0x85a043ff, 0xe59f5d08, 0x0420e3e9, 0x0460e3ea, - 0x04a0e3eb, 0x04e0e3ec, 0x25104042, 0x25104871, - 0x25904861, 0x25904c92, 0x05344020, 0x05744041, - 0x05b44062, 0x05f44083, 0x252c8840, 0x253c1420, - 0x25681572, 0x25a21ce3, 0x25ea1e34, 0x253c0421, - 0x25680572, 0x25a20ce3, 0x25ea0e34, 0x0522c020, - 0x05e6c0a4, 0x2401a001, 0x2443a051, 0x24858881, - 0x24c78cd1, 0x24850891, 0x24c70cc1, 0x250f9001, - 0x25508051, 0x25802491, 0x25df28c1, 0x25850c81, - 0x251e10d1, 0x65816001, 0x65c36051, 0x65854891, - 0x65c74cc1, 0x05733820, 0x05b238a4, 0x05f138e6, - 0x0570396a, 0x65d0a001, 0x65d6a443, 0x65d4a826, - 0x6594ac26, 0x6554ac26, 0x6556ac26, 0x6552ac26, - 0x65cbac85, 0x65caac01, 0x6589ac85, 0x6588ac01, - 0x65c9ac85, 0x65c8ac01, 0x65dea833, 0x659ca509, - 0x65d8a801, 0x65dcac01, 0x655cb241, 0x0520a1e0, - 0x0521a601, 0x052281e0, 0x05238601, 0x04a14026, - 0x042244a6, 0x046344a6, 0x04a444a6, 0x04e544a7, - 0x0568aca7, 0x05b23230, 0x05302a30, 0x05702a30, - 0x05b02a30, 0x05f02a30, 0x853040af, 0xc5b040af, - 0xe57080af, 0xe5b080af, 0x25034440, 0x254054c4, - 0x25034640, 0x25415a05, 0x25834440, 0x25c54489, - 0x250b5d3a, 0x2550dc20, 0x2518e3e1, 0x2518e021, - 0x2518e0a1, 0x2518e121, 0x2518e1a1, 0x2558e3e2, - 0x2558e042, 0x2558e0c2, 0x2558e142, 0x2598e3e3, - 0x2598e063, 0x2598e0e3, 0x2598e163, 0x25d8e3e4, - 0x25d8e084, 0x25d8e104, 0x25d8e184, 0x2518e407, - 0x05214800, 0x05614800, 0x05a14800, 0x05e14800, - 0x05214c00, 0x05614c00, 0x05a14c00, 0x05e14c00, - 0x05304001, 0x05314001, 0x05a18610, 0x05e18610, - 0x0420bc31, 0x05271e11, 0x6545e891, 0x6585e891, - 0x65c5e891, 0x6545c891, 0x6585c891, 0x65c5c891, - 0x052c8020, 0x056c8020, 0x05ac8020, 0x05ec8020, - 0x45b0c210, 0x45f1c231, 0x45527a30, 0x45957e93, - 0x45d872f6, 0x455b7759, 0x1e601000, 0x1e603000, - 0x1e621000, 0x1e623000, 0x1e641000, 0x1e643000, - 0x1e661000, 0x1e663000, 0x1e681000, 0x1e683000, - 0x1e6a1000, 0x1e6a3000, 0x1e6c1000, 0x1e6c3000, - 0x1e6e1000, 0x1e6e3000, 0x1e701000, 0x1e703000, - 0x1e721000, 0x1e723000, 0x1e741000, 0x1e743000, - 0x1e761000, 0x1e763000, 0x1e781000, 0x1e783000, - 0x1e7a1000, 0x1e7a3000, 0x1e7c1000, 0x1e7c3000, - 0x1e7e1000, 0x1e7e3000, 0xf82c8114, 0xf8390274, - 0xf820130b, 0xf82623f4, 0xf82e30d0, 0xf82051e7, - 0xf833413a, 0xf82a72b7, 0xf836605c, 0xf8a3826f, - 0xf8b40087, 0xf8bd1007, 0xf8a92290, 0xf8b73204, - 0xf8aa5177, 0xf8b943e6, 0xf8b072ed, 0xf8ac61c1, - 0xf8e98215, 0xf8fa008f, 0xf8e41110, 0xf8e6209e, - 0xf8fd33b1, 0xf8fa51e9, 0xf8e243ab, 0xf8e37027, - 0xf8fb61f5, 0xf86e81e8, 0xf87600b9, 0xf87411f5, - 0xf87723d0, 0xf8743014, 0xf8645313, 0xf8644094, - 0xf878727a, 0xf8626108, 0xb82e81f8, 0xb83f0096, - 0xb83f1141, 0xb834200c, 0xb8293307, 0xb8305364, - 0xb826436a, 0xb838720d, 0xb83f62d6, 0xb8b483bf, - 0xb8a9028e, 0xb8a71394, 0xb8a921cb, 0xb8ac3034, - 0xb8b85269, 0xb8ad41f3, 0xb8b07005, 0xb8a3610c, - 0xb8ef820f, 0xb8e403cf, 0xb8e51140, 0xb8f6207b, - 0xb8e03269, 0xb8fd530a, 0xb8e440f4, 0xb8f871dd, - 0xb8f5636b, 0xb86d83f0, 0xb871006e, 0xb87e12d0, - 0xb8742287, 0xb8633341, 0xb8735209, 0xb8714015, - 0xb8647302, 0xb86e6166, 0xce3179d5, 0xce035c6c, - 0xce788c69, 0xce93bc7c, 0xce758347, 0xce6884ae, - 0xcec080ba, 0xce718a56, 0x2520c9e0, 0x2561c834, - 0x05800d2c, 0x0540154b, 0x0500093f, 0x25e0d78f, - 0x25a1c81c, 0x058026a8, 0x05401eca, 0x05008816, - 0x25e0c5d7, 0x25e1d35a, 0x05800e11, 0x0540155e, - 0x05026c22, 0x25e0ccf6, 0x2521c0a8, 0x0580000f, - 0x054287b3, 0x0500b04d, 0x2560d481, 0x25a1d84c, - 0x05800d38, 0x05407854, 0x050015d5, 0x25e0dabf, - 0x25a1cf12, 0x0580158b, 0x05400e05, 0x05003682, - 0x047a0093, 0x043e0462, 0x65d400b4, 0x658d09bd, - 0x658107ce, 0x04e3107c, 0x04291b29, 0x042e155a, - 0x04e71f54, 0x04d6b0d4, 0x044003ad, 0x041a0029, - 0x041099fb, 0x04db1e24, 0x0419a302, 0x041abdba, - 0x04d90e16, 0x04d38571, 0x04118210, 0x04d006fc, - 0x04d4115c, 0x04d51cf1, 0x0457af04, 0x041ea969, - 0x049816c4, 0x056781e4, 0x05e49f44, 0x04481745, - 0x040a033f, 0x04890468, 0x04cb1b07, 0x04011e38, - 0x049cafca, 0x65809ba8, 0x65cd97ff, 0x65c694e0, - 0x65879add, 0x65829a9d, 0x049db246, 0x6582b51a, - 0x6580ab93, 0x65c1a7d1, 0x65cdbdd8, 0x65c1914e, - 0x65ab980b, 0x65f416fc, 0x65b837b7, 0x65ada6fb, - 0x65facfe4, 0x65fde454, 0x65a35ee0, 0x65ed6b85, - 0x044a4d0d, 0x049d7009, 0x043731b0, 0x04ad33d7, - 0x046032d9, 0x04eb33d9, 0x05766aee, 0x05606e45, - 0x65c88069, 0x455db08e, 0x45c4b6ce, 0x042f3edb, - 0x0438397f, 0x4418938c, 0x44da909c, 0x449981e6, - 0x449b9641, 0x045a2882, 0x04982b8b, 0x045937e3, - 0x044835f8, 0x044a2d06, 0x04c93c95, 0x040b34d8, - 0x65c72924, 0x65c627ea, 0x65d82c79, 0x0441284e, - 0x0e2a1128, 0x4e2d118b, 0x0e7812f6, 0x4e651083, - 0x0eae11ac, 0x4eba1338, 0x2e2b1149, 0x6e3d139b, - 0x2e7d139b, 0x6e6810e6, 0x2eb612b4, 0x6eb612b4, - + 0xd44cad80, 0x00006e41, 0xd503201f, 0xd503203f, + 0xd503205f, 0xd503209f, 0xd50320bf, 0xd503219f, + 0xd50323bf, 0xd503239f, 0xd50321df, 0xd50323ff, + 0xd50323df, 0xd503211f, 0xd503233f, 0xd503231f, + 0xd503215f, 0xd503237f, 0xd503235f, 0xd69f03e0, + 0xd6bf03e0, 0xd5033fdf, 0xd50330ff, 0xd5031004, + 0xd503207f, 0xd50320ff, 0xd503399f, 0xd5033abf, + 0xd61f0140, 0xd63f0360, 0xdac123e8, 0xdac127e0, + 0xdac12be1, 0xdac12ff5, 0xdac133f1, 0xdac137fd, + 0xdac13bfd, 0xdac13ffc, 0xdac147e1, 0xd61f0aff, + 0xd61f0ebf, 0xd63f0a9f, 0xd63f0edf, 0xd51b443b, + 0xd51b4213, 0xd53b442b, 0xd53b4210, 0xd53b00e6, + 0xd53b0031, 0xd53be0c0, 0xdac143e4, 0xc80a7ed8, + 0xc80afc33, 0xc85f7fc5, 0xc85ffd88, 0xc89ffd31, + 0xc8dffcee, 0x88017e05, 0x8802fd4c, 0x885f7c6c, + 0x885ffddc, 0x889fffda, 0x88dffdca, 0x48157d2d, + 0x4816ff9b, 0x485f7d73, 0x485ffe7e, 0x489ffee2, + 0x48dffc01, 0x080c7db0, 0x080ffeb1, 0x085f7d6d, + 0x085ffd1e, 0x089ffdb8, 0x08dffc2b, 0xc87f577a, + 0xc87fd06d, 0xc82c07a6, 0xc826ae04, 0x887f7984, + 0x887fedf5, 0x883c3e89, 0x8826abb1, 0xf810d379, + 0xb8027044, 0x39003897, 0x780173cc, 0xf843323a, + 0xb85ce3a1, 0x385f7031, 0x785ed16a, 0x389f7175, + 0x789cc270, 0x78c0b31c, 0xb88351f8, 0xfc5752a3, + 0xbc5852e2, 0xfc10b046, 0xbd0034c5, 0xf8132cb4, + 0xb819ed88, 0x381e3c54, 0x781c5fae, 0xf8408fad, + 0xb85dde78, 0x385f6f63, 0x785f7c31, 0x389f9e71, + 0x789e6d75, 0x78de2d21, 0xb8984ef5, 0xfc5efe98, + 0xbc5bfd16, 0xfc1aae06, 0xbc1cafa5, 0xf816d79d, + 0xb81a9704, 0x381f552d, 0x781f24fa, 0xf851b46d, + 0xb84304a1, 0x385ef5a8, 0x785cb697, 0x389ff4d4, + 0x789d6629, 0x78df14d5, 0xb89f15aa, 0xfc5be408, + 0xbc5c962a, 0xfc0025a4, 0xbc1ab40d, 0xf826cb6c, + 0xb8306900, 0x383af880, 0x7825db2e, 0xf8714889, + 0xb867689b, 0x387eda2f, 0x7876c810, 0x38bef956, + 0x78aafabd, 0x78f34963, 0xb8bd5b8d, 0xfc65fbb8, + 0xbc68d906, 0xfc38cb1e, 0xbc2cfa34, 0xf91f226d, + 0xb91aa2f3, 0x39187bb7, 0x791f7176, 0xf95d9143, + 0xb95e7e08, 0x395a2697, 0x795f3422, 0x399c2624, + 0x799c2374, 0x79dfa1d9, 0xb99d595a, 0xfd5b1869, + 0xbd593d9c, 0xfd1cdaeb, 0xbd1f4c6f, 0x5800000a, + 0x18000010, 0xf8863080, 0xd8000000, 0xf8b1e880, + 0xf99ac9e0, 0x1a07015c, 0x3a1001e4, 0x5a140182, + 0x7a0d01bd, 0x9a0c00ce, 0xba110194, 0xda1b03d9, + 0xfa11000b, 0x0b21c8ee, 0x2b3ba47d, 0xcb3ae9a0, + 0x6b256a36, 0x8b28efd1, 0xab37ce6a, 0xcb254fa6, + 0xeb2d4d33, 0x3a4a72c2, 0x7a4c91aa, 0xba502303, + 0xfa5030ee, 0x3a439ac5, 0x7a5bbba6, 0xba4a3b68, + 0xfa57caaf, 0x1a9e3369, 0x1a9dd5fd, 0x5a8402b9, + 0x5a9d66b1, 0x9a868295, 0x9a95747e, 0xda80c30b, + 0xda8355d9, 0x5ac000f1, 0x5ac0070f, 0x5ac00a3c, + 0x5ac01059, 0x5ac0179a, 0xdac00325, 0xdac0077a, + 0xdac00a30, 0xdac00ea6, 0xdac0100c, 0xdac01584, + 0xdac1023b, 0xdac1079c, 0xdac10a22, 0xdac10dea, + 0xdac111ce, 0xdac11723, 0xdac11a6f, 0xdac11cae, + 0xd71f0a04, 0xd71f0f59, 0xd73f0882, 0xd73f0c4c, + 0x1ac80a3d, 0x1ac40c67, 0x1ada2099, 0x1ad12499, + 0x1ad12b40, 0x1ad52df7, 0x9adb0a3c, 0x9ac00c6a, + 0x9ac92327, 0x9add25e6, 0x9ac2294f, 0x9acb2cf1, + 0x9bc77eeb, 0x9b4e7efd, 0x1b0b117b, 0x1b0fb998, + 0x9b1c3574, 0x9b17f98b, 0x9b2935da, 0x9b25f4ea, + 0x9bab306f, 0x9bbec7cf, 0x7ed016b3, 0x1ef5094f, + 0x1efc1942, 0x1eff2bc7, 0x1ee23832, 0x1ee34946, + 0x1ee75979, 0x1ee08981, 0x7ebdd663, 0x1e260ae6, + 0x1e3b1b80, 0x1e2728a2, 0x1e39399d, 0x1e38498d, + 0x1e325913, 0x1e358b56, 0x7ee2d674, 0x1e680ade, + 0x1e751a76, 0x1e752a4c, 0x1e633a06, 0x1e634ba3, + 0x1e6e59fc, 0x1e6c89aa, 0x1fda1d52, 0x1f1d01e7, + 0x1f0ce017, 0x1f283dae, 0x1f344d27, 0x1f500bfd, + 0x1f55fa09, 0x1f7b6424, 0x1f7535d8, 0x1e204186, + 0x1e20c339, 0x1e21439e, 0x1e21c215, 0x1e22c0b7, + 0x1e23c2dd, 0x1ee241b3, 0x1e604274, 0x1e60c25c, + 0x1e6141c6, 0x1e61c387, 0x1e62423a, 0x1ee1c026, + 0x1e3801c4, 0x9e3800f4, 0x1e780375, 0x9e7801b7, + 0x1e2203d4, 0x9e22015c, 0x1e6200b5, 0x9e620171, + 0x1e2401cd, 0x9e640374, 0x1e30008e, 0x9e700317, + 0x1e26019d, 0x9e66022e, 0x1e2702bc, 0x9e6700c0, + 0x1e322360, 0x1e6d2360, 0x1e2020c8, 0x1e602008, + 0x29104de4, 0x297203ce, 0x69741ef8, 0xa90869e0, + 0xa973191a, 0x29b228ef, 0x29e479c1, 0x69ee76f4, + 0xa9863503, 0xa9f96605, 0x28b01411, 0x28ca3313, + 0x68e239f1, 0xa88347ca, 0xa8c12917, 0x28107b4a, + 0x286a6114, 0xa83226b9, 0xa8475923, 0x0c4073df, + 0x4cdfa0b5, 0x0cd06d39, 0x4cdf2590, 0x0d40c0f8, + 0x4ddfca1b, 0x0dc7cd7a, 0x4c408d9f, 0x0cdf8530, + 0x4d60c0df, 0x0dffcae7, 0x4de1ccc4, 0x4ccf4a64, + 0x0c4049d9, 0x4d40e79a, 0x4ddfe8ba, 0x0dcaedc2, + 0x4cdf04de, 0x0cd9017a, 0x0d60e191, 0x0dffe552, + 0x0dfaebad, 0x0e31b96a, 0x4e31bbdd, 0x0e71bbdd, + 0x4e71ba93, 0x4eb1baf6, 0x0e30a96a, 0x4e30a8a4, + 0x0e70a81f, 0x4e70aad5, 0x4eb0a928, 0x6e30f81f, + 0x0e31aa93, 0x2e31a96a, 0x4e31abbc, 0x6e31a862, + 0x0e71ab59, 0x2e71a8c5, 0x4e71a883, 0x6e71a928, + 0x4eb1aaf6, 0x6eb1aa93, 0x6eb0f9cd, 0x7e30f8c5, + 0x7e70fbdd, 0x7eb0fb38, 0x7ef0fad5, 0x0ea0cb7a, + 0x4ea0cb38, 0x4ee0c883, 0x2ea0cb38, 0x6ea0cb7a, + 0x6ee0cb17, 0x0ea0da0f, 0x4ea0dad5, 0x4ee0d883, + 0x0ea0eb38, 0x4ea0e928, 0x4ee0eb59, 0x2ea0dab4, + 0x6ea0da30, 0x6ee0da51, 0x0e20b862, 0x4e20b841, + 0x0e60b820, 0x4e60bb38, 0x0ea0b8a4, 0x4ea0b883, + 0x4ee0b9ac, 0x0ea0f81f, 0x4ea0fbbc, 0x4ee0f96a, + 0x0ef8fb7a, 0x4ef8f862, 0x2ea0f9ac, 0x6ea0fa72, + 0x6ee0f81f, 0x2ef8f841, 0x6ef8f9cd, 0x2ea1fbdd, + 0x6ea1f820, 0x6ee1fa93, 0x2ef9f9ac, 0x6ef9fa51, + 0x2e205af6, 0x6e2059cd, 0x0e3e1fbc, 0x4e201ffe, + 0x0ea11c1f, 0x4ea31c41, 0x2e3c1f7a, 0x6e3e1fbc, + 0x0e2684a4, 0x4e2087fe, 0x0e6684a4, 0x4e6884e6, + 0x0ea087fe, 0x4ebc877a, 0x4ef48672, 0x0e2b0d49, + 0x4e2a0d28, 0x0e6e0dac, 0x4e620c20, 0x0eb60eb4, + 0x4ea30c41, 0x4efa0f38, 0x2e240c62, 0x6e220c20, + 0x2e6b0d49, 0x6e7a0f38, 0x2ebc0f7a, 0x6eb20e30, + 0x6ee00ffe, 0x0e25d483, 0x4e2cd56a, 0x4e79d717, + 0x0e4c156a, 0x4e4614a4, 0x2e348672, 0x6e248462, + 0x2e6d858b, 0x6e6a8528, 0x2eac856a, 0x6eb1860f, + 0x6ef38651, 0x0e242c62, 0x4e2c2d6a, 0x0e6e2dac, + 0x4e6e2dac, 0x0eb12e0f, 0x4eaf2dcd, 0x4ee42c62, + 0x2e292d07, 0x6e362eb4, 0x2e7c2f7a, 0x6e722e30, + 0x2ea62ca4, 0x6ea42c62, 0x6ee62ca4, 0x0eaed5ac, + 0x4eb4d672, 0x4ef7d6d5, 0x0ed21630, 0x4ed41672, + 0x0e2d9d8b, 0x4e379ed5, 0x0e799f17, 0x4e6e9dac, + 0x0ebc9f7a, 0x4eb99f17, 0x2ebed7bc, 0x6eb0d5ee, + 0x6eedd58b, 0x2eda1738, 0x6ec31441, 0x2e2ed5ac, + 0x6e21d41f, 0x6e6cd56a, 0x2e521630, 0x6e491507, + 0x2e24dc62, 0x6e25dc83, 0x6e6fddcd, 0x2e551e93, + 0x6e531e51, 0x0e729630, 0x4e659483, 0x0ea39441, + 0x4ead958b, 0x0e20cffe, 0x4e27ccc5, 0x4e6acd28, + 0x0e510e0f, 0x4e5f0fdd, 0x2e6097fe, 0x6e629420, + 0x2eb696b4, 0x6ea99507, 0x0eb6ceb4, 0x4eb9cf17, + 0x4efecfbc, 0x0ed70ed5, 0x4edd0f9b, 0x2e3bff59, + 0x6e27fcc5, 0x6e63fc41, 0x2e593f17, 0x6e523e30, + 0x0e21641f, 0x4e2764c5, 0x0e6e65ac, 0x4e6b6549, + 0x0ebe67bc, 0x4eb1660f, 0x2e3f67dd, 0x6e3866f6, + 0x2e61641f, 0x6e756693, 0x2ea1641f, 0x6ea764c5, + 0x0e30a5ee, 0x4e34a672, 0x0e61a41f, 0x4e74a672, + 0x0ebda79b, 0x4eb6a6b4, 0x0e32f630, 0x4e2ef5ac, + 0x4e6df58b, 0x0e4b3549, 0x4e4834e6, 0x0e206ffe, + 0x4e336e51, 0x0e7d6f9b, 0x4e7e6fbc, 0x0ea06ffe, + 0x4ea96d07, 0x2e2c6d6a, 0x6e366eb4, 0x2e6c6d6a, + 0x6e666ca4, 0x2eba6f38, 0x6eb36e51, 0x0e33ae51, + 0x4e38aef6, 0x0e65ac83, 0x4e7fafdd, 0x0eb1ae0f, + 0x4eb8aef6, 0x2e35ae93, 0x6e35ae93, 0x2e78aef6, + 0x6e64ac62, 0x2eb1ae0f, 0x6ea8ace6, 0x2e2ea5ac, + 0x6e32a630, 0x2e6da58b, 0x6e6fa5cd, 0x2eb9a717, + 0x6ea3a441, 0x0e60b7fe, 0x4e75b693, 0x0ea7b4c5, + 0x4eb3b651, 0x0e242462, 0x4e322630, 0x0e7826f6, + 0x4e6f25cd, 0x0eac256a, 0x4eb726d5, 0x0ebff7dd, + 0x4ebdf79b, 0x4eeef5ac, 0x0edd379b, 0x4ec53483, + 0x2ea3ec41, 0x6ea1ec1f, 0x6efaef38, 0x2ed52e93, + 0x6ed32e51, 0x0f9011ee, 0x4fa98907, 0x4fcc116a, + 0x0fa1500f, 0x4fa38841, 0x4fcf59cd, 0x2fa790c5, + 0x4f8b8949, 0x6fcb9149, 0x0f4e81ac, 0x4f6d898b, + 0x0f8b8149, 0x4fa48062, 0x0e3e37bc, 0x4e2037fe, + 0x0e7f37dd, 0x4e723630, 0x0ebd379b, 0x4ea834e6, + 0x4eeb3549, 0x0e3f3fdd, 0x4e343e72, 0x0e693d07, + 0x4e663ca4, 0x0ea93d07, 0x4eb13e0f, 0x4eeb3d49, + 0x2e398f17, 0x6e2a8d28, 0x2e648c62, 0x6e7e8fbc, + 0x2eb78ed5, 0x6ea18c1f, 0x6ee78cc5, 0x2e3d379b, + 0x6e223420, 0x2e733651, 0x6e71360f, 0x2ea634a4, + 0x6ebc377a, 0x6eea3528, 0x2e3e3fbc, 0x6e383ef6, + 0x2e7d3f9b, 0x6e7d3f9b, 0x2ebb3f59, 0x6eb93f17, + 0x6ee23c20, 0x0e26e4a4, 0x4e28e4e6, 0x4e74e672, + 0x2ea2e420, 0x6ea6e4a4, 0x6ef1e60f, 0x2e23e441, + 0x6e2ce56a, 0x6e69e507, 0x65d22542, 0x65d026fa, + 0x65d03d05, 0x65912e23, 0x65913bbf, 0x65932fab, + 0x25d2862e, 0x258b0957, 0x2501158b, 0x25823022, + 0x254121d6, 0x259686b1, 0x24719e63, 0x24231cd8, + 0x24adf4d2, 0x24747a86, 0xba5fd3e3, 0x3a5f03e5, + 0xfa411be4, 0x7a42cbe2, 0x93df03ff, 0xc820ffff, + 0x8822fc7f, 0xc8247cbf, 0x88267fff, 0x4e010fe0, + 0x5e040420, 0x4e081fe1, 0x4e0c1fe1, 0x4e0a1fe1, + 0x4e071fe1, 0x4e042c20, 0x4e062c20, 0x4e052c20, + 0x4e083c20, 0x0e0c3c20, 0x0e0a3c20, 0x0e073c20, + 0x9eae0020, 0x0f03f409, 0x6f03f40e, 0x4cc0ac3f, + 0x0ea1b820, 0x0ef9b820, 0x4ef9b820, 0x4e21c862, + 0x0e79c862, 0x4e79c862, 0x4e61b8a4, 0x0e79b8a4, + 0x4e79b8a4, 0x05a08020, 0x05104fe0, 0x05505001, + 0x05906fe2, 0x05d03005, 0x05101fea, 0x05901feb, + 0x0590cc0b, 0x0590de0b, 0x04b0e3e0, 0x0470e7e1, + 0x042f9c20, 0x043f9c35, 0x047f9c20, 0x04ff9c20, + 0x04299420, 0x04319160, 0x0461943e, 0x04a19020, + 0x04038100, 0x040381a0, 0x040387e1, 0x04438be2, + 0x04c38fe3, 0x040181e0, 0x04018100, 0x04018621, + 0x04418b22, 0x04418822, 0x04818c23, 0x040081e0, + 0x04008120, 0x04008761, 0x04008621, 0x04408822, + 0x04808c23, 0x042053ff, 0x047f5401, 0x25208028, + 0x2538cfe0, 0x2578d001, 0x25b8efe2, 0x25f8f007, + 0x2538dfea, 0x25b8dfeb, 0xa400a3e0, 0xa420a7e0, + 0xa4484be0, 0xa467afe0, 0xa4a8a7ea, 0xa547a814, + 0xa4084ffe, 0xa55c53e0, 0xa5e1540b, 0xe400fbf6, + 0xe408ffff, 0xe420e7e0, 0xe4484be0, 0xe460efe0, + 0xe547e400, 0xe4014be0, 0xe4a84fe0, 0xe5f15000, + 0x858043e0, 0x85a043ff, 0xe59f5d08, 0x0420e3e9, + 0x0460e3ea, 0x04a0e3eb, 0x04e0e3ec, 0x25104042, + 0x25104871, 0x25904861, 0x25904c92, 0x05344020, + 0x05744041, 0x05b44062, 0x05f44083, 0x252c8840, + 0x253c1420, 0x25681572, 0x25a21ce3, 0x25ea1e34, + 0x253c0421, 0x25680572, 0x25a20ce3, 0x25ea0e34, + 0x0522c020, 0x05e6c0a4, 0x2401a001, 0x2443a051, + 0x24858881, 0x24c78cd1, 0x24850891, 0x24c70cc1, + 0x250f9001, 0x25508051, 0x25802491, 0x25df28c1, + 0x25850c81, 0x251e10d1, 0x65816001, 0x65c36051, + 0x65854891, 0x65c74cc1, 0x05733820, 0x05b238a4, + 0x05f138e6, 0x0570396a, 0x65d0a001, 0x65d6a443, + 0x65d4a826, 0x6594ac26, 0x6554ac26, 0x6556ac26, + 0x6552ac26, 0x65cbac85, 0x65caac01, 0x6589ac85, + 0x6588ac01, 0x65c9ac85, 0x65c8ac01, 0x65dea833, + 0x659ca509, 0x65d8a801, 0x65dcac01, 0x655cb241, + 0x0520a1e0, 0x0521a601, 0x052281e0, 0x05238601, + 0x04a14026, 0x042244a6, 0x046344a6, 0x04a444a6, + 0x04e544a7, 0x0568aca7, 0x05b23230, 0x05302a30, + 0x05702a30, 0x05b02a30, 0x05f02a30, 0x853040af, + 0xc5b040af, 0xe57080af, 0xe5b080af, 0x25034440, + 0x254054c4, 0x25034640, 0x25415a05, 0x25834440, + 0x25c54489, 0x250b5d3a, 0x2550dc20, 0x2518e3e1, + 0x2518e021, 0x2518e0a1, 0x2518e121, 0x2518e1a1, + 0x2558e3e2, 0x2558e042, 0x2558e0c2, 0x2558e142, + 0x2598e3e3, 0x2598e063, 0x2598e0e3, 0x2598e163, + 0x25d8e3e4, 0x25d8e084, 0x25d8e104, 0x25d8e184, + 0x2518e407, 0x05214800, 0x05614800, 0x05a14800, + 0x05e14800, 0x05214c00, 0x05614c00, 0x05a14c00, + 0x05e14c00, 0x05304001, 0x05314001, 0x05a18610, + 0x05e18610, 0x0420bc31, 0x05271e11, 0x6545e891, + 0x6585e891, 0x65c5e891, 0x6545c891, 0x6585c891, + 0x65c5c891, 0x052c8020, 0x056c8020, 0x05ac8020, + 0x05ec8020, 0x45b0c210, 0x45f1c231, 0x45527a30, + 0x45957e93, 0x45d872f6, 0x455b7759, 0x1e601000, + 0x1e603000, 0x1e621000, 0x1e623000, 0x1e641000, + 0x1e643000, 0x1e661000, 0x1e663000, 0x1e681000, + 0x1e683000, 0x1e6a1000, 0x1e6a3000, 0x1e6c1000, + 0x1e6c3000, 0x1e6e1000, 0x1e6e3000, 0x1e701000, + 0x1e703000, 0x1e721000, 0x1e723000, 0x1e741000, + 0x1e743000, 0x1e761000, 0x1e763000, 0x1e781000, + 0x1e783000, 0x1e7a1000, 0x1e7a3000, 0x1e7c1000, + 0x1e7c3000, 0x1e7e1000, 0x1e7e3000, 0xf8338160, + 0xf8380286, 0xf83f120e, 0xf82620e0, 0xf82f3353, + 0xf82952ea, 0xf8354396, 0xf82271e3, 0xf83360f4, + 0xf8a480fd, 0xf8a00209, 0xf8b41097, 0xf8b022ea, + 0xf8ab30d9, 0xf8bf51b0, 0xf8b7402c, 0xf8ae72a9, + 0xf8b061fa, 0xf8e481e4, 0xf8e803c6, 0xf8e4123d, + 0xf8fd213a, 0xf8ef3162, 0xf8fd50e3, 0xf8e142bb, + 0xf8f0710e, 0xf8f06336, 0xf86582b4, 0xf8700217, + 0xf87e1294, 0xf8602264, 0xf8783284, 0xf8645358, + 0xf8734102, 0xf868730e, 0xf87062df, 0xb824803f, + 0xb82a0194, 0xb82010e9, 0xb8382090, 0xb83b3146, + 0xb83b51b8, 0xb83042df, 0xb83673f4, 0xb83d61c9, + 0xb8b48287, 0xb8bc0169, 0xb8ae128c, 0xb8a12138, + 0xb8b3326d, 0xb8b050b0, 0xb8a04183, 0xb8a871ef, + 0xb8b061e4, 0xb8fe8005, 0xb8ea0376, 0xb8e31120, + 0xb8f3215d, 0xb8f83284, 0xb8e753b8, 0xb8ee4175, + 0xb8fb71ed, 0xb8ff61d1, 0xb863821e, 0xb87600f4, + 0xb8741023, 0xb87a2133, 0xb87032b1, 0xb8605044, + 0xb87840ce, 0xb86b71d5, 0xb871619e, 0xce372463, + 0xce1c0f03, 0xce678ef3, 0xce8e2aba, 0xce658348, + 0xce718656, 0xcec08060, 0xce6c8a89, 0x2560cec8, + 0x25a1cbd3, 0x0583762d, 0x05403cb3, 0x050039fb, + 0x2560c528, 0x25e1ca5c, 0x058015c0, 0x05400ed5, + 0x05003eda, 0x25a0c113, 0x2561de8d, 0x0580060e, + 0x0540319f, 0x05006c5e, 0x2560d7c0, 0x2521d3b7, + 0x0582b21a, 0x0540e096, 0x0500266b, 0x25e0c918, + 0x25a1d41f, 0x05802d54, 0x0543762d, 0x05022ddf, + 0x2560cd6f, 0x25a1c57d, 0x05806c41, 0x05401467, + 0x05037904, 0x04a103c3, 0x04ff0685, 0x658901ad, + 0x65cf083e, 0x659a0463, 0x04e11139, 0x04a119ca, + 0x04bd14fa, 0x047c1cd1, 0x0456bd61, 0x04c00021, + 0x041a0c5b, 0x0410933e, 0x04db1862, 0x0499ac7d, + 0x049ab38e, 0x04990b64, 0x04d39022, 0x04d197e7, + 0x04900ad0, 0x049406dd, 0x0495196c, 0x0417a80b, + 0x041eb697, 0x04180de3, 0x05279b7e, 0x05e49955, + 0x04481883, 0x040a02a6, 0x04c91bd9, 0x044b103f, + 0x04411dac, 0x04dcbc39, 0x65809e97, 0x65cd87f5, + 0x65c6951b, 0x658794ba, 0x65c291b2, 0x04dda815, + 0x65c2bcea, 0x65c0be86, 0x6581ae3c, 0x658dab53, + 0x65818178, 0x65f496fc, 0x65b817b7, 0x65ad26fb, + 0x65faafe4, 0x65fdc454, 0x65a3fee0, 0x65ed4b85, + 0x65aa6d0d, 0x049d5009, 0x04986ef0, 0x042231be, + 0x04af3016, 0x046f317e, 0x04ef32d7, 0x056b6812, + 0x05796c62, 0x65889d44, 0x45d9b096, 0x45d7b6cf, + 0x042b3e18, 0x043c3871, 0x441887b0, 0x441a8e40, + 0x44199254, 0x445b85cb, 0x041a3e6a, 0x04d83d75, + 0x04192d95, 0x048829ed, 0x04ca273c, 0x04092454, + 0x044b2b2a, 0x65c73ec5, 0x6586224f, 0x6598214a, + 0x0441346b, 0x0e3a1338, 0x4e2b1149, 0x0e7d139b, + 0x4e7d139b, 0x0ea810e6, 0x4eb612b4, 0x2e3612b4, + 0x6e2710c5, 0x2e731251, 0x6e71120f, 0x2ea91107, + 0x6eb812f6, }; // END Generated code -- do not edit diff --git a/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp b/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp index f3fb298ad346..0cb663e1ade2 100644 --- a/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp @@ -89,8 +89,8 @@ class G1CardSetTest : public ::testing::Test { return (seed % i); } - static void cardset_basic_test(); - static void cardset_mt_test(); + static void card_set_basic_test(); + static void card_set_mt_test(); static void add_cards(G1CardSet* card_set, uint cards_per_region, uint* cards, uint num_cards, G1AddCardResult* results); static void contains_cards(G1CardSet* card_set, uint cards_per_region, uint* cards, uint num_cards); @@ -215,7 +215,7 @@ void G1CardSetTest::check_iteration(G1CardSet* card_set, const size_t expected, } } -void G1CardSetTest::cardset_basic_test() { +void G1CardSetTest::card_set_basic_test() { const uint CardsPerRegion = 2048; const double FullCardSetThreshold = 0.8; @@ -435,7 +435,7 @@ class G1CardSetMtTestTask : public WorkerTask { size_t found() const { return _found.load_relaxed(); } }; -void G1CardSetTest::cardset_mt_test() { +void G1CardSetTest::card_set_mt_test() { const uint CardsPerRegion = 16384; const double FullCardSetThreshold = 1.0; const uint BitmapCoarsenThreshold = 1.0; @@ -456,7 +456,7 @@ void G1CardSetTest::cardset_mt_test() { G1CardSetMtTestTask cl(&card_set); { - GCTraceTime(Error, gc) x("Cardset test"); + GCTraceTime(Error, gc) x("G1CardSet test"); _workers->run_task(&cl, num_workers); } @@ -492,10 +492,10 @@ void G1CardSetTest::cardset_mt_test() { ASSERT_TRUE(count_cards._num_cards <= cl.added()); } -TEST_VM(G1CardSetTest, basic_cardset_test) { - G1CardSetTest::cardset_basic_test(); +TEST_VM(G1CardSetTest, basic_card_set_test) { + G1CardSetTest::card_set_basic_test(); } -TEST_VM(G1CardSetTest, mt_cardset_test) { - G1CardSetTest::cardset_mt_test(); +TEST_VM(G1CardSetTest, mt_card_set_test) { + G1CardSetTest::card_set_mt_test(); } diff --git a/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp b/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp index 2236b4e83aaf..6289679617ca 100644 --- a/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,9 +39,9 @@ class G1CardSetContainersTest : public ::testing::Test { return G1CardSetInlinePtr::max_cards_in_inline_ptr(bits_per_card); } - static void cardset_inlineptr_test(uint bits_per_card); - static void cardset_array_test(uint cards_per_array); - static void cardset_bitmap_test(uint threshold, uint size_in_bits); + static void card_set_inlineptr_test(uint bits_per_card); + static void card_set_array_test(uint cards_per_array); + static void card_set_bitmap_test(uint threshold, uint size_in_bits); }; class G1FindCardsInRange : public StackObj { @@ -78,7 +78,7 @@ class G1FindCardsInRange : public StackObj { } }; -void G1CardSetContainersTest::cardset_inlineptr_test(uint bits_per_card) { +void G1CardSetContainersTest::card_set_inlineptr_test(uint bits_per_card) { const uint CardsPerSet = cards_per_inlineptr_set(bits_per_card); G1AddCardResult res; @@ -138,9 +138,9 @@ void G1CardSetContainersTest::cardset_inlineptr_test(uint bits_per_card) { } } -void G1CardSetContainersTest::cardset_array_test(uint cards_per_array) { - uint8_t* cardset_data = NEW_C_HEAP_ARRAY(uint8_t, G1CardSetArray::size_in_bytes(cards_per_array), mtGC); - G1CardSetArray* cards = new (cardset_data) G1CardSetArray(1, cards_per_array); +void G1CardSetContainersTest::card_set_array_test(uint cards_per_array) { + uint8_t* card_set_data = NEW_C_HEAP_ARRAY(uint8_t, G1CardSetArray::size_in_bytes(cards_per_array), mtGC); + G1CardSetArray* cards = new (card_set_data) G1CardSetArray(1, cards_per_array); ASSERT_TRUE(cards->contains(1)); // Added during initialization ASSERT_TRUE(cards->num_entries() == 1); // Check it's the only one. @@ -185,12 +185,12 @@ void G1CardSetContainersTest::cardset_array_test(uint cards_per_array) { found.verify_all_found(); } - FREE_C_HEAP_ARRAY(cardset_data); + FREE_C_HEAP_ARRAY(card_set_data); } -void G1CardSetContainersTest::cardset_bitmap_test(uint threshold, uint size_in_bits) { - uint8_t* cardset_data = NEW_C_HEAP_ARRAY(uint8_t, G1CardSetBitMap::size_in_bytes(size_in_bits), mtGC); - G1CardSetBitMap* cards = new (cardset_data) G1CardSetBitMap(1, size_in_bits); +void G1CardSetContainersTest::card_set_bitmap_test(uint threshold, uint size_in_bits) { + uint8_t* card_set_data = NEW_C_HEAP_ARRAY(uint8_t, G1CardSetBitMap::size_in_bytes(size_in_bits), mtGC); + G1CardSetBitMap* cards = new (card_set_data) G1CardSetBitMap(1, size_in_bits); ASSERT_TRUE(cards->contains(1, size_in_bits)); // Added during initialization ASSERT_TRUE(cards->num_bits_set() == 1); // Should be the only one. @@ -232,32 +232,32 @@ void G1CardSetContainersTest::cardset_bitmap_test(uint threshold, uint size_in_b found.verify_part_found(threshold); } - FREE_C_HEAP_ARRAY(cardset_data); + FREE_C_HEAP_ARRAY(card_set_data); } -TEST_VM_F(G1CardSetContainersTest, basic_cardset_inptr_test) { +TEST_VM_F(G1CardSetContainersTest, basic_card_set_inptr_test) { uint const min = (uint)log2i(G1HeapRegionBounds::min_size()); uint const max = (uint)log2i(G1HeapRegionBounds::max_size()); for (uint i = min; i <= max; i++) { - G1CardSetContainersTest::cardset_inlineptr_test(i - CardTable::card_shift()); + G1CardSetContainersTest::card_set_inlineptr_test(i - CardTable::card_shift()); } } -TEST_VM_F(G1CardSetContainersTest, basic_cardset_array_test) { +TEST_VM_F(G1CardSetContainersTest, basic_card_set_array_test) { uint array_sizes[] = { 5, 9, 63, 77, 127 }; for (uint i = 0; i < ARRAY_SIZE(array_sizes); i++) { size_t const max_cards_in_set = ARRAY_SIZE(array_sizes); - G1CardSetContainersTest::cardset_array_test(max_cards_in_set); + G1CardSetContainersTest::card_set_array_test(max_cards_in_set); } } -TEST_VM_F(G1CardSetContainersTest, basic_cardset_bitmap_test) { +TEST_VM_F(G1CardSetContainersTest, basic_card_set_bitmap_test) { uint bit_sizes[] = { 64, 2048 }; uint threshold_sizes[] = { 17, 330 }; for (uint i = 0; i < ARRAY_SIZE(bit_sizes); i++) { - G1CardSetContainersTest::cardset_bitmap_test(threshold_sizes[i], bit_sizes[i]); + G1CardSetContainersTest::card_set_bitmap_test(threshold_sizes[i], bit_sizes[i]); } } diff --git a/test/hotspot/gtest/gc/g1/test_g1FromCardCache.cpp b/test/hotspot/gtest/gc/g1/test_g1FromCardCache.cpp index f560bacd6f6e..8861a239bd8f 100644 --- a/test/hotspot/gtest/gc/g1/test_g1FromCardCache.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1FromCardCache.cpp @@ -26,54 +26,54 @@ TEST(G1FromCardCache, hit_and_miss) { const uintptr_t from_card = 64; - const uint cset_group_a = 3; - const uint cset_group_b = 13; - const uint cset_group_high = 1024; + const uint card_set_group_a = 3; + const uint card_set_group_b = 13; + const uint card_set_group_high = 1024; G1FromCardCache cache; - EXPECT_FALSE(cache.contains_or_add(from_card, cset_group_a)); - EXPECT_TRUE(cache.contains_or_add(from_card, cset_group_a)); + EXPECT_FALSE(cache.contains_or_add(from_card, card_set_group_a)); + EXPECT_TRUE(cache.contains_or_add(from_card, card_set_group_a)); - // Retain multiple cset groups for the same from_card. - EXPECT_FALSE(cache.contains_or_add(from_card, cset_group_b)); - EXPECT_TRUE(cache.contains_or_add(from_card, cset_group_a)); - EXPECT_TRUE(cache.contains_or_add(from_card, cset_group_b)); + // Retain multiple card set groups for the same from_card. + EXPECT_FALSE(cache.contains_or_add(from_card, card_set_group_b)); + EXPECT_TRUE(cache.contains_or_add(from_card, card_set_group_a)); + EXPECT_TRUE(cache.contains_or_add(from_card, card_set_group_b)); // A group id is not an array index. - EXPECT_FALSE(cache.contains_or_add(from_card, cset_group_high)); - EXPECT_TRUE(cache.contains_or_add(from_card, cset_group_high)); + EXPECT_FALSE(cache.contains_or_add(from_card, card_set_group_high)); + EXPECT_TRUE(cache.contains_or_add(from_card, card_set_group_high)); } TEST(G1FromCardCache, from_card_transition) { const uintptr_t from_card_a = 2; const uintptr_t from_card_b = 3; - const uint cset_group_id = 17; + const uint card_set_group_id = 17; G1FromCardCache cache; - EXPECT_FALSE(cache.contains_or_add(from_card_a, cset_group_id)); - EXPECT_TRUE(cache.contains_or_add(from_card_a, cset_group_id)); + EXPECT_FALSE(cache.contains_or_add(from_card_a, card_set_group_id)); + EXPECT_TRUE(cache.contains_or_add(from_card_a, card_set_group_id)); // Discard previous from_card data. - EXPECT_FALSE(cache.contains_or_add(from_card_b, cset_group_id)); - EXPECT_TRUE(cache.contains_or_add(from_card_b, cset_group_id)); + EXPECT_FALSE(cache.contains_or_add(from_card_b, card_set_group_id)); + EXPECT_TRUE(cache.contains_or_add(from_card_b, card_set_group_id)); // Verify that it was discarded before. - EXPECT_FALSE(cache.contains_or_add(from_card_a, cset_group_id)); + EXPECT_FALSE(cache.contains_or_add(from_card_a, card_set_group_id)); } TEST(G1FromCardCache, cache_reset) { const uintptr_t from_card = 17; - const uint cset_group_id = 17; + const uint card_set_group_id = 17; G1FromCardCache cache; - EXPECT_FALSE(cache.contains_or_add(from_card, cset_group_id)); - EXPECT_TRUE(cache.contains_or_add(from_card, cset_group_id)); + EXPECT_FALSE(cache.contains_or_add(from_card, card_set_group_id)); + EXPECT_TRUE(cache.contains_or_add(from_card, card_set_group_id)); cache.reset(); - EXPECT_FALSE(cache.contains_or_add(from_card, cset_group_id)); - EXPECT_TRUE(cache.contains_or_add(from_card, cset_group_id)); + EXPECT_FALSE(cache.contains_or_add(from_card, card_set_group_id)); + EXPECT_TRUE(cache.contains_or_add(from_card, card_set_group_id)); } diff --git a/test/hotspot/gtest/gc/g1/test_g1RegionMap.cpp b/test/hotspot/gtest/gc/g1/test_g1RegionMap.cpp index 3a45182726a6..388c78074a07 100644 --- a/test/hotspot/gtest/gc/g1/test_g1RegionMap.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1RegionMap.cpp @@ -31,8 +31,8 @@ class G1CommittedRegionMapSerial : public G1CommittedRegionMap { static const uint TestRegions = 512; void verify_counts() { - verify_active_count(0, TestRegions, num_active()); - verify_inactive_count(0, TestRegions, num_inactive()); + verify_num_active_regions(0, TestRegions, num_active_regions()); + verify_num_inactive_regions(0, TestRegions, num_inactive_regions()); } protected: @@ -51,7 +51,7 @@ static void generate_random_map(G1CommittedRegionMap* map) { } } - if (map->num_active() == 0) { + if (map->num_active_regions() == 0) { // If we randomly activated 0 regions, activate the first half // to have some regions to test. map->activate(0, G1CommittedRegionMapSerial::TestRegions / 2); @@ -63,12 +63,12 @@ static void random_deactivate(G1CommittedRegionMap* map) { do { G1HeapRegionRange current = map->next_active_range(current_offset); if (mutate()) { - if (current.length() < 5) { + if (current.num_regions() < 5) { // For short ranges, deactivate whole. map->deactivate(current.start(), current.end()); } else { // For larger ranges, deactivate half. - map->deactivate(current.start(), current.end() - (current.length() / 2)); + map->deactivate(current.start(), current.end() - (current.num_regions() / 2)); } } current_offset = current.end(); @@ -94,14 +94,14 @@ static void random_activate_free(G1CommittedRegionMap* map) { uint current_offset = 0; do { G1HeapRegionRange current = map->next_committable_range(current_offset); - // Randomly either reactivate or uncommit + // Randomly activate parts of the committed map. if (mutate()) { - if (current.length() < 5) { + if (current.num_regions() < 5) { // For short ranges, deactivate whole. map->activate(current.start(), current.end()); } else { // For larger ranges, deactivate half. - map->activate(current.start(), current.end() - (current.length() / 2)); + map->activate(current.start(), current.end() - (current.num_regions() / 2)); } } @@ -124,6 +124,6 @@ TEST(G1CommittedRegionMapTest, serial) { serial_map.verify_counts(); random_activate_free(&serial_map); serial_map.verify_counts(); - ASSERT_EQ(serial_map.num_inactive(), 0u); + ASSERT_EQ(serial_map.num_inactive_regions(), 0u); } -} \ No newline at end of file +} diff --git a/test/hotspot/gtest/gc/parallel/test_mutableNUMASpace.cpp b/test/hotspot/gtest/gc/parallel/test_mutableNUMASpace.cpp new file mode 100644 index 000000000000..931d3cec8bd3 --- /dev/null +++ b/test/hotspot/gtest/gc/parallel/test_mutableNUMASpace.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "gc/parallel/mutableNUMASpace.hpp" +#include "unittest.hpp" + +TEST_VM(MutableNUMASpaceTest, reactivate) { + const size_t page_size = 4096; + GrowableArray all_lgrp_spaces(3, mtTest); + GrowableArray active_lgrp_spaces(3, mtTest); + + for (uint i = 0; i < 3; i++) { + all_lgrp_spaces.append(new MutableNUMASpace::LGRPSpace(i, page_size)); + } + + MutableNUMASpace::update_active_lgrp_spaces(&all_lgrp_spaces, &active_lgrp_spaces, + 3 * page_size, page_size); + EXPECT_EQ(all_lgrp_spaces.length(), active_lgrp_spaces.length()); + + MutableNUMASpace::update_active_lgrp_spaces(&all_lgrp_spaces, &active_lgrp_spaces, + 0, page_size); + EXPECT_EQ(1, active_lgrp_spaces.length()); + + MutableNUMASpace::update_active_lgrp_spaces(&all_lgrp_spaces, &active_lgrp_spaces, + 3 * page_size, page_size); + EXPECT_EQ(all_lgrp_spaces.length(), active_lgrp_spaces.length()); + for (int i = 0; i < all_lgrp_spaces.length(); i++) { + EXPECT_EQ(all_lgrp_spaces.at(i), active_lgrp_spaces.at(i)); + delete all_lgrp_spaces.at(i); + } +} diff --git a/test/hotspot/gtest/nmt/test_nmt_ht.cpp b/test/hotspot/gtest/nmt/test_nmt_ht.cpp new file mode 100644 index 000000000000..9a8bba7d9158 --- /dev/null +++ b/test/hotspot/gtest/nmt/test_nmt_ht.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "nmt/nmtHashTable.hpp" +#include "unittest.hpp" + + +struct KVElement { + int k; + int v; + static int hash(const KVElement& a) { + return a.k & 0xFF; + } + static bool equals(const KVElement& a, const KVElement& b) { + return a.k == b.k; + } +}; + +TEST(NMTOAHTTest, Basic) { + using BasicHT = OpenAddressedHashTable; + + BasicHT ht(&KVElement::hash, &KVElement::equals); + KVElement kv{1, 1}; + bool found = false; + ht.put_if_absent(kv, &found); + EXPECT_FALSE(found); + EXPECT_EQ(1, ht.occupied()); + kv.v = 0; + KVElement* found_kv = ht.put_if_absent(kv, &found); + EXPECT_TRUE(found); + EXPECT_EQ(1, found_kv->v); +} + +struct PointerKey { + int value; + + unsigned int hash() const { + return value; + } + + bool equals(const PointerKey& other) const { + return value == other.value; + } +}; + +struct PointerKeyElement { + PointerKey _key; + int _v; + + const PointerKey* key() const { + return &_key; + } +}; + +TEST(NMTOAHTTest, PointerKeyAccessor) { + auto hash = [](const PointerKeyElement& kv) { return kv.key()->hash(); }; + auto equals = [](const PointerKeyElement& a, const PointerKeyElement& b) { + return a.key()->equals(*b.key()); + }; + using PointerKeyHT = OpenAddressedHashTable; + + PointerKeyHT ht(hash, equals); + PointerKeyElement kv{{1}, 1}; + bool found = false; + ht.put_if_absent(kv, &found); + EXPECT_FALSE(found); + EXPECT_EQ(1, ht.occupied()); + kv._v = 0; + PointerKeyElement* found_kv = ht.put_if_absent(kv, &found); + EXPECT_TRUE(found); + EXPECT_EQ(1, found_kv->_v); +} + +TEST(NMTOAHTTest, Detach) { + auto hash = [](const PointerKeyElement& kv) { return kv.key()->hash(); }; + auto equals = [](const PointerKeyElement& a, const PointerKeyElement& b) { + return a.key()->equals(*b.key()); + }; + using PointerKeyHT = OpenAddressedHashTable; + PointerKeyHT ht(hash, equals); + bool found = false; + PointerKeyElement kv{{1}, 1}; + ht.put_if_absent(kv, &found); + PointerKeyElement kv2{{2}, 1}; + ht.put_if_absent(kv2, &found); + + // Check state of returned array + int len = 0; + PointerKeyElement* array = ht.detach(&len); + EXPECT_EQ(2, len); + // Check both elements are inserted + bool found_elts[2] = {false, false}; + for (int i = 0; i < len; i++) { + PointerKeyElement x = array[i]; + found_elts[0] = found_elts[0] || x.key()->equals(*kv.key()); + found_elts[1] = found_elts[1] || x.key()->equals(*kv2.key()); + } + EXPECT_TRUE(found_elts[0]); + EXPECT_TRUE(found_elts[1]); + + // Check state of the hashtable + EXPECT_EQ(0, ht.occupied()); + found = false; + EXPECT_NE(nullptr, ht.put_if_absent(kv, &found)); + EXPECT_FALSE(found); + EXPECT_NE(nullptr, ht.put_if_absent(kv2, &found)); + EXPECT_FALSE(found); + + FREE_C_HEAP_ARRAY(array); +} diff --git a/test/hotspot/gtest/oops/test_flatArrayOop.cpp b/test/hotspot/gtest/oops/test_flatArrayOop.cpp index eab45acebeba..508245de474e 100644 --- a/test/hotspot/gtest/oops/test_flatArrayOop.cpp +++ b/test/hotspot/gtest/oops/test_flatArrayOop.cpp @@ -38,7 +38,7 @@ static flatArrayOop fake_flat_array(int length) { return farr; } -// What FlatArrayKlass::array_layout_helper does, but w/o InlineKlass +// What FlatArrayKlass::array_layout_helper does, but w/o ValueKlass static int make_lh(int payload_size_bytes, bool null_free) { BasicType etype = T_FLAT_ELEMENT; int esize = log2i_exact(round_up_power_of_2(payload_size_bytes)); diff --git a/test/hotspot/gtest/oops/test_markWord.cpp b/test/hotspot/gtest/oops/test_markWord.cpp index 1147d8e3ecd3..ff98f3a1231f 100644 --- a/test/hotspot/gtest/oops/test_markWord.cpp +++ b/test/hotspot/gtest/oops/test_markWord.cpp @@ -131,7 +131,7 @@ static void assert_copy_set_hash(markWord mark) { static void assert_type(markWord mark) { EXPECT_FALSE(mark.is_flat_array()); - EXPECT_FALSE(mark.is_inline_type()); + EXPECT_FALSE(mark.is_value_type()); } TEST_VM(markWord, prototype) { @@ -147,18 +147,18 @@ TEST_VM(markWord, prototype) { assert_type(mark); } -static void assert_inline_type(markWord mark) { +static void assert_value_type(markWord mark) { EXPECT_FALSE(mark.is_flat_array()); - EXPECT_TRUE(mark.is_inline_type()); + EXPECT_TRUE(mark.is_value_type()); EXPECT_FALSE(mark.is_null_free_array()); } -TEST_VM(markWord, inline_type_prototype) { - markWord mark = markWord::inline_type_prototype(); +TEST_VM(markWord, value_type_prototype) { + markWord mark = markWord::value_type_prototype(); assert_lock_neutral_state(mark); - assert_test_pattern(&mark, " inline_type"); + assert_test_pattern(&mark, " value_type"); - assert_inline_type(mark); + assert_value_type(mark); EXPECT_FALSE(mark.has_hash()); EXPECT_FALSE(mark.is_marked()); @@ -168,7 +168,7 @@ TEST_VM(markWord, inline_type_prototype) { static void assert_flat_array_type(markWord mark) { EXPECT_TRUE(mark.is_flat_array()); - EXPECT_FALSE(mark.is_inline_type()); + EXPECT_FALSE(mark.is_value_type()); } TEST_VM(markWord, null_free_flat_array_prototype) { @@ -207,7 +207,7 @@ TEST_VM(markWord, nullable_flat_array_prototype) { static void assert_null_free_array_type(markWord mark) { EXPECT_FALSE(mark.is_flat_array()); - EXPECT_FALSE(mark.is_inline_type()); + EXPECT_FALSE(mark.is_value_type()); EXPECT_TRUE(mark.is_null_free_array()); } diff --git a/test/hotspot/gtest/oops/test_objArrayOop.cpp b/test/hotspot/gtest/oops/test_objArrayOop.cpp index cc5bb2326882..f530dc1d49ee 100644 --- a/test/hotspot/gtest/oops/test_objArrayOop.cpp +++ b/test/hotspot/gtest/oops/test_objArrayOop.cpp @@ -73,7 +73,7 @@ static int make_flat_array_layout_helper(int payload_size_bytes, bool null_free) TEST_VM(objArrayOop, osize_flatarray) { struct FlatArraySizeCase { int objal; // Object alignment in bytes - int payload_size; // Raw inline payload size + int payload_size; // Raw value payload size bool null_free; // Null free int result; // Expected size in heap words }; diff --git a/test/hotspot/gtest/runtime/test_classPrinter.cpp b/test/hotspot/gtest/runtime/test_classPrinter.cpp index 744858dcc339..9eb6466e714b 100644 --- a/test/hotspot/gtest/runtime/test_classPrinter.cpp +++ b/test/hotspot/gtest/runtime/test_classPrinter.cpp @@ -57,7 +57,7 @@ TEST_VM(ClassPrinter, print_classes) { const char* o3 = s3.freeze(); ASSERT_THAT(o3, HasSubstr("class: java/lang/Integer mirror:")) << "must find java/lang/Integer"; Klass::KlassKind kind = Arguments::is_valhalla_enabled() - ? Klass::InlineKlassKind + ? Klass::ValueKlassKind : Klass::InstanceKlassKind; stringStream headerExpected; headerExpected.print("InstanceKlass (kind=%d): java.lang.Integer {0x", kind); diff --git a/test/hotspot/gtest/runtime/test_objectMonitor.cpp b/test/hotspot/gtest/runtime/test_objectMonitor.cpp index 95cea800a40b..37741c514cc8 100644 --- a/test/hotspot/gtest/runtime/test_objectMonitor.cpp +++ b/test/hotspot/gtest/runtime/test_objectMonitor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,14 +30,6 @@ TEST_VM(ObjectMonitor, sanity) { if (cache_line_size != 0) { - EXPECT_EQ(in_bytes(ObjectMonitor::metadata_offset()), 0) - << "_metadata at a non 0 offset. metadata_offset = " - << in_bytes(ObjectMonitor::metadata_offset()); - - EXPECT_GE((size_t) in_bytes(ObjectMonitor::owner_offset()), cache_line_size) - << "the _metadata and _owner fields are closer " - << "than a cache line which permits false sharing."; - EXPECT_GE((size_t) in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), cache_line_size) << "the _owner and _recursions fields are closer " << "than a cache line which permits false sharing."; diff --git a/test/hotspot/jtreg/ProblemList-enable-preview.txt b/test/hotspot/jtreg/ProblemList-enable-preview.txt index b7c2a76b46fa..68b05395fc8f 100644 --- a/test/hotspot/jtreg/ProblemList-enable-preview.txt +++ b/test/hotspot/jtreg/ProblemList-enable-preview.txt @@ -38,6 +38,3 @@ # Compiler: # Runtime: -runtime/cds/appcds/aotCode/AOTCodeFlags.java#default_gc 8382398 generic-all -runtime/cds/appcds/aotCode/AOTCodeFlags.java#parallel 8382398 generic-all -runtime/cds/appcds/aotCode/AOTCodeFlags.java#Z 8382398 generic-all diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 2eca4b5cddd2..576a4fa6acd5 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -71,6 +71,8 @@ compiler/escapeAnalysis/TestBCEscapeAnalyzerOverflow.java 8387392 windows-aarch6 compiler/vectorapi/VectorStoreMaskIdentityTest.java 8388281 generic-all +compiler/vectorapi/AllBitsSetVectorMatchRuleTest.java 8391806 generic-aarch64 + ############################################################################# # :hotspot_gc @@ -115,7 +117,7 @@ containers/docker/ShareTmpDir.java 8390823 linux-all # :hotspot_serviceability # 8239062 and 8270326 only affects macosx-x64,macosx-aarch64 -serviceability/sa/sadebugd/DebugdConnectTest.java 8239062,8270326 generic-all +serviceability/sa/sadebugd/DebugdConnectTest.java 8239062,8270326 macosx-x64,macosx-aarch64 serviceability/sa/TestRevPtrsForInvokeDynamic.java 8241235 generic-all serviceability/jvmti/vthread/GetThreadStateMountedTest/GetThreadStateMountedTest.java 8318090,8318729 generic-all diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 0216f5f13550..21bf60ce6105 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -226,7 +226,7 @@ tier1_compiler_3 = \ -compiler/loopopts/Test7052494.java \ -compiler/memoryinitialization/ZeroTLABTest.java \ -compiler/runtime/Test6826736.java \ - -compiler/valhalla/inlinetypes/TestVirtualThreads.java + -compiler/valhalla/valuetypes/TestVirtualThreads.java tier1_compiler_3_no_valhalla = \ :tier1_compiler_3 \ @@ -345,11 +345,11 @@ tier1_gc_shenandoah = \ gtest/ShenandoahGtests.java tier2_gc_shenandoah = \ - compiler/valhalla/inlinetypes/TestWrongFlatArrayCopyStubWithShenandoah.java \ + compiler/valhalla/valuetypes/TestWrongFlatArrayCopyStubWithShenandoah.java \ runtime/MemberName/MemberNameLeak.java \ runtime/CompressedOops/UseCompressedOops.java \ - runtime/valhalla/inlinetypes/FlatArrayCopyingTest.java \ - runtime/valhalla/inlinetypes/InlineOops.java \ + runtime/valhalla/valuetypes/FlatArrayCopyingTest.java \ + runtime/valhalla/valuetypes/ValueOops.java \ gc/TestHumongousReferenceObject.java \ gc/TestSystemGC.java \ gc/arguments/TestDisableDefaultGC.java \ diff --git a/test/hotspot/jtreg/compiler/c1/CanonicalizeArrayLength.java b/test/hotspot/jtreg/compiler/c1/CanonicalizeArrayLength.java index fb8f09028afc..30f1aab00474 100644 --- a/test/hotspot/jtreg/compiler/c1/CanonicalizeArrayLength.java +++ b/test/hotspot/jtreg/compiler/c1/CanonicalizeArrayLength.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestFarJump.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestFarJump.java index 3fe213122bda..8173c49c58a7 100644 --- a/test/hotspot/jtreg/compiler/c2/aarch64/TestFarJump.java +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestFarJump.java @@ -75,7 +75,7 @@ static boolean containsADRP(String input) { int dump = (int)Long.parseLong(match, 16); int encoding = Integer.reverseBytes(dump); // Check the first instruction only. The raw pointer can be confused with the encoded adrp instruction: - // emit_exception_handler() = far_call() + should_not_reach_here() = ADRP + ADD + BLR + DCPS1 + raw_pointer + // emit_exception_handler() = far_call() + should_not_reach_here() = ADRP + ADD + BLR + UDF + raw_pointer return isADRP(encoding); } return false; diff --git a/test/hotspot/jtreg/compiler/c2/igvn/TestCMoveIdentityNotification.java b/test/hotspot/jtreg/compiler/c2/igvn/TestCMoveIdentityNotification.java new file mode 100644 index 000000000000..b7bad18ab333 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/igvn/TestCMoveIdentityNotification.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.c2.igvn; + +/* + * @test + * @bug 8391353 + * @summary CMoveNode::Identity folds "(x == c) ? c : x" to x by looking at the + * inputs of the Cmp behind the Bool. When an input of that Cmp changes, + * the CMove must be put back on the IGVN worklist. Use + * -XX:VerifyIterativeGVN=1110 to catch missing optimizations. + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions + * -Xcomp -XX:-TieredCompilation + * -XX:+StressIGVN -XX:StressSeed=3 + * -XX:CompileCommand=compileonly,${test.main.class}::test* + * -XX:VerifyIterativeGVN=1110 + * ${test.main.class} + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions + * -Xcomp -XX:-TieredCompilation + * -XX:+StressIGVN + * -XX:CompileCommand=compileonly,${test.main.class}::test* + * -XX:VerifyIterativeGVN=1110 + * ${test.main.class} + * @run main ${test.main.class} + */ + +public class TestCMoveIdentityNotification { + static void test() { + for (int i = 0, j = 0, k = 0; j < 9; j++) { + for (i += j - 1L; k < 3; k++) { + if (i != 0) { } + } + } + } + + public static void main(String[] args) { + test(); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/AddINodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/AddINodeIdealizationTests.java index c82f82a19b11..a9b66463b1ae 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/AddINodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/AddINodeIdealizationTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ /* * @test - * @bug 8267265 + * @bug 8267265 8389218 * @summary Test that Ideal transformations of AddINode* are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.AddINodeIdealizationTests @@ -45,7 +45,8 @@ public static void main(String[] args) { "test14", "test15", "test16", "test17", "test18", "test19", "test20", "test21", "test22", - "test23", "test24", "test25"}) + "test23", "test24", "test25", + "test26", "test27"}) public void runMethod() { int a = RunInfo.getRandom().nextInt(); int b = RunInfo.getRandom().nextInt(); @@ -90,6 +91,8 @@ public void assertResult(int a, int b, int c, int d) { Asserts.assertEQ((a - b) + 190 , test23(a, b)); Asserts.assertEQ(Math.max(a, b) + Math.min(a, b), test24(a, b)); Asserts.assertEQ(Math.min(a, b) + Math.max(a, b), test25(a, b)); + Asserts.assertEQ(Math.max((a | -2) + Integer.MIN_VALUE, 0), test26(a)); + Asserts.assertEQ(Math.min(((a & 1) | 2) + Integer.MAX_VALUE, 0), test27(a)); } @Test @@ -311,4 +314,22 @@ public int test24(int a, int b) { public int test25(int a, int b) { return Math.min(a, b) + Math.max(a, b); } + + @Test + @IR(failOn = { IRNode.MAX }) + // Checks that AddI keeps a precise range when the entire sum + // range underflows. + public int test26(int x) { + int value = (x | -2) + Integer.MIN_VALUE; + return Math.max(value, 0); + } + + @Test + @IR(failOn = { IRNode.MIN }) + // Checks that AddI keeps a precise range when the entire sum + // range overflows. + public int test27(int x) { + int value = ((x & 1) | 2) + Integer.MAX_VALUE; + return Math.min(value, 0); + } } diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java b/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java index a827d032eba4..2b64b4bb7da5 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java @@ -24,7 +24,7 @@ /** * @test -* @bug 8308363 8336406 8381617 +* @bug 8308363 8336406 8381617 8391717 * @summary Validate compiler IR for various Float16 scalar operations. * @modules jdk.incubator.vector * @requires vm.compiler2.enabled @@ -99,6 +99,7 @@ public class TestFloat16ScalarOperations { public static void main(String args[]) { new TestFramework().addFlags("--add-modules=jdk.incubator.vector").start(); + new TestFramework().addFlags("--add-modules=jdk.incubator.vector", "-XX:-UseFMA").start(); } public TestFloat16ScalarOperations() { @@ -287,9 +288,13 @@ public void testSqrt() { @Test @IR(counts = {IRNode.FMA_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, + applyIf = {"UseFMA", "true"}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) @IR(counts = {IRNode.FMA_HF, " >0 ", IRNode.REINTERPRET_S2HF, " >0 ", IRNode.REINTERPRET_HF2S, " >0 "}, + applyIf = {"UseFMA", "true"}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) + @IR(failOn = {IRNode.FMA_HF}, + applyIf = {"UseFMA", "false"}) public void testFma() { Float16 res = shortBitsToFloat16((short)0); for (int i = 0; i < count; i++) { @@ -799,9 +804,21 @@ public void checkRounding1() { @Test @IR(counts = {IRNode.ADD_HF, " >0 ", IRNode.SUB_HF, " >0 ", IRNode.MUL_HF, " >0 ", IRNode.DIV_HF, " >0 ", IRNode.SQRT_HF, " >0 ", IRNode.FMA_HF, " >0 "}, + applyIf = {"UseFMA", "true"}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) @IR(counts = {IRNode.ADD_HF, " >0 ", IRNode.SUB_HF, " >0 ", IRNode.MUL_HF, " >0 ", IRNode.DIV_HF, " >0 ", IRNode.SQRT_HF, " >0 ", IRNode.FMA_HF, " >0 "}, + applyIf = {"UseFMA", "true"}, + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) + @IR(counts = {IRNode.ADD_HF, " >0 ", IRNode.SUB_HF, " >0 ", IRNode.MUL_HF, " >0 ", + IRNode.DIV_HF, " >0 ", IRNode.SQRT_HF, " >0 "}, + failOn = {IRNode.FMA_HF}, + applyIf = {"UseFMA", "false"}, + applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + @IR(counts = {IRNode.ADD_HF, " >0 ", IRNode.SUB_HF, " >0 ", IRNode.MUL_HF, " >0 ", + IRNode.DIV_HF, " >0 ", IRNode.SQRT_HF, " >0 "}, + failOn = {IRNode.FMA_HF}, + applyIf = {"UseFMA", "false"}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) @Warmup(10000) public void testRounding2() { diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StableFlatArrayTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableFlatArrayTest.java index aa56ba3c3ab3..2cfa6fc134e2 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/stable/StableFlatArrayTest.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableFlatArrayTest.java @@ -36,7 +36,7 @@ package compiler.c2.irTests.stable; import compiler.lib.ir_framework.*; -import compiler.valhalla.inlinetypes.*; +import compiler.valhalla.valuetypes.*; import jdk.internal.value.ValueClass; import jdk.internal.vm.annotation.Stable; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/ccp/TestCmpUCCPFixpoint.java b/test/hotspot/jtreg/compiler/ccp/TestCmpUCCPFixpoint.java new file mode 100644 index 000000000000..bdde109b1672 --- /dev/null +++ b/test/hotspot/jtreg/compiler/ccp/TestCmpUCCPFixpoint.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2026, 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 8389218 + * @summary Test that PhaseCCP reaches a fixpoint for CmpU with a wrapped + * AddI range. + * @run main/othervm -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,${test.main.class}::test + * ${test.main.class} + */ + +package compiler.ccp; + +public class TestCmpUCCPFixpoint { + static int iFld; + static int limit; + + public static void main(String[] args) { + test(); + } + + static void test() { + short x = -100; + + for (int i = 0; i < limit; i++) { + x++; + } + x++; + + switch (x) { + case Short.MIN_VALUE + 1: + case Short.MAX_VALUE: + iFld = 2; + } + } +} diff --git a/test/hotspot/jtreg/compiler/igvn/TestMaskedStoreIdealization.java b/test/hotspot/jtreg/compiler/igvn/TestMaskedStoreIdealization.java index 58cab1b61519..03d62af1ad52 100644 --- a/test/hotspot/jtreg/compiler/igvn/TestMaskedStoreIdealization.java +++ b/test/hotspot/jtreg/compiler/igvn/TestMaskedStoreIdealization.java @@ -114,9 +114,24 @@ TemplateToken generate() { return scope(""); } + // Single lane vectors are not intrinsified, so there is no vector store to idealize. + // With IncrementalInlineVector on by default the Vector API fallback implementation is + // inlined, creating scalar Store nodes that the rules below catch. Earlier only a + // CallStaticJava was emitted in its place. + if (vec.length == 1) { + return scope(" // No Vector nodes are emitted for single lane vectors.\n"); + } + final PrimitiveType pty = (PrimitiveType) vec.elementType; final String ptyIR = pty.abbrev().equals("S") ? "C" : pty.abbrev(); + // Unboxing a mask loads a boolean vector of the same length, and the shortest supported + // one holds four lanes on x64 but only two on AArch64. Masked stores of two lane vectors + // are hence only intrinsified on AArch64. + final String maskedStoreCPUFeatures = vec.length >= 4 + ? "applyIfCPUFeatureOr = {\"avx512\", \"true\", \"sve\", \"true\"}" + : "applyIfCPUFeature = {\"sve\", \"true\"}"; + // Verify that the Scatter store for STORE_VECTOR_AFTER_SCATTER is not eliminated. var opVerification = Template.make(() -> { if (op != Operation.STORE_VECTOR_AFTER_SCATTER) { @@ -152,6 +167,7 @@ TemplateToken generate() { let("pty", vec.elementType.name()), let("ptyIR", ptyIR), let("idx", idx), + let("maskedStoreCPUFeatures", maskedStoreCPUFeatures), switch (op) { case STORE_MASK, STORE_SCATTER_MASK -> // For masked operations, depending on the generated mask and index map C2 does not manage to elide a branch from @@ -164,7 +180,7 @@ TemplateToken generate() { """ @IR(counts = {IRNode.START + "Store#{ptyIR}" + IRNode.MID + "(Memory: @aryptr:[a-z_]*:#{pty}\\\\[int:#{arraySize}\\\\]).*(:NotNull:exact:[a-z_:]*\\\\[\\\\d+\\\\]).*" + IRNode.END, ">=1", IRNode.START + "Store#{ptyIR}" + IRNode.MID + "(Memory: @aryptr:[a-z_]*:#{pty}\\\\[int:#{arraySize}\\\\]).*(:NotNull:exact:[a-z_:].*\\\\[\\\\d+\\\\]).*" + IRNode.END, "<=2"}, - applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}, + #{maskedStoreCPUFeatures}, phase = CompilePhase.BEFORE_MATCHING) """; case STORE_SCATTER -> diff --git a/test/hotspot/jtreg/compiler/intrinsics/TestInt128Math.java b/test/hotspot/jtreg/compiler/intrinsics/TestInt128Math.java new file mode 100644 index 000000000000..a9c27d836d2b --- /dev/null +++ b/test/hotspot/jtreg/compiler/intrinsics/TestInt128Math.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2026, 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 compiler.intrinsics; + +import compiler.lib.generators.Generator; +import compiler.lib.generators.Generators; +import compiler.lib.ir_framework.*; +import jdk.internal.math.Int128Math; +import jdk.test.lib.Asserts; + +/* + * @test + * @bug 8383724 + * @summary Test the C2 implementation of int128_t operations + * @key randomness + * @modules java.base/jdk.internal.math + * @library /test/lib / + * @run driver ${test.main.class} + */ +public class TestInt128Math { + static final Generator LONGS = Generators.G.longs(); + + public static void main(String[] args) { + var framework = new TestFramework(); + framework.setDefaultWarmup(1); + framework.addFlags("--add-exports=java.base/jdk.internal.math=ALL-UNNAMED"); + framework.start(); + } + + @Test + @IR(counts = {IRNode.ADD_I128T, "1"}, phase = CompilePhase.BEFORE_MACRO_EXPANSION) + @IR(failOn = IRNode.ADD_I128T, phase = CompilePhase.BEFORE_MATCHING) + public long testAddLo(long lo1, long hi1, long lo2, long hi2) { + return Int128Math.addLo(lo1, hi1, lo2, hi2); + } + + @Run(test = "testAddLo") + public void runAddLo() { + long lo1 = LONGS.next(); + long hi1 = LONGS.next(); + long lo2 = LONGS.next(); + long hi2 = LONGS.next(); + Asserts.assertEQ(lo1 + lo2, testAddLo(lo1, hi1, lo2, hi2)); + } + + @Test + @IR(counts = {IRNode.ADD_I128T, "1"}, phase = CompilePhase.BEFORE_MACRO_EXPANSION) + @IR(failOn = IRNode.ADD_I128T, phase = CompilePhase.BEFORE_MATCHING) + public long testAddHi(long lo1, long hi1, long lo2, long hi2) { + return Int128Math.addHi(lo1, hi1, lo2, hi2); + } + + @Run(test = "testAddHi") + public void runAddHi() { + long lo1 = LONGS.next(); + long hi1 = LONGS.next(); + long lo2 = LONGS.next(); + long hi2 = LONGS.next(); + Asserts.assertEQ(0L, testAddHi(0, 0, 0, 0)); + Asserts.assertEQ(1L, testAddHi(1, 0, -1, 0)); + Asserts.assertEQ(0L, testAddHi(1, 0, -1, -1)); + Asserts.assertEQ(hi1 + hi2, testAddHi(0, hi1, 0, hi2)); + Asserts.assertEQ(hi1 + hi2, testAddHi(Long.MAX_VALUE, hi1, Long.MAX_VALUE, hi2)); + Asserts.assertEQ(hi1 + hi2 + 1, testAddHi(Long.MIN_VALUE, hi1, Long.MIN_VALUE, hi2)); + Asserts.assertEQ(hi1 + hi2 + 1, testAddHi(-1, hi1, 1, hi2)); + Asserts.assertEQ(hi1 + hi2 + 1, testAddHi(-1, hi1, -1, hi2)); + + if (Long.compareUnsigned(lo1 + lo2, lo1) >= 0) { + Asserts.assertEQ(hi1 + hi2, testAddHi(lo1, hi1, lo2, hi2)); + } + if (Long.compareUnsigned(lo1 + lo2, lo2) >= 0) { + Asserts.assertEQ(hi1 + hi2, testAddHi(lo1, hi1, lo2, hi2)); + } + if (Long.compareUnsigned(lo1 + lo2, lo1) < 0) { + Asserts.assertEQ(hi1 + hi2 + 1, testAddHi(lo1, hi1, lo2, hi2)); + } + } + + @Test + @IR(counts = {IRNode.SUB_I128T, "1"}, phase = CompilePhase.BEFORE_MACRO_EXPANSION) + @IR(failOn = IRNode.SUB_I128T, phase = CompilePhase.BEFORE_MATCHING) + public long testSubLo(long lo1, long hi1, long lo2, long hi2) { + return Int128Math.subLo(lo1, hi1, lo2, hi2); + } + + @Run(test = "testSubLo") + public void runSubLo() { + long lo1 = LONGS.next(); + long hi1 = LONGS.next(); + long lo2 = LONGS.next(); + long hi2 = LONGS.next(); + Asserts.assertEQ(lo1 - lo2, testSubLo(lo1, hi1, lo2, hi2)); + } + + @Test + @IR(counts = {IRNode.SUB_I128T, "1"}, phase = CompilePhase.BEFORE_MACRO_EXPANSION) + @IR(failOn = IRNode.SUB_I128T, phase = CompilePhase.BEFORE_MATCHING) + public long testSubHi(long lo1, long hi1, long lo2, long hi2) { + return Int128Math.subHi(lo1, hi1, lo2, hi2); + } + + @Run(test = "testSubHi") + public void runSubHi() { + long lo1 = LONGS.next(); + long hi1 = LONGS.next(); + long lo2 = LONGS.next(); + long hi2 = LONGS.next(); + Asserts.assertEQ(0L, testSubHi(0, 0, 0, 0)); + Asserts.assertEQ(0L, testSubHi(0, 1, 1, 0)); + Asserts.assertEQ(-1L, testSubHi(-1, -1, 0, 0)); + Asserts.assertEQ(-1L, testSubHi(0, 0, -1, 0)); + Asserts.assertEQ(hi1, testSubHi(0, hi1, 0, 0)); + Asserts.assertEQ(hi1 - 1, testSubHi(0, hi1, 1, 0)); + Asserts.assertEQ(hi1 - hi2, testSubHi(0, hi1, 0, hi2)); + Asserts.assertEQ(hi1 - hi2, testSubHi(-1, hi1, -1, hi2)); + Asserts.assertEQ(hi1 - hi2, testSubHi(-1, hi1, 0, hi2)); + Asserts.assertEQ(hi1 - hi2 - 1, testSubHi(0, hi1, 1, hi2)); + Asserts.assertEQ(hi1 - hi2 - 1, testSubHi(0, hi1, -1, hi2)); + Asserts.assertEQ(hi1 - hi2 - 1, testSubHi(-2, hi1, -1, hi2)); + if (Long.compareUnsigned(lo1, lo2) >= 0) { + Asserts.assertEQ(hi1 - hi2, testSubHi(lo1, hi1, lo2, hi2)); + } else { + Asserts.assertEQ(hi1 - hi2 - 1, testSubHi(lo1, hi1, lo2, hi2)); + } + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 510c9f7ef369..60cc3d514a29 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -533,6 +533,11 @@ public static void callLeafNoFpOfMethodNodes(String irNodePlaceholder, String ca callOfNodes(irNodePlaceholder, "CallLeafNoFP", calleeRegex); } + public static final String VECTORAPI_INSERT_OP = PREFIX + "VECTORAPI_INSERT_OP" + POSTFIX; + static { + beforeMatchingNameRegex(VECTORAPI_INSERT_OP, "CallStaticJava(?=.*VectorSupport::insert instptr:)"); + } + public static final String CAST_II = PREFIX + "CAST_II" + POSTFIX; static { beforeMatchingNameRegex(CAST_II, "CastII"); @@ -982,9 +987,9 @@ public static void callLeafNoFpOfMethodNodes(String irNodePlaceholder, String ca beforeMatchingNameRegex(IF, "If\\b"); } - public static final String INLINE_TYPE = PREFIX + "INLINE_TYPE" + POSTFIX; + public static final String VALUE_TYPE = PREFIX + "VALUE_TYPE" + POSTFIX; static { - beforeMatchingNameRegex(INLINE_TYPE, "InlineType"); + beforeMatchingNameRegex(VALUE_TYPE, "ValueType"); } public static final String INTRINSIC_TRAP = PREFIX + "INTRINSIC_TRAP" + POSTFIX; @@ -3223,6 +3228,16 @@ public static void anyStoreOfNodes(String irNodePlaceholder, String fieldHolder) vectorNode(EXPAND_VD, "ExpandV", TYPE_DOUBLE); } + public static final String ADD_I128T = PREFIX + "ADD_I128T" + POSTFIX; + static { + beforeMatchingNameRegex(ADD_I128T, "AddI128T"); + } + + public static final String SUB_I128T = PREFIX + "SUB_I128T" + POSTFIX; + static { + beforeMatchingNameRegex(SUB_I128T, "SubI128T"); + } + public static final String Z_LOAD_P_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "Z_LOAD_P_WITH_BARRIER_FLAG" + POSTFIX; static { String regex = START + "zLoadP\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; @@ -3411,7 +3426,7 @@ public static void anyStoreOfNodes(String irNodePlaceholder, String fieldHolder) } /* - * Inline type nodes. + * Value type nodes. */ public static final String CALL_UNSAFE = PREFIX + "CALL_UNSAFE" + POSTFIX; @@ -3419,19 +3434,19 @@ public static void anyStoreOfNodes(String irNodePlaceholder, String fieldHolder) staticCallOfMethodNodes(CALL_UNSAFE, "# Static jdk.internal.misc.Unsafe::"); } - public static final String STORE_INLINE_FIELDS = PREFIX + "STORE_INLINE_FIELDS" + POSTFIX; + public static final String STORE_VALUE_FIELDS = PREFIX + "STORE_VALUE_FIELDS" + POSTFIX; static { - staticCallOfMethodNodes(STORE_INLINE_FIELDS, "store_inline_type_fields"); + staticCallOfMethodNodes(STORE_VALUE_FIELDS, "store_value_type_fields"); } - public static final String LOAD_UNKNOWN_INLINE = PREFIX + "LOAD_UNKNOWN_INLINE" + POSTFIX; + public static final String LOAD_UNKNOWN_VALUE = PREFIX + "LOAD_UNKNOWN_VALUE" + POSTFIX; static { - staticCallOfMethodNodes(LOAD_UNKNOWN_INLINE, "load_unknown_inline_blob \\(C2 runtime\\)"); + staticCallOfMethodNodes(LOAD_UNKNOWN_VALUE, "load_unknown_value_blob \\(C2 runtime\\)"); } - public static final String STORE_UNKNOWN_INLINE = PREFIX + "STORE_UNKNOWN_INLINE" + POSTFIX; + public static final String STORE_UNKNOWN_VALUE = PREFIX + "STORE_UNKNOWN_VALUE" + POSTFIX; static { - staticCallOfMethodNodes(STORE_UNKNOWN_INLINE, "store_unknown_inline_blob \\(C2 runtime\\)"); + staticCallOfMethodNodes(STORE_UNKNOWN_VALUE, "store_unknown_value_blob \\(C2 runtime\\)"); } public static final String INLINE_ARRAY_NULL_GUARD = PREFIX + "INLINE_ARRAY_NULL_GUARD" + POSTFIX; @@ -3449,8 +3464,8 @@ public static void anyStoreOfNodes(String irNodePlaceholder, String fieldHolder) callLeafNoFpOfMethodNodes(JLONG_ARRAYCOPY, "jlong_disjoint_arraycopy"); } - // The following nodes are specific to tests in in compiler/valhalla/inlinetypes using one of the MyValue classes. - private static final String MYVALUE_KLASS = "compiler/valhalla/inlinetypes/.*MyValue\\w*"; + // The following nodes are specific to tests in in compiler/valhalla/valuetypes using one of the MyValue classes. + private static final String MYVALUE_KLASS = "compiler/valhalla/valuetypes/.*MyValue\\w*"; public static final String ALLOC_OF_MYVALUE_KLASS = PREFIX + "ALLOC_OF_MYVALUE_KLASS" + POSTFIX; static { allocateOfNodes(ALLOC_OF_MYVALUE_KLASS, MYVALUE_KLASS); @@ -3461,7 +3476,7 @@ public static void anyStoreOfNodes(String irNodePlaceholder, String fieldHolder) allocateArrayOfNodes(ALLOC_ARRAY_OF_MYVALUE_KLASS, MYVALUE_KLASS); } - private static final String ANY_KLASS = "compiler/valhalla/inlinetypes/[\\w/]*"; + private static final String ANY_KLASS = "compiler/valhalla/valuetypes/[\\w/]*"; // TODO: Revisit with JDK-8380875 public static final String LOAD_OF_ANY_KLASS = PREFIX + "LOAD_OF_ANY_KLASS" + POSTFIX; diff --git a/test/hotspot/jtreg/compiler/locks/TestLockElimination.java b/test/hotspot/jtreg/compiler/locks/TestLockElimination.java index 2ee031ab8d97..241805de4e51 100644 --- a/test/hotspot/jtreg/compiler/locks/TestLockElimination.java +++ b/test/hotspot/jtreg/compiler/locks/TestLockElimination.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.*; import jdk.test.lib.Asserts; @@ -31,7 +31,7 @@ * @bug 8366879 * @summary Test that locks are successfully eliminated by C2. * @library /test/lib / - * @run driver compiler.valhalla.inlinetypes.TestLockElimination + * @run driver compiler.valhalla.valuetypes.TestLockElimination */ public class TestLockElimination { diff --git a/test/hotspot/jtreg/compiler/loopopts/TestArrayFillWithSubIndexMin.java b/test/hotspot/jtreg/compiler/loopopts/TestArrayFillWithSubIndexMin.java new file mode 100644 index 000000000000..ca81233f0e8f --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestArrayFillWithSubIndexMin.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary Exercise minimal int array fill with i - c index and forced fill optimization. + * @requires vm.compiler2.enabled + * + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions + * -XX:-TieredCompilation + * -XX:+OptimizeFill + * -XX:+UseCompactObjectHeaders + * -XX:CompileCommand=compileonly,${test.main.class}::test_coh + * -XX:CompileCommand=compileonly,${test.main.class}::test_nocoh + * ${test.main.class} + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions + * -XX:-TieredCompilation + * -XX:+OptimizeFill + * -XX:-UseCompactObjectHeaders + * -XX:CompileCommand=compileonly,${test.main.class}::test_coh + * -XX:CompileCommand=compileonly,${test.main.class}::test_nocoh + * ${test.main.class} + * @run main ${test.main.class} + */ + +package compiler.loopopts; + +public class TestArrayFillWithSubIndexMin { + static final int ARRAY_SIZE = 100; + static final int[] ARRAY = new int[ARRAY_SIZE]; + + public static void test_coh() { + for (int i = 3; i < ARRAY_SIZE; i++) { + ARRAY[i - 3] = 42; + } + } + + public static void test_nocoh() { + for (int i = 4; i < ARRAY_SIZE; i++) { + ARRAY[i - 4] = 42; + } + } + + public static void main(String[] args) { + test_coh(); + test_nocoh(); + } +} diff --git a/test/hotspot/jtreg/compiler/loopstripmining/TestExpensiveNodeInOuterStripMinedLoop.java b/test/hotspot/jtreg/compiler/loopstripmining/TestExpensiveNodeInOuterStripMinedLoop.java new file mode 100644 index 000000000000..6df336655dc6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopstripmining/TestExpensiveNodeInOuterStripMinedLoop.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2026, 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 8388592 + * @summary The early control of an expensive node must not be computed above + * its control input when verifying, otherwise it can end up in an + * outer strip mined loop. + * + * @run main/othervm -Xbatch -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,${test.main.class}::test + * ${test.main.class} + * @run main ${test.main.class} + */ + +/* + * The Sqrt below is an expensive node pinned right after the strip mined loop + * nest. get_early_ctrl() ignores the control input of an expensive node because + * get_early_ctrl_for_expensive() normally adjusts it, but that adjustment + * modifies the graph and is therefore skipped when verifying. The early control + * was then taken from the data inputs only and could land inside the outer strip + * mined loop, above the control input. The Sqrt itself is pinned and so is not + * checked, but its ConvI2D input inherited that block and + * verify_strip_mined_scheduling() hit ShouldNotReachHere(). + * + * Only a debug VM verifies loop optimizations, so this test can only fail there. + * The reduced shape comes from a JavaFuzzer test and needs OSR to trigger. + */ + +package compiler.loopstripmining; + +public class TestExpensiveNodeInOuterStripMinedLoop { + + short sFld; + + public static void main(String[] args) { + TestExpensiveNodeInOuterStripMinedLoop t = + new TestExpensiveNodeInOuterStripMinedLoop(); + for (int i = 0; i < 10_000; i++) { + t.test(); + } + } + + void test() { + int n = 8; + int m = 0; + int k = 2; + for (int i = 55; i > 8; --i) { + for (int j = 71; j > 8; j--) { + n = sFld; + } + do { + m = (int)(m - Math.sqrt(n)); + } while (++k < 71); + for (int j = 6; 71 > j; ++j) {} + } + } +} diff --git a/test/hotspot/jtreg/compiler/profiling/TestEmptySwitchProfile.java b/test/hotspot/jtreg/compiler/profiling/TestEmptySwitchProfile.java new file mode 100644 index 000000000000..3a3fdebd3781 --- /dev/null +++ b/test/hotspot/jtreg/compiler/profiling/TestEmptySwitchProfile.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2026, 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 8385134 + * @summary Test that C1 profiles constant table and lookup switches. + * @requires vm.compiler1.enabled & vm.compiler2.enabled + * @library /test/lib / + * @run driver compiler.profiling.TestEmptySwitchProfile + */ + +package compiler.profiling; + +import compiler.lib.ir_framework.*; +import compiler.lib.ir_framework.Compiler; +import jdk.test.lib.Asserts; + +public class TestEmptySwitchProfile { + public static void main(String[] args) { + TestFramework.run(); + } + + @ForceInline + private static int tableSwitch(int val) { + return switch (val) { + case 0 -> 42; + case 1 -> 43; + case 2 -> 44; + default -> -42; + }; + } + + @ForceCompile(CompLevel.C1_FULL_PROFILE) + @DontCompile(Compiler.C2) + private static int profileTableSwitch(int val) { + // C1 profiles non-constant case 0 and must also profile constant case 2 here. + return tableSwitch(val) + tableSwitch(2); + } + + // Test that C2 does not trap on constant case 2. + @Test + @IR(failOn = IRNode.UNSTABLE_IF_TRAP) + private static int testTableSwitch() { + return tableSwitch(2); + } + + @Run(test = "testTableSwitch") + @Warmup(10_000) + private static void runTestTableSwitch(RunInfo info) { + if (info.isWarmUp()) { + profileTableSwitch(0); + } else { + Asserts.assertEquals(testTableSwitch(), 44); + } + } + + // Same as above but with lookupswitch instead + @ForceInline + private static int lookupSwitch(int val) { + return switch (val) { + case 0 -> 42; + case 1_000 -> 43; + case 50_000 -> 44; + default -> -42; + }; + } + + @ForceCompile(CompLevel.C1_FULL_PROFILE) + @DontCompile(Compiler.C2) + private static int profileLookupSwitch(int val) { + // C1 profiles non-constant case 0 and must also profile constant case 50_000 here. + return lookupSwitch(val) + lookupSwitch(50_000); + } + + // Test that C2 does not trap on constant case 50_000. + @Test + @IR(failOn = IRNode.UNSTABLE_IF_TRAP) + private static int testLookupSwitch() { + return lookupSwitch(50_000); + } + + @Run(test = "testLookupSwitch") + @Warmup(10_000) + private static void runTestLookupSwitch(RunInfo info) { + if (info.isWarmUp()) { + profileLookupSwitch(0); + } else { + Asserts.assertEquals(testLookupSwitch(), 44); + } + } +} diff --git a/test/hotspot/jtreg/compiler/stable/TestStableArrayMembars.java b/test/hotspot/jtreg/compiler/stable/TestStableArrayMembars.java index 77d1ae9c918e..f298a4c4f09e 100644 --- a/test/hotspot/jtreg/compiler/stable/TestStableArrayMembars.java +++ b/test/hotspot/jtreg/compiler/stable/TestStableArrayMembars.java @@ -57,9 +57,9 @@ public static void main(String[] args) { "--add-exports=java.base/jdk.internal.value=ALL-UNNAMED"); if (Integer.class.isValue()) { tf.addCrossProductScenarios(Set.of("", "-XX:-UseArrayFlattening", - "-XX:-UseArrayFlattening -XX:-InlineTypePassFieldsAsArgs", - "-XX:-UseArrayFlattening -XX:-InlineTypeReturnedAsFields", - "-XX:-UseArrayFlattening -XX:-InlineTypePassFieldsAsArgs -XX:-InlineTypeReturnedAsFields")); + "-XX:-UseArrayFlattening -XX:-ValueTypePassFieldsAsArgs", + "-XX:-UseArrayFlattening -XX:-ValueTypeReturnedAsFields", + "-XX:-UseArrayFlattening -XX:-ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields")); } tf.start(); } diff --git a/test/hotspot/jtreg/compiler/stringopts/TestLongStringConcat.java b/test/hotspot/jtreg/compiler/stringopts/TestLongStringConcat.java index a1cb9f774d14..b879a61e10c0 100644 --- a/test/hotspot/jtreg/compiler/stringopts/TestLongStringConcat.java +++ b/test/hotspot/jtreg/compiler/stringopts/TestLongStringConcat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,15 @@ * @run main/othervm -Xbatch compiler.stringopts.TestLongStringConcat */ +/* + * @test + * @bug 8391643 + * @summary We missed ResourceMark in TypeInterfaces::intersection_with and + * TypeInterfaces::union_with. + * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+StressVerifyMeetJoin + * ${test.main.class} + */ + package compiler.stringopts; public class TestLongStringConcat { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/BlackholeTest.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/BlackholeTest.java similarity index 90% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/BlackholeTest.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/BlackholeTest.java index bb1e6d75dbaf..9bcf51fadbdb 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/BlackholeTest.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/BlackholeTest.java @@ -22,21 +22,21 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.vm.annotation.LooselyConsistentValue; import jdk.internal.vm.annotation.NullRestricted; /* * @test BlackholeTest - * @summary Check that blackholes work with inline types + * @summary Check that blackholes work with value types * @enablePreview * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @run main/othervm * -Xbatch -XX:+UnlockExperimentalVMOptions - * -XX:CompileCommand=blackhole,compiler/valhalla/inlinetypes/BlackholeTest.blackhole - * compiler.valhalla.inlinetypes.BlackholeTest + * -XX:CompileCommand=blackhole,compiler/valhalla/valuetypes/BlackholeTest.blackhole + * compiler.valhalla.valuetypes.BlackholeTest */ public class BlackholeTest { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/CompareAndSetFlatArrayField.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/CompareAndSetFlatArrayField.java similarity index 99% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/CompareAndSetFlatArrayField.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/CompareAndSetFlatArrayField.java index 48ffe1626386..a2011163e299 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/CompareAndSetFlatArrayField.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/CompareAndSetFlatArrayField.java @@ -32,7 +32,7 @@ * @run main/othervm -XX:-BackgroundCompilation ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.lang.reflect.Field; import jdk.internal.misc.Unsafe; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/CorrectlyRestoreRfp.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/CorrectlyRestoreRfp.java similarity index 99% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/CorrectlyRestoreRfp.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/CorrectlyRestoreRfp.java index 40bf3b316ea4..704827d55653 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/CorrectlyRestoreRfp.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/CorrectlyRestoreRfp.java @@ -39,7 +39,7 @@ * ${test.main.class} **/ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.whitebox.WhiteBox; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/GetfieldChains.jcod b/test/hotspot/jtreg/compiler/valhalla/valuetypes/GetfieldChains.jcod similarity index 91% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/GetfieldChains.jcod rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/GetfieldChains.jcod index 0320f2829be3..00451120672d 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/GetfieldChains.jcod +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/GetfieldChains.jcod @@ -25,7 +25,7 @@ // java org.openjdk.asmtools.Main jdec NamedRectangleN.class NamedRectangleP.class PointN.class RectangleN.class RectangleP.class /* -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.vm.annotation.LooselyConsistentValue; import jdk.internal.vm.annotation.NullRestricted; @@ -75,14 +75,14 @@ class NamedRectangleP { */ -class compiler/valhalla/inlinetypes/NamedRectangleN { +class compiler/valhalla/valuetypes/NamedRectangleN { 0xCAFEBABE; 65535; // minor version 72; // version [] { // Constant Pool ; // first element is empty class #2; // #1 - Utf8 "compiler/valhalla/inlinetypes/RectangleN"; // #2 + Utf8 "compiler/valhalla/valuetypes/RectangleN"; // #2 Method #1 #4; // #3 NameAndType #5 #6; // #4 Utf8 ""; // #5 @@ -90,9 +90,9 @@ class compiler/valhalla/inlinetypes/NamedRectangleN { Field #8 #9; // #7 class #10; // #8 NameAndType #11 #12; // #9 - Utf8 "compiler/valhalla/inlinetypes/NamedRectangleN"; // #10 + Utf8 "compiler/valhalla/valuetypes/NamedRectangleN"; // #10 Utf8 "rect"; // #11 - Utf8 "Lcompiler/valhalla/inlinetypes/RectangleN;"; // #12 + Utf8 "Lcompiler/valhalla/valuetypes/RectangleN;"; // #12 String #14; // #13 Utf8 ""; // #14 Field #8 #16; // #15 @@ -105,11 +105,11 @@ class compiler/valhalla/inlinetypes/NamedRectangleN { Field #1 #23; // #22 NameAndType #24 #25; // #23 Utf8 "p1"; // #24 - Utf8 "Lcompiler/valhalla/inlinetypes/PointN;"; // #25 + Utf8 "Lcompiler/valhalla/valuetypes/PointN;"; // #25 Field #27 #28; // #26 class #29; // #27 NameAndType #30 #31; // #28 - Utf8 "compiler/valhalla/inlinetypes/PointN"; // #29 + Utf8 "compiler/valhalla/valuetypes/PointN"; // #29 Utf8 "x"; // #30 Utf8 "I"; // #31 Utf8 "RuntimeVisibleAnnotations"; // #32 @@ -119,7 +119,7 @@ class compiler/valhalla/inlinetypes/NamedRectangleN { Utf8 "Code"; // #36 Utf8 "LineNumberTable"; // #37 Utf8 "getP1X"; // #38 - Utf8 "(Lcompiler/valhalla/inlinetypes/NamedRectangleN;)I"; // #39 + Utf8 "(Lcompiler/valhalla/valuetypes/NamedRectangleN;)I"; // #39 Utf8 "SourceFile"; // #40 Utf8 "PointN.java"; // #41 Utf8 "LoadableDescriptors"; // #42 @@ -234,16 +234,16 @@ class compiler/valhalla/inlinetypes/NamedRectangleN { 0x0001000C; } // end LoadableDescriptors } // Attributes -} // end class compiler/valhalla/inlinetypes/NamedRectangleN +} // end class compiler/valhalla/valuetypes/NamedRectangleN -class compiler/valhalla/inlinetypes/NamedRectangleP { +class compiler/valhalla/valuetypes/NamedRectangleP { 0xCAFEBABE; 65535; // minor version 72; // version [] { // Constant Pool ; // first element is empty class #2; // #1 - Utf8 "compiler/valhalla/inlinetypes/RectangleP"; // #2 + Utf8 "compiler/valhalla/valuetypes/RectangleP"; // #2 Method #1 #4; // #3 NameAndType #5 #6; // #4 Utf8 ""; // #5 @@ -251,9 +251,9 @@ class compiler/valhalla/inlinetypes/NamedRectangleP { Field #8 #9; // #7 class #10; // #8 NameAndType #11 #12; // #9 - Utf8 "compiler/valhalla/inlinetypes/NamedRectangleP"; // #10 + Utf8 "compiler/valhalla/valuetypes/NamedRectangleP"; // #10 Utf8 "rect"; // #11 - Utf8 "Lcompiler/valhalla/inlinetypes/RectangleP;"; // #12 + Utf8 "Lcompiler/valhalla/valuetypes/RectangleP;"; // #12 String #14; // #13 Utf8 ""; // #14 Field #8 #16; // #15 @@ -266,11 +266,11 @@ class compiler/valhalla/inlinetypes/NamedRectangleP { Field #1 #23; // #22 NameAndType #24 #25; // #23 Utf8 "p1"; // #24 - Utf8 "Lcompiler/valhalla/inlinetypes/PointN;"; // #25 + Utf8 "Lcompiler/valhalla/valuetypes/PointN;"; // #25 Field #27 #28; // #26 class #29; // #27 NameAndType #30 #31; // #28 - Utf8 "compiler/valhalla/inlinetypes/PointN"; // #29 + Utf8 "compiler/valhalla/valuetypes/PointN"; // #29 Utf8 "y"; // #30 Utf8 "I"; // #31 Utf8 "RuntimeVisibleAnnotations"; // #32 @@ -280,7 +280,7 @@ class compiler/valhalla/inlinetypes/NamedRectangleP { Utf8 "Code"; // #36 Utf8 "LineNumberTable"; // #37 Utf8 "getP1Y"; // #38 - Utf8 "(Lcompiler/valhalla/inlinetypes/NamedRectangleP;)I"; // #39 + Utf8 "(Lcompiler/valhalla/valuetypes/NamedRectangleP;)I"; // #39 Utf8 "SourceFile"; // #40 Utf8 "PointN.java"; // #41 Utf8 "LoadableDescriptors"; // #42 @@ -395,9 +395,9 @@ class compiler/valhalla/inlinetypes/NamedRectangleP { 0x0001000C; } // end LoadableDescriptors } // Attributes -} // end class compiler/valhalla/inlinetypes/NamedRectangleP +} // end class compiler/valhalla/valuetypes/NamedRectangleP -class compiler/valhalla/inlinetypes/PointN { +class compiler/valhalla/valuetypes/PointN { 0xCAFEBABE; 65535; // minor version 72; // version @@ -406,7 +406,7 @@ class compiler/valhalla/inlinetypes/PointN { Field #2 #3; // #1 class #4; // #2 NameAndType #5 #6; // #3 - Utf8 "compiler/valhalla/inlinetypes/PointN"; // #4 + Utf8 "compiler/valhalla/valuetypes/PointN"; // #4 Utf8 "x0"; // #5 Utf8 "I"; // #6 Field #2 #8; // #7 @@ -497,16 +497,16 @@ class compiler/valhalla/inlinetypes/PointN { } } // end RuntimeVisibleAnnotations } // Attributes -} // end class compiler/valhalla/inlinetypes/PointN +} // end class compiler/valhalla/valuetypes/PointN -class compiler/valhalla/inlinetypes/RectangleN { +class compiler/valhalla/valuetypes/RectangleN { 0xCAFEBABE; 65535; // minor version 72; // version [] { // Constant Pool ; // first element is empty class #2; // #1 - Utf8 "compiler/valhalla/inlinetypes/PointN"; // #2 + Utf8 "compiler/valhalla/valuetypes/PointN"; // #2 Method #1 #4; // #3 NameAndType #5 #6; // #4 Utf8 ""; // #5 @@ -514,9 +514,9 @@ class compiler/valhalla/inlinetypes/RectangleN { Field #8 #9; // #7 class #10; // #8 NameAndType #11 #12; // #9 - Utf8 "compiler/valhalla/inlinetypes/RectangleN"; // #10 + Utf8 "compiler/valhalla/valuetypes/RectangleN"; // #10 Utf8 "p1"; // #11 - Utf8 "Lcompiler/valhalla/inlinetypes/PointN;"; // #12 + Utf8 "Lcompiler/valhalla/valuetypes/PointN;"; // #12 Method #14 #15; // #13 class #16; // #14 NameAndType #5 #17; // #15 @@ -619,16 +619,16 @@ class compiler/valhalla/inlinetypes/RectangleN { 0x0001000C; } // end LoadableDescriptors } // Attributes -} // end class compiler/valhalla/inlinetypes/RectangleN +} // end class compiler/valhalla/valuetypes/RectangleN -class compiler/valhalla/inlinetypes/RectangleP { +class compiler/valhalla/valuetypes/RectangleP { 0xCAFEBABE; 65535; // minor version 72; // version [] { // Constant Pool ; // first element is empty class #2; // #1 - Utf8 "compiler/valhalla/inlinetypes/PointN"; // #2 + Utf8 "compiler/valhalla/valuetypes/PointN"; // #2 Method #1 #4; // #3 NameAndType #5 #6; // #4 Utf8 ""; // #5 @@ -636,9 +636,9 @@ class compiler/valhalla/inlinetypes/RectangleP { Field #8 #9; // #7 class #10; // #8 NameAndType #11 #12; // #9 - Utf8 "compiler/valhalla/inlinetypes/RectangleP"; // #10 + Utf8 "compiler/valhalla/valuetypes/RectangleP"; // #10 Utf8 "p1"; // #11 - Utf8 "Lcompiler/valhalla/inlinetypes/PointN;"; // #12 + Utf8 "Lcompiler/valhalla/valuetypes/PointN;"; // #12 Method #14 #15; // #13 class #16; // #14 NameAndType #5 #17; // #15 @@ -741,4 +741,4 @@ class compiler/valhalla/inlinetypes/RectangleP { 0x0001000C; } // end LoadableDescriptors } // Attributes -} // end class compiler/valhalla/inlinetypes/RectangleP +} // end class compiler/valhalla/valuetypes/RectangleP diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/GraphShouldBeSchedulable.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/GraphShouldBeSchedulable.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/GraphShouldBeSchedulable.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/GraphShouldBeSchedulable.java index 52ff60699fa1..71c14e5b6b05 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/GraphShouldBeSchedulable.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/GraphShouldBeSchedulable.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.value.ValueClass; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/LarvalDetectionAboveOSR.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/LarvalDetectionAboveOSR.java similarity index 96% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/LarvalDetectionAboveOSR.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/LarvalDetectionAboveOSR.java index f4b8ac66269b..0048490e8389 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/LarvalDetectionAboveOSR.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/LarvalDetectionAboveOSR.java @@ -32,10 +32,10 @@ * @library /test/jdk/java/lang/invoke/common * @enablePreview * @requires vm.debug - * @run main compiler.valhalla.inlinetypes.LarvalDetectionAboveOSR + * @run main compiler.valhalla.valuetypes.LarvalDetectionAboveOSR */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import test.java.lang.invoke.lib.InstructionHelper; @@ -108,7 +108,7 @@ static class CompilationBlock { } } - static Pattern print_compilation_regex = Pattern.compile("\\d+\\s+\\d+\\s+(%\\s+)?compiler\\.valhalla\\.inlinetypes\\.\\S*::[a-zA-Z0-9_]* (@ \\d+ )?\\(\\d+ bytes\\)"); + static Pattern print_compilation_regex = Pattern.compile("\\d+\\s+\\d+\\s+(%\\s+)?compiler\\.valhalla\\.valuetypes\\.\\S*::[a-zA-Z0-9_]* (@ \\d+ )?\\(\\d+ bytes\\)"); static Pattern allocate_elimination_regex = Pattern.compile("\\+{4} Eliminated: \\d+ Allocate"); static Pattern allocate_regex = Pattern.compile("\\s*\\d+ {2}Allocate {2}={3}.*"); @@ -183,9 +183,9 @@ public static void main(String[] args) throws Throwable { } return; } - analyzeLines(runInSeparateVM("without_new", "compiler.valhalla.inlinetypes.MyNumber::loop*")); - analyzeLines(runInSeparateVM("with_new", "compiler.valhalla.inlinetypes.MyNumber::loop*")); - analyzeLines(runInSeparateVM("bytecode", "compiler.valhalla.inlinetypes.Bytecode$Code_0::meth")); + analyzeLines(runInSeparateVM("without_new", "compiler.valhalla.valuetypes.MyNumber::loop*")); + analyzeLines(runInSeparateVM("with_new", "compiler.valhalla.valuetypes.MyNumber::loop*")); + analyzeLines(runInSeparateVM("bytecode", "compiler.valhalla.valuetypes.Bytecode$Code_0::meth")); } } @@ -262,7 +262,7 @@ static void test() throws Throwable { .aload(10) .iload(11) .i2l() - .invokevirtual(myNumberDesc, "add", MethodTypeDesc.ofDescriptor("(J)Lcompiler/valhalla/inlinetypes/MyNumber;")) + .invokevirtual(myNumberDesc, "add", MethodTypeDesc.ofDescriptor("(J)Lcompiler/valhalla/valuetypes/MyNumber;")) .astore(10) // local(11)++ diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyAbstract.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/MyAbstract.java similarity index 96% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyAbstract.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/MyAbstract.java index 1d11361113a0..1947d8aa22f9 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyAbstract.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/MyAbstract.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.vm.annotation.LooselyConsistentValue; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyInterface.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/MyInterface.java similarity index 96% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyInterface.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/MyInterface.java index d7db3af44f62..7b77084eddf6 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyInterface.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/MyInterface.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; public interface MyInterface { public long hash(); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValue1.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValue1.java similarity index 93% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValue1.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValue1.java index fa38f0c5640d..14ec960b27d0 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValue1.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValue1.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.DontCompile; import compiler.lib.ir_framework.DontInline; @@ -37,7 +37,7 @@ @ForceCompileClassInitializer public value class MyValue1 extends MyAbstract { static int s; - static final long sf = InlineTypes.rL; + static final long sf = ValueTypes.rL; int x; long y; short z; @@ -48,7 +48,7 @@ public value class MyValue1 extends MyAbstract { @NullRestricted MyValue2 v2; @NullRestricted - static final MyValue2 v3 = MyValue2.createWithFieldsInline(InlineTypes.rI, InlineTypes.rD); + static final MyValue2 v3 = MyValue2.createWithFieldsInline(ValueTypes.rI, ValueTypes.rD); MyValue2 v4; @NullRestricted MyValue2 v5; @@ -96,15 +96,15 @@ static MyValue1 createWithFieldsInline(int x, long y) { v = setO(v, new Integer(x)); int[] oa = {x}; v = setOA(v, oa); - v = setV1(v, MyValue2.createWithFieldsInline(x, y, InlineTypes.rD)); - v = setV2(v, MyValue2.createWithFieldsInline(x + 1, y + 1, InlineTypes.rD + 1)); - v = setV4(v, MyValue2.createWithFieldsInline(x + 2, y + 2, InlineTypes.rD + 2)); - v = setV5(v, MyValue2.createWithFieldsInline(x + 3, y + 3, InlineTypes.rD + 3)); + v = setV1(v, MyValue2.createWithFieldsInline(x, y, ValueTypes.rD)); + v = setV2(v, MyValue2.createWithFieldsInline(x + 1, y + 1, ValueTypes.rD + 1)); + v = setV4(v, MyValue2.createWithFieldsInline(x + 2, y + 2, ValueTypes.rD + 2)); + v = setV5(v, MyValue2.createWithFieldsInline(x + 3, y + 3, ValueTypes.rD + 3)); v = setC(v, (int)(x+y)); return v; } - // Hash only primitive and inline type fields to avoid NullPointerException + // Hash only primitive and value type fields to avoid NullPointerException @ForceInline public long hashPrimitive() { return s + sf + x + y + z + c + v1.hash() + v2.hash() + v3.hash() + v5.hash(); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValue2.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValue2.java similarity index 95% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValue2.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValue2.java index 77f825340b9e..f99fdd36177a 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValue2.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValue2.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.DontInline; import compiler.lib.ir_framework.ForceInline; @@ -104,7 +104,7 @@ public static MyValue2 createWithFieldsInline(int x, double d) { MyValue2 v = createDefaultInline(); v = setX(v, x); v = setY(v, (byte)x); - v = setV(v, MyValue2Inline.createWithFieldsInline(d, InlineTypes.rL)); + v = setV(v, MyValue2Inline.createWithFieldsInline(d, ValueTypes.rL)); return v; } @@ -113,7 +113,7 @@ public static MyValue2 createWithFieldsDontInline(int x, double d) { MyValue2 v = createDefaultInline(); v = setX(v, x); v = setY(v, (byte)x); - v = setV(v, MyValue2Inline.createWithFieldsInline(d, InlineTypes.rL)); + v = setV(v, MyValue2Inline.createWithFieldsInline(d, ValueTypes.rL)); return v; } diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValue3.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValue3.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValue3.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValue3.java index f4298f5d3cd4..bcd60c535158 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValue3.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValue3.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; import jdk.test.lib.Utils; @@ -71,7 +71,7 @@ public String toString() { } } -// Inline type definition to stress test return of an inline type in registers +// Value type definition to stress test return of a value type in registers // (uses all registers of calling convention on x86_64) @LooselyConsistentValue public value class MyValue3 extends MyAbstract { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValue4.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValue4.java similarity index 95% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValue4.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValue4.java index 526ae09dcad2..0923e478968d 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValue4.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValue4.java @@ -21,14 +21,14 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.ForceInline; import jdk.internal.vm.annotation.LooselyConsistentValue; import jdk.internal.vm.annotation.NullRestricted; -// Inline type definition with too many fields to return in registers +// Value type definition with too many fields to return in registers @LooselyConsistentValue value class MyValue4 extends MyAbstract { @NullRestricted diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValueClass1.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValueClass1.java similarity index 95% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValueClass1.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValueClass1.java index ae11021e67a1..ce2c54b02f47 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValueClass1.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValueClass1.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.DontCompile; import compiler.lib.ir_framework.DontInline; @@ -33,7 +33,7 @@ @ForceCompileClassInitializer public value class MyValueClass1 extends MyAbstract { static int s; - static long sf = InlineTypes.rL; + static long sf = ValueTypes.rL; int x; long y; short z; @@ -41,7 +41,7 @@ public value class MyValueClass1 extends MyAbstract { int[] oa; MyValueClass2 v1; MyValueClass2 v2; - static MyValueClass2 v3 = MyValueClass2.createWithFieldsInline(InlineTypes.rI, InlineTypes.rD); + static MyValueClass2 v3 = MyValueClass2.createWithFieldsInline(ValueTypes.rI, ValueTypes.rD); MyValueClass2 v4; int c; @@ -84,14 +84,14 @@ static MyValueClass1 createWithFieldsInline(int x, long y) { v = setO(v, new Integer(x)); int[] oa = {x}; v = setOA(v, oa); - v = setV1(v, MyValueClass2.createWithFieldsInline(x, y, InlineTypes.rD)); - v = setV2(v, MyValueClass2.createWithFieldsInline(x + 1, y + 1, InlineTypes.rD + 1)); - v = setV4(v, MyValueClass2.createWithFieldsInline(x + 2, y + 2, InlineTypes.rD + 2)); + v = setV1(v, MyValueClass2.createWithFieldsInline(x, y, ValueTypes.rD)); + v = setV2(v, MyValueClass2.createWithFieldsInline(x + 1, y + 1, ValueTypes.rD + 1)); + v = setV4(v, MyValueClass2.createWithFieldsInline(x + 2, y + 2, ValueTypes.rD + 2)); v = setC(v, (int)(x+y)); return v; } - // Hash only primitive and inline type fields to avoid NullPointerException + // Hash only primitive and value type fields to avoid NullPointerException @ForceInline public long hashPrimitive() { return s + sf + x + y + z + c + v1.hash() + v2.hash() + v3.hash(); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValueClass2.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValueClass2.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValueClass2.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValueClass2.java index ce03d21a9aae..443cd556064f 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValueClass2.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValueClass2.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.DontInline; import compiler.lib.ir_framework.ForceInline; @@ -96,7 +96,7 @@ public static MyValueClass2 createWithFieldsInline(int x, double d) { MyValueClass2 v = createDefaultInline(); v = setX(v, x); v = setY(v, (byte)x); - v = setV(v, MyValueClass2Inline.createWithFieldsInline(d, InlineTypes.rL)); + v = setV(v, MyValueClass2Inline.createWithFieldsInline(d, ValueTypes.rL)); return v; } @@ -105,7 +105,7 @@ public static MyValueClass2 createWithFieldsDontInline(int x, double d) { MyValueClass2 v = createDefaultInline(); v = setX(v, x); v = setY(v, (byte)x); - v = setV(v, MyValueClass2Inline.createWithFieldsInline(d, InlineTypes.rL)); + v = setV(v, MyValueClass2Inline.createWithFieldsInline(d, ValueTypes.rL)); return v; } diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValueEmpty.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValueEmpty.java similarity index 97% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValueEmpty.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValueEmpty.java index e1634160847c..da053ac97193 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/MyValueEmpty.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/MyValueEmpty.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.vm.annotation.LooselyConsistentValue; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/NonValueClass.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/NonValueClass.java similarity index 96% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/NonValueClass.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/NonValueClass.java index f1536699e794..12b2037781fd 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/NonValueClass.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/NonValueClass.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.ForceInline; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/PutFlatValueWithoutUseArrayFlattening.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/PutFlatValueWithoutUseArrayFlattening.java similarity index 91% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/PutFlatValueWithoutUseArrayFlattening.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/PutFlatValueWithoutUseArrayFlattening.java index 5b2d80841e8f..3ef0c0f60c10 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/PutFlatValueWithoutUseArrayFlattening.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/PutFlatValueWithoutUseArrayFlattening.java @@ -28,16 +28,16 @@ * @enablePreview * @library /test/lib * @modules java.base/jdk.internal.misc - * @run main/othervm -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.PutFlatValueWithoutUseArrayFlattening::test + * @run main/othervm -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.PutFlatValueWithoutUseArrayFlattening::test * -XX:-TieredCompilation -Xcomp * -XX:+UnlockDiagnosticVMOptions * -XX:-UseArrayFlattening -XX:+UseFieldFlattening -XX:+IgnoreUnrecognizedVMOptions -XX:+PreloadClasses - * compiler.valhalla.inlinetypes.PutFlatValueWithoutUseArrayFlattening + * compiler.valhalla.valuetypes.PutFlatValueWithoutUseArrayFlattening * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening -XX:+IgnoreUnrecognizedVMOptions -XX:+PreloadClasses - * compiler.valhalla.inlinetypes.PutFlatValueWithoutUseArrayFlattening + * compiler.valhalla.valuetypes.PutFlatValueWithoutUseArrayFlattening */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.lang.reflect.Field; import jdk.internal.misc.Unsafe; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/RepairStackWithBigFrame.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/RepairStackWithBigFrame.java similarity index 87% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/RepairStackWithBigFrame.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/RepairStackWithBigFrame.java index fed179caeed5..000a2cb4e04d 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/RepairStackWithBigFrame.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/RepairStackWithBigFrame.java @@ -21,9 +21,9 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; -import static compiler.valhalla.inlinetypes.InlineTypes.*; +import static compiler.valhalla.valuetypes.ValueTypes.*; /* * @test @@ -38,9 +38,9 @@ * @modules java.base/jdk.internal.vm.annotation * @run main/othervm * -Xcomp - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.RepairStackWithBigFrame::test - * compiler.valhalla.inlinetypes.RepairStackWithBigFrame - * @run main compiler.valhalla.inlinetypes.RepairStackWithBigFrame + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.RepairStackWithBigFrame::test + * compiler.valhalla.valuetypes.RepairStackWithBigFrame + * @run main compiler.valhalla.valuetypes.RepairStackWithBigFrame */ public class RepairStackWithBigFrame { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/SimpleInlineType.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/SimpleValueType.java similarity index 83% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/SimpleInlineType.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/SimpleValueType.java index 1676e27c2f02..d09aa095651c 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/SimpleInlineType.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/SimpleValueType.java @@ -21,22 +21,22 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; -value class SimpleInlineType { +value class SimpleValueType { int x; - private SimpleInlineType() { + private SimpleValueType() { x = 0; } - static SimpleInlineType create() { - return new SimpleInlineType(); + static SimpleValueType create() { + return new SimpleValueType(); } @Override public String toString() { - return "SimpleInlineType[x=" + x + "]"; + return "SimpleValueType[x=" + x + "]"; } } diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestACmpWithNullCheckTrap.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestACmpWithNullCheckTrap.java similarity index 100% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestACmpWithNullCheckTrap.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestACmpWithNullCheckTrap.java diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAbstractDelayedAccess.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAbstractDelayedAccess.java similarity index 97% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAbstractDelayedAccess.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAbstractDelayedAccess.java index 389bc597043d..42fc9911a42a 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAbstractDelayedAccess.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAbstractDelayedAccess.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.vm.annotation.NullRestricted; import jdk.test.lib.Asserts; @@ -56,7 +56,7 @@ static class Holder { } // Loading h.value starts a delayed flat field access. Resolving AbstractValue.i - // while it is pending must not cast the AbstractValue holder to ciInlineKlass. + // while it is pending must not cast the AbstractValue holder to ciValueKlass. static int test(Holder h) { return h.value.i; } diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAbstractStrictFinalField.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAbstractStrictFinalField.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAbstractStrictFinalField.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAbstractStrictFinalField.java index bc5ec7a4929a..21e25055735a 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAbstractStrictFinalField.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAbstractStrictFinalField.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAcmpCyclicInlineType.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAcmpCyclicValueType.java similarity index 96% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAcmpCyclicInlineType.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAcmpCyclicValueType.java index 165b608940a6..4d99aa0cf5aa 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAcmpCyclicInlineType.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAcmpCyclicValueType.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; /* * @test @@ -32,7 +32,7 @@ * @run main/othervm -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening ${test.main.class} * @run main/othervm -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:-UseFieldFlattening ${test.main.class} */ -public class TestAcmpCyclicInlineType { +public class TestAcmpCyclicValueType { static value class Node { Node prev; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAcmpEdgeCases.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAcmpEdgeCases.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAcmpEdgeCases.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAcmpEdgeCases.java index aebe858e4a6a..7e51e1fb919f 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAcmpEdgeCases.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAcmpEdgeCases.java @@ -27,18 +27,18 @@ * @summary Test correctness of acmp/substitutability with edge case values. * @library /test/lib * @enablePreview - * @run main compiler.valhalla.inlinetypes.TestAcmpEdgeCases + * @run main compiler.valhalla.valuetypes.TestAcmpEdgeCases * @run main/othervm -Xbatch * -XX:+UnlockDiagnosticVMOptions * -XX:+UseFieldFlattening - * compiler.valhalla.inlinetypes.TestAcmpEdgeCases + * compiler.valhalla.valuetypes.TestAcmpEdgeCases * @run main/othervm -Xbatch * -XX:+UnlockDiagnosticVMOptions * -XX:-UseFieldFlattening - * compiler.valhalla.inlinetypes.TestAcmpEdgeCases + * compiler.valhalla.valuetypes.TestAcmpEdgeCases */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; import jdk.test.lib.Utils; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAcmpFastPath.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAcmpFastPath.java similarity index 99% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAcmpFastPath.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAcmpFastPath.java index ff8c3f69263b..f2a929fb76bc 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAcmpFastPath.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAcmpFastPath.java @@ -175,7 +175,7 @@ * @run driver ${test.main.class} 13 */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.*; import jdk.test.lib.Asserts; @@ -184,14 +184,14 @@ public class TestAcmpFastPath { public static void main(String[] args) { - Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; + Scenario[] scenarios = ValueTypes.DEFAULT_SCENARIOS; int idx = Integer.parseInt(args[0]); Scenario scenario = scenarios[idx % 7]; if (idx / 7 == 1) { scenario.addFlags("-XX:-UseAcmpFastPath"); } scenario.addFlags(); - InlineTypes.getFramework() + ValueTypes.getFramework() .addScenarios(scenario) .start(); } diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAcmpFastPathPerf.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAcmpFastPathPerf.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAcmpFastPathPerf.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAcmpFastPathPerf.java index 85dc3f64f48b..3bd539baf8b6 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAcmpFastPathPerf.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAcmpFastPathPerf.java @@ -32,7 +32,7 @@ * ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; // In debug build, it's about 1s with acmp fast path, ~ 4 min without, and < 0.5s without Valhalla // In product build, it's resp. 1s, 1 min, < 0.5s. diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAcmpStressUnstableIf.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAcmpStressUnstableIf.java similarity index 86% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAcmpStressUnstableIf.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAcmpStressUnstableIf.java index c14c7dafc129..89f097eb4d5d 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAcmpStressUnstableIf.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAcmpStressUnstableIf.java @@ -27,17 +27,17 @@ * @summary Ensure the stress counter is wired correctly with StressUnstableIf for acmp. * @enablePreview * @run main/othervm -Xbatch -XX:-TieredCompilation - * -XX:CompileCommand=compileonly,compiler/valhalla/inlinetypes/TestAcmpStressUnstableIf.test + * -XX:CompileCommand=compileonly,compiler/valhalla/valuetypes/TestAcmpStressUnstableIf.test * -XX:+UnlockDiagnosticVMOptions -XX:+StressUnstableIfTraps -XX:StressSeed=3862475856 - * compiler.valhalla.inlinetypes.TestAcmpStressUnstableIf + * compiler.valhalla.valuetypes.TestAcmpStressUnstableIf * @run main/othervm -Xbatch -XX:-TieredCompilation - * -XX:CompileCommand=compileonly,compiler/valhalla/inlinetypes/TestAcmpStressUnstableIf.test + * -XX:CompileCommand=compileonly,compiler/valhalla/valuetypes/TestAcmpStressUnstableIf.test * -XX:+UnlockDiagnosticVMOptions -XX:+StressUnstableIfTraps - * compiler.valhalla.inlinetypes.TestAcmpStressUnstableIf - * @run main compiler.valhalla.inlinetypes.TestAcmpStressUnstableIf + * compiler.valhalla.valuetypes.TestAcmpStressUnstableIf + * @run main compiler.valhalla.valuetypes.TestAcmpStressUnstableIf */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; public class TestAcmpStressUnstableIf { static value class MyValue { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAcmpWithUnstableIf.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAcmpWithUnstableIf.java similarity index 95% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAcmpWithUnstableIf.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAcmpWithUnstableIf.java index d92f05ea403f..e01edc3452c2 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAcmpWithUnstableIf.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAcmpWithUnstableIf.java @@ -27,12 +27,12 @@ * @summary Test that deoptimization at unstable ifs in acmp works as expected. * @library /test/lib * @enablePreview - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+StressUnstableIfTraps compiler.valhalla.inlinetypes.TestAcmpWithUnstableIf - * @run main/othervm -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestAcmpWithUnstableIf::test* -Xbatch - * -XX:+UnlockDiagnosticVMOptions -XX:+StressUnstableIfTraps compiler.valhalla.inlinetypes.TestAcmpWithUnstableIf + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+StressUnstableIfTraps compiler.valhalla.valuetypes.TestAcmpWithUnstableIf + * @run main/othervm -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestAcmpWithUnstableIf::test* -Xbatch + * -XX:+UnlockDiagnosticVMOptions -XX:+StressUnstableIfTraps compiler.valhalla.valuetypes.TestAcmpWithUnstableIf */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; import jdk.test.lib.Utils; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAdapterSharing.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAdapterSharing.java similarity index 96% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAdapterSharing.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAdapterSharing.java index 64717c23c3b8..8ef1875d0102 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAdapterSharing.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAdapterSharing.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.vm.annotation.NullRestricted; @@ -31,7 +31,7 @@ * @requires vm.debug == true * @enablePreview * @modules java.base/jdk.internal.vm.annotation - * @run main/othervm -XX:+VerifyAdapterSharing compiler.valhalla.inlinetypes.TestAdapterSharing + * @run main/othervm -XX:+VerifyAdapterSharing compiler.valhalla.valuetypes.TestAdapterSharing */ public class TestAdapterSharing { static abstract value class MyAbstract { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAllocationMergeAndFolding.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAllocationMergeAndFolding.java similarity index 95% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAllocationMergeAndFolding.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAllocationMergeAndFolding.java index f6d8997bf591..022c2ce0a825 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestAllocationMergeAndFolding.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestAllocationMergeAndFolding.java @@ -101,7 +101,7 @@ * @enablePreview * @run driver ${test.main.class} 8 */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.*; import jdk.test.lib.Utils; @@ -112,10 +112,10 @@ public class TestAllocationMergeAndFolding { private static final Random RANDOM = Utils.getRandomInstance(); public static void main(String[] args) { - TestFramework framework = InlineTypes.getFramework(); + TestFramework framework = ValueTypes.getFramework(); int index = Integer.parseInt(args[0]); if (index < 7) { - framework.addScenarios(InlineTypes.DEFAULT_SCENARIOS[index]); + framework.addScenarios(ValueTypes.DEFAULT_SCENARIOS[index]); } else if (index == 7) { framework.addScenarios(new Scenario(7, "--enable-preview", "-XX:-UseCompressedOops")); } else { @@ -136,7 +136,7 @@ static int test(boolean flag) { dontInline(); // Not inlined and thus we have a safepoint where keep phi(o) = [V, Object]. // 'o' escapes as store to 'f'. However, 'f' does not escape and can be removed. As a result, we can also remove - // the allocations in both branches with EA after JDK-8287061. Since V has an inline type field v2, we put it + // the allocations in both branches with EA after JDK-8287061. Since V has a value type field v2, we put it // on a list to scalarize it as well. The improved allocation merge was disabled in Valhalla but is now enabled // and fixed with JDK-8315003. Foo f = new Foo(o); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayAccessDeopt.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayAccessDeopt.java similarity index 95% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayAccessDeopt.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayAccessDeopt.java index 7d8c675d008d..15245beb63ea 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayAccessDeopt.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayAccessDeopt.java @@ -29,10 +29,10 @@ * @enablePreview * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation - * @run main compiler.valhalla.inlinetypes.TestArrayAccessDeopt + * @run main compiler.valhalla.valuetypes.TestArrayAccessDeopt */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.util.Objects; @@ -97,8 +97,8 @@ static public void main(String[] args) throws Exception { if (args.length == 0) { // Run test in new VM instance String[] arg = {"--enable-preview", "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED", "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED", - "-XX:+UnlockDiagnosticVMOptions", "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestArrayAccessDeopt::test*", "-XX:-UseArrayLoadStoreProfile", - "-Xlog:deoptimization=debug", "-Xbatch", "-XX:-MonomorphicArrayCheck", "-Xmixed", "-XX:+ProfileInterpreter", "compiler.valhalla.inlinetypes.TestArrayAccessDeopt", "run"}; + "-XX:+UnlockDiagnosticVMOptions", "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestArrayAccessDeopt::test*", "-XX:-UseArrayLoadStoreProfile", + "-Xlog:deoptimization=debug", "-Xbatch", "-XX:-MonomorphicArrayCheck", "-Xmixed", "-XX:+ProfileInterpreter", "compiler.valhalla.valuetypes.TestArrayAccessDeopt", "run"}; OutputAnalyzer oa = ProcessTools.executeTestJava(arg); oa.shouldHaveExitValue(0); String output = oa.getOutput(); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayAccessProfileRace.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayAccessProfileRace.java similarity index 99% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayAccessProfileRace.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayAccessProfileRace.java index 4e94dfc79e26..3ef8d8a56cd8 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayAccessProfileRace.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayAccessProfileRace.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.lang.reflect.Method; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayCopy.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayCopy.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayCopy.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayCopy.java index b9af773c6179..ed2e922e6ea2 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayCopy.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayCopy.java @@ -29,7 +29,7 @@ * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @run main/othervm -Xbatch - * compiler.valhalla.inlinetypes.TestArrayCopy + * compiler.valhalla.valuetypes.TestArrayCopy */ /* @@ -40,7 +40,7 @@ * java.base/jdk.internal.vm.annotation * @run main/othervm -Xbatch -XX:-TieredCompilation * -XX:+UnlockExperimentalVMOptions -XX:PerMethodSpecTrapLimit=0 -XX:PerMethodTrapLimit=0 - * compiler.valhalla.inlinetypes.TestArrayCopy + * compiler.valhalla.valuetypes.TestArrayCopy */ /* @@ -51,7 +51,7 @@ * java.base/jdk.internal.vm.annotation * @run main/othervm -Xbatch -XX:-TieredCompilation * -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline - * compiler.valhalla.inlinetypes.TestArrayCopy + * compiler.valhalla.valuetypes.TestArrayCopy */ /* @@ -61,10 +61,10 @@ * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @run main/othervm -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:-UseArrayFlattening - * compiler.valhalla.inlinetypes.TestArrayCopy + * compiler.valhalla.valuetypes.TestArrayCopy */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.util.Random; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayCopyWithOops.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayCopyWithOops.java similarity index 93% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayCopyWithOops.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayCopyWithOops.java index db5f8ac06b94..b4ffb21b72d8 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayCopyWithOops.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayCopyWithOops.java @@ -29,7 +29,7 @@ * @enablePreview * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation - * @run main/timeout=240 compiler.valhalla.inlinetypes.TestArrayCopyWithOops + * @run main/timeout=240 compiler.valhalla.valuetypes.TestArrayCopyWithOops */ /* @@ -40,10 +40,10 @@ * @enablePreview * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation - * @run main/othervm/timeout=240 -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestArrayCopyWithOops::test* - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestArrayCopyWithOops::create* + * @run main/othervm/timeout=240 -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestArrayCopyWithOops::test* + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestArrayCopyWithOops::create* * -Xbatch - * compiler.valhalla.inlinetypes.TestArrayCopyWithOops + * compiler.valhalla.valuetypes.TestArrayCopyWithOops */ /* @@ -54,13 +54,13 @@ * @enablePreview * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation - * @run main/othervm/timeout=240 -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestArrayCopyWithOops::test* - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestArrayCopyWithOops::create* + * @run main/othervm/timeout=240 -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestArrayCopyWithOops::test* + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestArrayCopyWithOops::create* * -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:-UseArrayFlattening - * compiler.valhalla.inlinetypes.TestArrayCopyWithOops + * compiler.valhalla.valuetypes.TestArrayCopyWithOops */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.util.Arrays; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayMetadata.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayMetadata.java similarity index 97% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayMetadata.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayMetadata.java index 55aadf5c0384..1da678c48aa9 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayMetadata.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayMetadata.java @@ -28,7 +28,7 @@ * @enablePreview * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation - * @run main/timeout=300 compiler.valhalla.inlinetypes.TestArrayMetadata + * @run main/timeout=300 compiler.valhalla.valuetypes.TestArrayMetadata */ /* @@ -39,7 +39,7 @@ * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @run main/othervm/timeout=300 -XX:+IgnoreUnrecognizedVMOptions -XX:+StressReflectiveCode - * compiler.valhalla.inlinetypes.TestArrayMetadata + * compiler.valhalla.valuetypes.TestArrayMetadata */ /* @@ -51,7 +51,7 @@ * java.base/jdk.internal.vm.annotation * @run main/othervm/timeout=300 -XX:+IgnoreUnrecognizedVMOptions * -XX:-MonomorphicArrayCheck -XX:-OmitStackTraceInFastThrow - * compiler.valhalla.inlinetypes.TestArrayMetadata + * compiler.valhalla.valuetypes.TestArrayMetadata */ /* @@ -61,7 +61,7 @@ * @enablePreview * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation - * @run main/othervm/timeout=300 -Xcomp compiler.valhalla.inlinetypes.TestArrayMetadata + * @run main/othervm/timeout=300 -Xcomp compiler.valhalla.valuetypes.TestArrayMetadata */ /* @@ -71,7 +71,7 @@ * @enablePreview * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation - * @run main/othervm/timeout=300 -XX:MultiArrayExpandLimit=0 compiler.valhalla.inlinetypes.TestArrayMetadata + * @run main/othervm/timeout=300 -XX:MultiArrayExpandLimit=0 compiler.valhalla.valuetypes.TestArrayMetadata */ /* @@ -83,7 +83,7 @@ * java.base/jdk.internal.vm.annotation * @run main/othervm/timeout=300 -Xbatch -XX:CompileCommand=compileonly,*TestArrayMetadata::* * -XX:CompileCommand=dontinline,*TestArrayMetadata::test* - * compiler.valhalla.inlinetypes.TestArrayMetadata + * compiler.valhalla.valuetypes.TestArrayMetadata */ /* @@ -95,7 +95,7 @@ * java.base/jdk.internal.vm.annotation * @run main/othervm/timeout=300 -Xbatch -XX:CompileCommand=compileonly,*TestArrayMetadata::* * -XX:CompileCommand=dontinline,*TestArrayMetadata::* - * compiler.valhalla.inlinetypes.TestArrayMetadata + * compiler.valhalla.valuetypes.TestArrayMetadata */ /* @@ -107,10 +107,10 @@ * java.base/jdk.internal.vm.annotation * @run main/othervm/timeout=300 -Xbatch -XX:CompileCommand=compileonly,*TestArrayMetadata::main * -XX:CompileCommand=dontinline,*TestArrayMetadata::test* - * compiler.valhalla.inlinetypes.TestArrayMetadata + * compiler.valhalla.valuetypes.TestArrayMetadata */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.lang.reflect.Array; import java.util.Arrays; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayNullMarkers.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayNullMarkers.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayNullMarkers.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayNullMarkers.java index 6b7d7b077df7..a0a5c115798f 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayNullMarkers.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayNullMarkers.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.lang.reflect.Method; import jdk.internal.value.ValueClass; @@ -41,7 +41,7 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * compiler.valhalla.inlinetypes.TestArrayNullMarkers + * compiler.valhalla.valuetypes.TestArrayNullMarkers */ /* @@ -57,7 +57,7 @@ * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -Xbatch * -XX:-UseNullableAtomicValueFlattening -XX:-UseNullFreeAtomicValueFlattening -XX:-UseNullFreeNonAtomicValueFlattening - * compiler.valhalla.inlinetypes.TestArrayNullMarkers + * compiler.valhalla.valuetypes.TestArrayNullMarkers */ /* @@ -73,7 +73,7 @@ * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -Xbatch * -XX:-UseNullableAtomicValueFlattening -XX:-UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening - * compiler.valhalla.inlinetypes.TestArrayNullMarkers + * compiler.valhalla.valuetypes.TestArrayNullMarkers */ /* @@ -89,7 +89,7 @@ * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -Xbatch * -XX:-UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:-UseNullFreeNonAtomicValueFlattening - * compiler.valhalla.inlinetypes.TestArrayNullMarkers + * compiler.valhalla.valuetypes.TestArrayNullMarkers */ /* @@ -105,7 +105,7 @@ * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -Xbatch * -XX:-UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening - * compiler.valhalla.inlinetypes.TestArrayNullMarkers + * compiler.valhalla.valuetypes.TestArrayNullMarkers */ /* @@ -121,7 +121,7 @@ * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -Xbatch * -XX:+UseNullableAtomicValueFlattening -XX:-UseNullFreeAtomicValueFlattening -XX:-UseNullFreeNonAtomicValueFlattening - * compiler.valhalla.inlinetypes.TestArrayNullMarkers + * compiler.valhalla.valuetypes.TestArrayNullMarkers */ /* @@ -137,7 +137,7 @@ * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -Xbatch * -XX:+UseNullableAtomicValueFlattening -XX:-UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening - * compiler.valhalla.inlinetypes.TestArrayNullMarkers + * compiler.valhalla.valuetypes.TestArrayNullMarkers */ /* @@ -153,7 +153,7 @@ * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -Xbatch * -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:-UseNullFreeNonAtomicValueFlattening - * compiler.valhalla.inlinetypes.TestArrayNullMarkers + * compiler.valhalla.valuetypes.TestArrayNullMarkers */ /* @@ -169,7 +169,7 @@ * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -Xbatch * -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening - * compiler.valhalla.inlinetypes.TestArrayNullMarkers + * compiler.valhalla.valuetypes.TestArrayNullMarkers */ /* @@ -186,7 +186,7 @@ * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -Xbatch * -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening * -XX:CompileCommand=dontinline,*::test* -XX:CompileCommand=dontinline,*::check* - * compiler.valhalla.inlinetypes.TestArrayNullMarkers + * compiler.valhalla.valuetypes.TestArrayNullMarkers */ /* @@ -203,7 +203,7 @@ * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -Xbatch * -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening * -XX:+IgnoreUnrecognizedVMOptions -XX:-MonomorphicArrayCheck -XX:-UseArrayLoadStoreProfile - * compiler.valhalla.inlinetypes.TestArrayNullMarkers + * compiler.valhalla.valuetypes.TestArrayNullMarkers */ public class TestArrayNullMarkers { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayRematerializationWithProperties.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayRematerializationWithProperties.java similarity index 96% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayRematerializationWithProperties.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayRematerializationWithProperties.java index 3caf05699cf8..d0049bdf2352 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrayRematerializationWithProperties.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrayRematerializationWithProperties.java @@ -28,13 +28,13 @@ * @enablePreview * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation - * @run main compiler.valhalla.inlinetypes.TestArrayRematerializationWithProperties + * @run main compiler.valhalla.valuetypes.TestArrayRematerializationWithProperties * @run main/othervm -XX:-TieredCompilation -Xbatch * -XX:CompileCommand=compileonly,*TestArrayRematerializationWithProperties::test - * compiler.valhalla.inlinetypes.TestArrayRematerializationWithProperties + * compiler.valhalla.valuetypes.TestArrayRematerializationWithProperties */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.value.ValueClass; import jdk.internal.vm.annotation.LooselyConsistentValue; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrays.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrays.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrays.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrays.java index 9d3a610e3a32..a7f829410d35 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrays.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrays.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.*; import jdk.test.lib.Asserts; @@ -36,7 +36,7 @@ import java.lang.reflect.Method; import java.util.Arrays; -import static compiler.valhalla.inlinetypes.InlineTypes.*; +import static compiler.valhalla.valuetypes.ValueTypes.*; import static compiler.lib.ir_framework.IRNode.ALLOC; import static compiler.lib.ir_framework.IRNode.ALLOC_ARRAY; @@ -49,11 +49,11 @@ import static compiler.lib.ir_framework.IRNode.INTRINSIC_TRAP; import static compiler.lib.ir_framework.IRNode.JLONG_ARRAYCOPY; import static compiler.lib.ir_framework.IRNode.LOAD_OF_ANY_KLASS; -import static compiler.lib.ir_framework.IRNode.LOAD_UNKNOWN_INLINE; +import static compiler.lib.ir_framework.IRNode.LOAD_UNKNOWN_VALUE; import static compiler.lib.ir_framework.IRNode.LOOP; import static compiler.lib.ir_framework.IRNode.PREDICATE_TRAP; import static compiler.lib.ir_framework.IRNode.STORE_OF_ANY_KLASS; -import static compiler.lib.ir_framework.IRNode.STORE_UNKNOWN_INLINE; +import static compiler.lib.ir_framework.IRNode.STORE_UNKNOWN_VALUE; import static compiler.lib.ir_framework.IRNode.UNSTABLE_IF_TRAP; /* @@ -144,13 +144,13 @@ public class TestArrays { public static void main(String[] args) { - Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; + Scenario[] scenarios = ValueTypes.DEFAULT_SCENARIOS; scenarios[2].addFlags("--enable-preview", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast", "-XX:+StressArrayCopyMacroNode"); scenarios[3].addFlags("--enable-preview", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UseArrayFlattening", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast"); scenarios[4].addFlags("--enable-preview", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast"); scenarios[5].addFlags("--enable-preview", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast", "-XX:+StressArrayCopyMacroNode"); - InlineTypes.getFramework() + ValueTypes.getFramework() .addScenarios(scenarios[Integer.parseInt(args[0])]) .addHelperClasses(MyValue1.class, MyValue2.class, MyValue2Inline.class) .start(); @@ -1741,7 +1741,7 @@ public void test71_verifier() { test71(); } - // Test EA with leaf call to 'store_unknown_inline' + // Test EA with leaf call to 'store_unknown_value' @Test public void test72(Object[] o, boolean b, Object element) { Object[] arr1 = new Object[10]; @@ -1932,9 +1932,9 @@ public void test78_verifier() { // Verify that casting an array element to a non-flattenable type marks the array as not flat @Test @IR(applyIf = {"UseArrayFlattening", "true"}, - counts = {LOAD_UNKNOWN_INLINE, "= 1"}) + counts = {LOAD_UNKNOWN_VALUE, "= 1"}) @IR(applyIf = {"UseArrayFlattening", "false"}, - failOn = {ALLOC, ALLOC_ARRAY, LOAD_UNKNOWN_INLINE}) + failOn = {ALLOC, ALLOC_ARRAY, LOAD_UNKNOWN_VALUE}) public Object test79(Object[] array, int i) { NonValueClass i1 = (NonValueClass)array[0]; Object o = array[1]; @@ -1953,9 +1953,9 @@ public void test79_verifier() { // Same as test79 but with not flattenable value class @Test @IR(applyIf = {"UseArrayFlattening", "true"}, - counts = {LOAD_UNKNOWN_INLINE, "= 1"}) + counts = {LOAD_UNKNOWN_VALUE, "= 1"}) @IR(applyIf = {"UseArrayFlattening", "false"}, - failOn = {ALLOC, ALLOC_ARRAY, LOAD_UNKNOWN_INLINE}) + failOn = {ALLOC, ALLOC_ARRAY, LOAD_UNKNOWN_VALUE}) public Object test80(Object[] array, int i) { NotFlattenable vt = (NotFlattenable)array[0]; Object o = array[1]; @@ -1971,9 +1971,9 @@ public void test80_verifier() { Asserts.assertEquals(result, vt); } - // Verify that writing an object of a non-inline, non-null type to an array marks the array as not null-free and not flat + // Verify that writing an object of a non-value, non-null type to an array marks the array as not null-free and not flat @Test - @IR(failOn = {ALLOC, ALLOC_ARRAY, LOAD_UNKNOWN_INLINE, STORE_UNKNOWN_INLINE, INLINE_ARRAY_NULL_GUARD}) + @IR(failOn = {ALLOC, ALLOC_ARRAY, LOAD_UNKNOWN_VALUE, STORE_UNKNOWN_VALUE, INLINE_ARRAY_NULL_GUARD}) public Object test81(Object[] array, NonValueClass v, Object o, int i) { if (v == null) { return null; @@ -2003,10 +2003,10 @@ public void test81_verifier() { // Verify that writing an object of a non-flattenable value class to an array marks the array as not flat @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, - failOn = {ALLOC_ARRAY, LOAD_UNKNOWN_INLINE, STORE_UNKNOWN_INLINE}) - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, - failOn = {ALLOC, ALLOC_ARRAY, LOAD_UNKNOWN_INLINE, STORE_UNKNOWN_INLINE}) + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, + failOn = {ALLOC_ARRAY, LOAD_UNKNOWN_VALUE, STORE_UNKNOWN_VALUE}) + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "false"}, + failOn = {ALLOC, ALLOC_ARRAY, LOAD_UNKNOWN_VALUE, STORE_UNKNOWN_VALUE}) public Object test82(Object[] array, NotFlattenable vt, Object o, int i) { array[0] = vt; array[1] = array[0]; @@ -2034,10 +2034,10 @@ public void test82_verifier() { // Verify that casting an array element to a non-value class type type marks the array as not null-free and not flat @Test @IR(applyIf = {"UseArrayFlattening", "true"}, - counts = {LOAD_UNKNOWN_INLINE, "= 1"}, - failOn = {ALLOC_ARRAY, STORE_UNKNOWN_INLINE, INLINE_ARRAY_NULL_GUARD}) + counts = {LOAD_UNKNOWN_VALUE, "= 1"}, + failOn = {ALLOC_ARRAY, STORE_UNKNOWN_VALUE, INLINE_ARRAY_NULL_GUARD}) @IR(applyIf = {"UseArrayFlattening", "false"}, - failOn = {ALLOC, ALLOC_ARRAY, LOAD_UNKNOWN_INLINE, STORE_UNKNOWN_INLINE, INLINE_ARRAY_NULL_GUARD}) + failOn = {ALLOC, ALLOC_ARRAY, LOAD_UNKNOWN_VALUE, STORE_UNKNOWN_VALUE, INLINE_ARRAY_NULL_GUARD}) public void test83(Object[] array, Object o) { NonValueClass i = (NonValueClass)array[0]; array[1] = o; @@ -2059,10 +2059,10 @@ public void test83_verifier() { @IR(applyIf = {"UseArrayFlattening", "true"}, failOn = {ALLOC, ALLOC_ARRAY}, counts = {INLINE_ARRAY_NULL_GUARD, "= 1", // Null check on first store, no check on second store - STORE_UNKNOWN_INLINE, "= 2", - LOAD_UNKNOWN_INLINE, "= 1"}) + STORE_UNKNOWN_VALUE, "= 2", + LOAD_UNKNOWN_VALUE, "= 1"}) @IR(applyIf = {"UseArrayFlattening", "false"}, - failOn = {ALLOC, ALLOC_ARRAY, STORE_UNKNOWN_INLINE, LOAD_UNKNOWN_INLINE}, + failOn = {ALLOC, ALLOC_ARRAY, STORE_UNKNOWN_VALUE, LOAD_UNKNOWN_VALUE}, counts = {INLINE_ARRAY_NULL_GUARD, "= 1"}) // Null check on first store, no check on second store public Object test84(Object[] array, int i) { array[0] = null; @@ -2096,9 +2096,9 @@ public void test84_verifier(RunInfo info) { @IR(applyIf = {"UseArrayFlattening", "true"}, failOn = {ALLOC, ALLOC_ARRAY}, counts = {INLINE_ARRAY_NULL_GUARD, "= 2", - STORE_UNKNOWN_INLINE, "<= 3"}) + STORE_UNKNOWN_VALUE, "<= 3"}) @IR(applyIf = {"UseArrayFlattening", "false"}, - failOn = {ALLOC, ALLOC_ARRAY, STORE_UNKNOWN_INLINE, LOAD_UNKNOWN_INLINE}, + failOn = {ALLOC, ALLOC_ARRAY, STORE_UNKNOWN_VALUE, LOAD_UNKNOWN_VALUE}, counts = {INLINE_ARRAY_NULL_GUARD, "= 2"}) public void test85(Object[] array, Object o, boolean b) { if (b) { @@ -2135,11 +2135,11 @@ public void test85_verifier(RunInfo info) { // Same as test85 but with not flattenable value class array @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, - failOn = {ALLOC_ARRAY, LOAD_UNKNOWN_INLINE, STORE_UNKNOWN_INLINE}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, + failOn = {ALLOC_ARRAY, LOAD_UNKNOWN_VALUE, STORE_UNKNOWN_VALUE}, counts = {INLINE_ARRAY_NULL_GUARD, "= 2", ALLOC, "= 1"}) - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, - failOn = {ALLOC, ALLOC_ARRAY, LOAD_UNKNOWN_INLINE, STORE_UNKNOWN_INLINE}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "false"}, + failOn = {ALLOC, ALLOC_ARRAY, LOAD_UNKNOWN_VALUE, STORE_UNKNOWN_VALUE}, counts = {INLINE_ARRAY_NULL_GUARD, "= 2"}) public void test86(NotFlattenable[] array, NotFlattenable o, boolean b) { if (b) { @@ -2171,11 +2171,11 @@ public void test86_verifier(RunInfo info) { // Same as test85 but with value class array @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, - failOn = {ALLOC_ARRAY, LOAD_UNKNOWN_INLINE, STORE_UNKNOWN_INLINE}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, + failOn = {ALLOC_ARRAY, LOAD_UNKNOWN_VALUE, STORE_UNKNOWN_VALUE}, counts = {INLINE_ARRAY_NULL_GUARD, "= 2", ALLOC, "= 1"}) - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, - failOn = {ALLOC, ALLOC_ARRAY, LOAD_UNKNOWN_INLINE, STORE_UNKNOWN_INLINE}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "false"}, + failOn = {ALLOC, ALLOC_ARRAY, LOAD_UNKNOWN_VALUE, STORE_UNKNOWN_VALUE}, counts = {INLINE_ARRAY_NULL_GUARD, "= 2"}) public void test87(MyValue1[] array, MyValue1 o, boolean b) { if (b) { @@ -3326,7 +3326,7 @@ public void test133_verifier() { // Non-escaping empty value class array access @Test - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, failOn = {ALLOC_OF_MYVALUE_KLASS, ALLOC_ARRAY_OF_MYVALUE_KLASS, LOAD_OF_ANY_KLASS, STORE_OF_ANY_KLASS}) public static MyValueEmpty test134() { MyValueEmpty[] array = new MyValueEmpty[1]; @@ -3467,8 +3467,8 @@ public void test138_verifier() { // Test load from array that is only known to be not a value class array after parsing @Test - @IR(failOn = {ALLOC, ALLOC_ARRAY, LOOP, LOAD_OF_ANY_KLASS, STORE_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP, LOAD_UNKNOWN_INLINE, - STORE_UNKNOWN_INLINE, INLINE_ARRAY_NULL_GUARD}) + @IR(failOn = {ALLOC, ALLOC_ARRAY, LOOP, LOAD_OF_ANY_KLASS, STORE_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP, LOAD_UNKNOWN_VALUE, + STORE_UNKNOWN_VALUE, INLINE_ARRAY_NULL_GUARD}) public Object test139() { Object[] array = null; Object[] oarray = new NonValueClass[1]; @@ -3489,7 +3489,7 @@ public void test139_verifier() { // Test store to array that is only known to be not a value class array after parsing @Test @IR(failOn = {ALLOC_ARRAY_OF_MYVALUE_KLASS, ALLOC, LOOP, LOAD_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP, - LOAD_UNKNOWN_INLINE, STORE_UNKNOWN_INLINE, INLINE_ARRAY_NULL_GUARD}) + LOAD_UNKNOWN_VALUE, STORE_UNKNOWN_VALUE, INLINE_ARRAY_NULL_GUARD}) public Object[] test140(Object val) { Object[] array = null; Object[] oarray = new NonValueClass[1]; @@ -3514,7 +3514,7 @@ public void test140_verifier() { // Test load from array that is only known to be not a value class array after parsing // TODO 8255938 @Test - // @IR(failOn = {ALLOC_G, ALLOC_ARRAY, LOOP, LOAD_OF_ANY_KLASS, STORE_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP, LOAD_UNKNOWN_INLINE, STORE_UNKNOWN_INLINE, INLINE_ARRAY_NULL_GUARD}) + // @IR(failOn = {ALLOC_G, ALLOC_ARRAY, LOOP, LOAD_OF_ANY_KLASS, STORE_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP, LOAD_UNKNOWN_VALUE, STORE_UNKNOWN_VALUE, INLINE_ARRAY_NULL_GUARD}) public Object test141() { Object[] array = null; Object[] oarray = new NonValueClass[1]; @@ -3535,7 +3535,7 @@ public void test141_verifier() { // Test store to array that is only known to be not a value class array after parsing // TODO 8255938 @Test - // @IR(failOn = {ALLOC_ARRAY_OF_MYVALUE_KLASS, ALLOC_G, LOOP, LOAD_OF_ANY_KLASS, STORE_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP, LOAD_UNKNOWN_INLINE, STORE_UNKNOWN_INLINE, INLINE_ARRAY_NULL_GUARD}) + // @IR(failOn = {ALLOC_ARRAY_OF_MYVALUE_KLASS, ALLOC_G, LOOP, LOAD_OF_ANY_KLASS, STORE_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP, LOAD_UNKNOWN_VALUE, STORE_UNKNOWN_VALUE, INLINE_ARRAY_NULL_GUARD}) public Object[] test142(Object val) { Object[] array = null; Object[] oarray = new NonValueClass[1]; @@ -3770,7 +3770,7 @@ static value class Test151Value { } @Test - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, failOn = {ALLOC_OF_MYVALUE_KLASS,}) static Test151Value test151(int i) { return Test151Value.ARRAY[i]; @@ -3798,7 +3798,7 @@ static value class MyValue152 { // Test that EA works for null-free arrays @Test // TODO 8350865 Scalar replacement does not work well for flat arrays - //@IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + //@IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, // failOn = {ALLOC, ALLOCA}) public MyValue152 test152() { MyValue152[] array = (MyValue152[])ValueClass.newNullRestrictedNonAtomicArray(MyValue152.class, 1, new MyValue152()); @@ -3819,7 +3819,7 @@ static value class MyValue153 { // Same as test152 but triggers a slightly different asserts @Test // TODO 8350865 Scalar replacement does not work well for flat arrays - //@IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + //@IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, // failOn = {ALLOC, ALLOCA}) public MyValue153 test153() { MyValue153[] array = (MyValue153[])ValueClass.newNullRestrictedNonAtomicArray(MyValue153.class, 1, new MyValue153()); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArraysCopyOf.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArraysCopyOf.java similarity index 97% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArraysCopyOf.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArraysCopyOf.java index 134aba00aeff..ea87e7e5fc98 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArraysCopyOf.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArraysCopyOf.java @@ -99,7 +99,7 @@ */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.compile_framework.CompileFramework; import compiler.lib.generators.Generators; @@ -119,7 +119,7 @@ public class TestArraysCopyOf { private static final RestrictableGenerator RANDOM_LENGTH = Generators.G.ints().restricted(0, 32); public static void main(String[] args) { - Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; + Scenario[] scenarios = ValueTypes.DEFAULT_SCENARIOS; scenarios[2].addFlags("--enable-preview", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast", "-XX:+StressArrayCopyMacroNode"); scenarios[3].addFlags("--enable-preview", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UseArrayFlattening", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast"); scenarios[4].addFlags("--enable-preview", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast"); @@ -127,12 +127,12 @@ public static void main(String[] args) { String[] flagsForScenario = scenarios[Integer.parseInt(args[0])].getFlags().toArray(new String[0]); CompileFramework comp = new CompileFramework(); - comp.addJavaSourceCode("compiler.valhalla.inlinetypes.TestArraysCopyOfGenerated", generate(comp)); + comp.addJavaSourceCode("compiler.valhalla.valuetypes.TestArraysCopyOfGenerated", generate(comp)); comp.compile("--enable-preview", "--source", "28", "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED", "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED", "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED"); - comp.invoke("compiler.valhalla.inlinetypes.TestArraysCopyOfGenerated", "main", + comp.invoke("compiler.valhalla.valuetypes.TestArraysCopyOfGenerated", "main", new Object[]{ flagsForScenario }); } @@ -333,7 +333,7 @@ static interface I {} """)) )); - return TestFrameworkClass.render("compiler.valhalla.inlinetypes", + return TestFrameworkClass.render("compiler.valhalla.valuetypes", "TestArraysCopyOfGenerated", Set.of("jdk.test.lib.Asserts", "java.util.Arrays", diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBasicFunctionality.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestBasicFunctionality.java similarity index 96% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBasicFunctionality.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestBasicFunctionality.java index 848570c04a6c..32705a2b9600 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBasicFunctionality.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestBasicFunctionality.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.*; import jdk.test.lib.Asserts; @@ -33,7 +33,7 @@ import jdk.internal.vm.annotation.NullRestricted; import jdk.test.whitebox.WhiteBox; -import static compiler.valhalla.inlinetypes.InlineTypes.*; +import static compiler.valhalla.valuetypes.ValueTypes.*; import static compiler.lib.ir_framework.IRNode.ALLOC_ARRAY_OF_MYVALUE_KLASS; import static compiler.lib.ir_framework.IRNode.ALLOC_OF_MYVALUE_KLASS; @@ -144,8 +144,8 @@ public TestBasicFunctionality() { } public static void main(String[] args) { - InlineTypes.getFramework() - .addScenarios(InlineTypes.DEFAULT_SCENARIOS[Integer.parseInt(args[0])]) + ValueTypes.getFramework() + .addScenarios(ValueTypes.DEFAULT_SCENARIOS[Integer.parseInt(args[0])]) .addHelperClasses(MyValue1.class, MyValue2.class, MyValue2Inline.class, @@ -195,12 +195,12 @@ public void test2_verifier() { // Return incoming value object without accessing fields @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, counts = {ALLOC_OF_MYVALUE_KLASS, "= 1"}, // TODO: JDK-8380875 // STORE_OF_ANY_KLASS, "= 19"}, failOn = {LOAD_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "false"}, failOn = {ALLOC_OF_MYVALUE_KLASS, LOAD_OF_ANY_KLASS, STORE_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) public MyValue1 test3(MyValue1 v) { return v; @@ -252,10 +252,10 @@ public void test5_verifier() { // Create a value object in compiled code and pass it to // the interpreter via a call. @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, counts = {ALLOC_OF_MYVALUE_KLASS, "<= 1"}, // 1 MyValue2 allocation (if not the all-zero value) failOn = {LOAD_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "false"}, counts = {ALLOC_OF_MYVALUE_KLASS, "<= 2"}, // 1 MyValue1 and 1 MyValue2 allocation (if not the all-zero value) failOn = {LOAD_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) public long test6() { @@ -309,10 +309,10 @@ public void test8_verifier() { // Merge value objects created from two branches @Test // TODO 8380875, 8384979 - // @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, + // @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, // counts = {ALLOC_OF_MYVALUE_KLASS, "= 1", LOAD_OF_ANY_KLASS, "= 19", STORE_OF_ANY_KLASS, "= 3"}, // failOn = {UNSTABLE_IF_TRAP, PREDICATE_TRAP}) - // @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, + // @IR(applyIf = {"ValueTypePassFieldsAsArgs", "false"}, // counts = {ALLOC_OF_MYVALUE_KLASS, "= 2", STORE_OF_ANY_KLASS, "= 19"}, // failOn = {LOAD_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) public MyValue1 test9(boolean b, int localrI, long localrL) { @@ -453,10 +453,10 @@ public void test13_verifier(RunInfo info) { // Create a value object in a non-inlined method and then call a // non-inlined method on that value object. @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, failOn = {ALLOC_OF_MYVALUE_KLASS, STORE_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP}, counts = {LOAD_OF_ANY_KLASS, "= 19"}) - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "false"}, failOn = {ALLOC_OF_MYVALUE_KLASS, LOAD_OF_ANY_KLASS, STORE_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) public long test14() { MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL); @@ -472,10 +472,10 @@ public void test14_verifier() { // Create a value object in an inlined method and then call a // non-inlined method on that value object. @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, failOn = {LOAD_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP}, counts = {ALLOC_OF_MYVALUE_KLASS, "<= 1"}) // 1 MyValue2 allocation (if not the all-zero value) - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "false"}, failOn = {LOAD_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP}, counts = {ALLOC_OF_MYVALUE_KLASS, "<= 2"}) // 1 MyValue1 and 1 MyValue2 allocation (if not the all-zero value) public long test15() { @@ -523,10 +523,10 @@ public void test17_verifier() { // interpreter via a call. The value object is live at the first call so // debug info should include a reference to all its fields. @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, counts = {ALLOC_OF_MYVALUE_KLASS, "<= 1"}, // 1 MyValue2 allocation (if not the all-zero value) failOn = {LOAD_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "false"}, counts = {ALLOC_OF_MYVALUE_KLASS, "<= 2"}, // 1 MyValue1 and 1 MyValue2 allocation (if not the all-zero value) failOn = {LOAD_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) public long test18() { @@ -545,10 +545,10 @@ public void test18_verifier() { // interpreter via a call. The value object is passed twice but // should only be allocated once. @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, counts = {ALLOC_OF_MYVALUE_KLASS, "<= 1"}, // 1 MyValue2 allocation (if not the all-zero value) failOn = {LOAD_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "false"}, counts = {ALLOC_OF_MYVALUE_KLASS, "<= 2"}, // 1 MyValue1 and 1 MyValue2 allocation (if not the all-zero value) failOn = {LOAD_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) public long test19() { @@ -572,10 +572,10 @@ public void test19_verifier() { // trap: verify that deoptimization causes the value object to be // correctly allocated. @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, counts = {ALLOC_OF_MYVALUE_KLASS, "<= 1"}, // 1 MyValue2 allocation (if not the all-zero value): MyValue1.createWithFieldsInline -> setV4 failOn = {LOAD_OF_ANY_KLASS}) - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "false"}, counts = {ALLOC_OF_MYVALUE_KLASS, "<= 3"}, // 1 MyValue1 and 2 MyValue2 allocation (if not the all-zero value): same as above + the local v (MyValue1) + MyValue2.DEFAULT for the calls to MyValue2.hashInterpreted() failOn = LOAD_OF_ANY_KLASS) public long test20(boolean deopt, Method m) { @@ -818,7 +818,7 @@ public void test30_verifier() { // Verify that C2 recognizes value class loads and re-uses the oop to avoid allocations @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "false"}, failOn = {ALLOC_OF_MYVALUE_KLASS, ALLOC_ARRAY_OF_MYVALUE_KLASS, STORE_OF_ANY_KLASS}) public MyValue3 test31() { // C2 can re-use the oop returned by createDontInline() @@ -840,7 +840,7 @@ public void test31_verifier() { // Verify that C2 recognizes value class loads and re-uses the oop to avoid allocations @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "false"}, failOn = {ALLOC_OF_MYVALUE_KLASS, ALLOC_ARRAY_OF_MYVALUE_KLASS, STORE_OF_ANY_KLASS}) public MyValue3 test32(MyValue3 vt) { // C2 can re-use the oop of vt because vt is equal to 'copy'. @@ -1129,7 +1129,7 @@ static MyValue41 make() { // Test detection of value object copies and removal of the MemBarRelease following the value buffer initialization @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "false"}, failOn = {ALLOC_OF_MYVALUE_KLASS, ALLOC_ARRAY_OF_MYVALUE_KLASS, STORE_OF_ANY_KLASS}) public void test41(MyValue41 val) { field41 = new MyValue41(val.x); @@ -1149,7 +1149,7 @@ public void test42_helper(MyValue41 val) { // Same as test41 but with call argument requiring buffering @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "false"}, failOn = {ALLOC_OF_MYVALUE_KLASS, ALLOC_ARRAY_OF_MYVALUE_KLASS, STORE_OF_ANY_KLASS}) public void test42(MyValue41 val) { test42_helper(new MyValue41(val.x)); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBimorphicInlining.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestBimorphicInlining.java similarity index 93% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBimorphicInlining.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestBimorphicInlining.java index fafa684d89c4..6b9ad95d7259 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBimorphicInlining.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestBimorphicInlining.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.util.Random; import jdk.test.lib.Asserts; @@ -34,14 +34,14 @@ * @library /testlibrary /test/lib * @enablePreview * @run main/othervm -Xbatch -XX:TypeProfileLevel=222 - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestBimorphicInlining::test* - * -XX:CompileCommand=quiet -XX:CompileCommand=print,compiler.valhalla.inlinetypes.TestBimorphicInlining::test* - * compiler.valhalla.inlinetypes.TestBimorphicInlining + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestBimorphicInlining::test* + * -XX:CompileCommand=quiet -XX:CompileCommand=print,compiler.valhalla.valuetypes.TestBimorphicInlining::test* + * compiler.valhalla.valuetypes.TestBimorphicInlining * @run main/othervm -Xbatch -XX:TypeProfileLevel=222 * -XX:+UnlockExperimentalVMOptions -XX:PerMethodTrapLimit=0 -XX:PerMethodSpecTrapLimit=0 - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestBimorphicInlining::test* - * -XX:CompileCommand=quiet -XX:CompileCommand=print,compiler.valhalla.inlinetypes.TestBimorphicInlining::test* - * compiler.valhalla.inlinetypes.TestBimorphicInlining + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestBimorphicInlining::test* + * -XX:CompileCommand=quiet -XX:CompileCommand=print,compiler.valhalla.valuetypes.TestBimorphicInlining::test* + * compiler.valhalla.valuetypes.TestBimorphicInlining */ interface MyInterfaceBimorphicInlining { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBufferLost.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestBufferLost.java similarity index 99% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBufferLost.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestBufferLost.java index 90813dd63aa0..53be74796123 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBufferLost.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestBufferLost.java @@ -40,7 +40,7 @@ */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.lang.management.*; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBufferTearingC1.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestBufferTearingC1.java similarity index 96% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBufferTearingC1.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestBufferTearingC1.java index 6d377c4d6519..3ad049d1d3d6 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestBufferTearingC1.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestBufferTearingC1.java @@ -22,7 +22,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; /** * @test TestBufferTearingC1 @@ -32,10 +32,10 @@ * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening -XX:+UseArrayFlattening - * compiler.valhalla.inlinetypes.TestBufferTearingC1 + * compiler.valhalla.valuetypes.TestBufferTearingC1 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening -XX:+UseArrayFlattening * -XX:TieredStopAtLevel=1 - * compiler.valhalla.inlinetypes.TestBufferTearingC1 + * compiler.valhalla.valuetypes.TestBufferTearingC1 */ import jdk.internal.value.ValueClass; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestC1.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestC1.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestC1.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestC1.java index a92376875bf8..b490affcfea2 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestC1.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestC1.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.CompLevel; import compiler.lib.ir_framework.Run; @@ -33,8 +33,8 @@ import jdk.internal.vm.annotation.LooselyConsistentValue; import jdk.internal.vm.annotation.NullRestricted; -import static compiler.valhalla.inlinetypes.InlineTypes.rI; -import static compiler.valhalla.inlinetypes.InlineTypes.rL; +import static compiler.valhalla.valuetypes.ValueTypes.rI; +import static compiler.valhalla.valuetypes.ValueTypes.rL; /* * @test @@ -63,7 +63,7 @@ public static void main(String[] args) { new Scenario(4, "-XX:TieredStopAtLevel=4", "-XX:-TieredCompilation", "-Xcomp") }; - InlineTypes.getFramework() + ValueTypes.getFramework() .addScenarios(scenarios) .addFlags("--enable-preview", "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED", diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestC1AcmpCEE.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestC1AcmpCEE.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestC1AcmpCEE.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestC1AcmpCEE.java index 4d393e5c2711..7f852ac786ac 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestC1AcmpCEE.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestC1AcmpCEE.java @@ -34,7 +34,7 @@ * @run main ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestC1ValueNumbering.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestC1ValueNumbering.java similarity index 94% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestC1ValueNumbering.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestC1ValueNumbering.java index 83269f315ac3..11a1bee3bcef 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestC1ValueNumbering.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestC1ValueNumbering.java @@ -22,7 +22,7 @@ */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; @@ -34,8 +34,8 @@ * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @run main/othervm -Xcomp -XX:TieredStopAtLevel=1 -ea - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestC1ValueNumbering::* - * compiler.valhalla.inlinetypes.TestC1ValueNumbering + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestC1ValueNumbering::* + * compiler.valhalla.valuetypes.TestC1ValueNumbering */ import jdk.internal.vm.annotation.LooselyConsistentValue; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestC2CCalls.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestC2CCalls.java similarity index 96% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestC2CCalls.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestC2CCalls.java index 444df2af9220..3cefa700e11d 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestC2CCalls.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestC2CCalls.java @@ -30,7 +30,7 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * compiler.valhalla.inlinetypes.TestC2CCalls + * compiler.valhalla.valuetypes.TestC2CCalls */ /* @@ -43,9 +43,9 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:-UseBimorphicInlining -Xbatch - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestC2CCalls*::test* - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestC2CCalls*::test* - * compiler.valhalla.inlinetypes.TestC2CCalls + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestC2CCalls*::test* + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestC2CCalls*::test* + * compiler.valhalla.valuetypes.TestC2CCalls */ /* @@ -58,9 +58,9 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:-UseBimorphicInlining -Xbatch -XX:-ProfileInterpreter - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestC2CCalls*::test* - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestC2CCalls*::test* - * compiler.valhalla.inlinetypes.TestC2CCalls + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestC2CCalls*::test* + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestC2CCalls*::test* + * compiler.valhalla.valuetypes.TestC2CCalls */ /* @@ -73,9 +73,9 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:-UseBimorphicInlining -Xbatch - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestC2CCalls::test* - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestC2CCalls*::test* - * compiler.valhalla.inlinetypes.TestC2CCalls + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestC2CCalls::test* + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestC2CCalls*::test* + * compiler.valhalla.valuetypes.TestC2CCalls */ /* @@ -88,12 +88,12 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:-UseBimorphicInlining -Xbatch -XX:-ProfileInterpreter - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestC2CCalls::test* - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestC2CCalls*::test* - * compiler.valhalla.inlinetypes.TestC2CCalls + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestC2CCalls::test* + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestC2CCalls*::test* + * compiler.valhalla.valuetypes.TestC2CCalls */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.lang.reflect.Method; import java.util.ArrayList; @@ -532,7 +532,7 @@ public static void main(String[] args) { Collections.addAll(methods, MyValue3.class.getDeclaredMethods()); Collections.addAll(methods, MyValue4.class.getDeclaredMethods()); Collections.addAll(methods, MyObject.class.getDeclaredMethods()); - Collections.addAll(methods, compiler.valhalla.inlinetypes.TestC2CCalls.class.getDeclaredMethods()); + Collections.addAll(methods, compiler.valhalla.valuetypes.TestC2CCalls.class.getDeclaredMethods()); System.out.println("Excluding methods from C2 compilation:"); for (Method m : methods) { if (Utils.getRandomInstance().nextBoolean()) { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestCallDevirtualizationWithUnloadedReturn.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallDevirtualizationWithUnloadedReturn.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestCallDevirtualizationWithUnloadedReturn.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallDevirtualizationWithUnloadedReturn.java index 55bffb33618d..dece707124ce 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestCallDevirtualizationWithUnloadedReturn.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallDevirtualizationWithUnloadedReturn.java @@ -32,7 +32,7 @@ * ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; public class TestCallDevirtualizationWithUnloadedReturn { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestCallProjSubsumed.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallProjSubsumed.java similarity index 97% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestCallProjSubsumed.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallProjSubsumed.java index e18d1502fcd2..86efa72a66bc 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestCallProjSubsumed.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallProjSubsumed.java @@ -31,7 +31,7 @@ * @run main ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; public class TestCallProjSubsumed { public static void main(String[] args) { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestCallingConvention.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConvention.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestCallingConvention.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConvention.java index 4453515dd959..3bbe3d65292b 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestCallingConvention.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConvention.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.*; import jdk.test.lib.Asserts; @@ -32,7 +32,7 @@ import java.lang.invoke.MethodType; import java.lang.reflect.Method; -import static compiler.valhalla.inlinetypes.InlineTypes.*; +import static compiler.valhalla.valuetypes.ValueTypes.*; import static compiler.lib.ir_framework.IRNode.ALLOC; import static compiler.lib.ir_framework.IRNode.ALLOC_OF_MYVALUE_KLASS; @@ -177,14 +177,14 @@ public TestCallingConvention() { public static void main(String[] args) { - Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; + Scenario[] scenarios = ValueTypes.DEFAULT_SCENARIOS; // Don't generate bytecodes but call through runtime for reflective calls scenarios[0].addFlags("-Dsun.reflect.inflationThreshold=10000"); scenarios[1].addFlags("-Dsun.reflect.inflationThreshold=10000"); scenarios[3].addFlags("-XX:-UseArrayFlattening"); scenarios[4].addFlags("-XX:-UseTLAB"); - InlineTypes.getFramework() + ValueTypes.getFramework() .addScenarios(scenarios[Integer.parseInt(args[0])]) .addHelperClasses(MyValue1.class, MyValue2.class, @@ -453,7 +453,7 @@ public MyValue3 test15_interp() { } @Test - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, failOn = {ALLOC_OF_MYVALUE_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) public MyValue3 test15() { return test15_interp(); @@ -469,7 +469,7 @@ public void test15_verifier() { final MyValue3 test16_vt; @Test - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, failOn = {ALLOC_OF_MYVALUE_KLASS, STORE_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) public MyValue3 test16() { return test16_vt; @@ -491,7 +491,7 @@ public MyValue3 test17_comp() { } @Test - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, failOn = {ALLOC_OF_MYVALUE_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) public MyValue3 test17() { return test17_comp(); @@ -1124,7 +1124,7 @@ static value class MixedContainer { // Empty value object return @Test @IR(failOn = {LOAD_OF_ANY_KLASS, STORE_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, failOn = {ALLOC_OF_MYVALUE_KLASS}) public MyValueEmpty test42() { EmptyContainer c = new EmptyContainer(new MyValueEmpty()); @@ -1512,7 +1512,7 @@ public void m(MyValue2 val) { // Verify that the scalarized calling convention works for abstract methods @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, failOn = {ALLOC}) public void test60(Interface60 intf) { intf.m(MyValue2.createWithFieldsInline(rI, rD)); @@ -1549,7 +1549,7 @@ public void m(MyValue2 val) { // Same as test60 but with abstract value class @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, failOn = {ALLOC}) public void test61(ValueClass61 intf) { intf.m(MyValue2.createWithFieldsInline(rI, rD)); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestCallingConventionC1.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConventionC1.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestCallingConventionC1.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConventionC1.java index 31387bb7eb71..294ddaf3348a 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestCallingConventionC1.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCallingConventionC1.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.*; import jdk.test.lib.Asserts; @@ -30,8 +30,8 @@ import jdk.internal.vm.annotation.LooselyConsistentValue; import jdk.internal.vm.annotation.NullRestricted; -import static compiler.valhalla.inlinetypes.InlineTypes.rI; -import static compiler.valhalla.inlinetypes.InlineTypes.rL; +import static compiler.valhalla.valuetypes.ValueTypes.rI; +import static compiler.valhalla.valuetypes.ValueTypes.rL; /* * @test @@ -88,7 +88,7 @@ public static void main(String[] args) { System.gc(); // Resolve this call, to avoid C1 code patching in the test cases. - InlineTypes.getFramework() + ValueTypes.getFramework() .addScenarios(scenarios) .start(); } @@ -452,7 +452,7 @@ static RefPointAccess get_RefPointAccess() { static RefPoint refPointField2 = new RefPoint(56789, 0x12345678); // This value class has too many fields to fit in registers on x64 for - // InlineTypeReturnedAsFields. + // ValueTypeReturnedAsFields. @LooselyConsistentValue static value class TooBigToReturnAsFields { int a0 = 0; @@ -1593,9 +1593,9 @@ public void test77_verifier(RunInfo info) { } //------------------------------------------------------------------------------- - // Tests for how C1 handles InlineTypeReturnedAsFields in both calls and returns + // Tests for how C1 handles ValueTypeReturnedAsFields in both calls and returns //------------------------------------------------------------------------------- - // C2->C1 invokestatic with InlineTypeReturnedAsFields (Point) + // C2->C1 invokestatic with ValueTypeReturnedAsFields (Point) @Test(compLevel = CompLevel.C2) public int test78(Point p) { Point np = test78_helper(p); @@ -1615,7 +1615,7 @@ public void test78_verifier() { Asserts.assertEQ(result, n); } - // C2->C1 invokestatic with InlineTypeReturnedAsFields (RefPoint) + // C2->C1 invokestatic with ValueTypeReturnedAsFields (RefPoint) @Test(compLevel = CompLevel.C2) public int test79(RefPoint p) { RefPoint np = test79_helper(p); @@ -1635,7 +1635,7 @@ public void test79_verifier() { Asserts.assertEQ(result, n); } - // C1->C2 invokestatic with InlineTypeReturnedAsFields (RefPoint) + // C1->C2 invokestatic with ValueTypeReturnedAsFields (RefPoint) @Test(compLevel = CompLevel.C1_SIMPLE) public int test80(RefPoint p) { RefPoint np = test80_helper(p); @@ -1655,7 +1655,7 @@ public void test80_verifier() { Asserts.assertEQ(result, n); } - // Interpreter->C1 invokestatic with InlineTypeReturnedAsFields (Point) + // Interpreter->C1 invokestatic with ValueTypeReturnedAsFields (Point) @Test(compLevel = CompLevel.C1_SIMPLE) public Point test81(Point p) { return p; @@ -1671,7 +1671,7 @@ public void test81_verifier() { Asserts.assertEQ(p.y, pointField2.y); } - // C1->Interpreter invokestatic with InlineTypeReturnedAsFields (RefPoint) + // C1->Interpreter invokestatic with ValueTypeReturnedAsFields (RefPoint) @Test(compLevel = CompLevel.C1_SIMPLE) public int test82(RefPoint p) { RefPoint np = test82_helper(p); @@ -1691,10 +1691,10 @@ public void test82_verifier() { } //------------------------------------------------------------------------------- - // Tests for InlineTypeReturnedAsFields vs the value class TooBigToReturnAsFields + // Tests for ValueTypeReturnedAsFields vs the value class TooBigToReturnAsFields //------------------------------------------------------------------------------- - // C2->C1 invokestatic with InlineTypeReturnedAsFields (TooBigToReturnAsFields) + // C2->C1 invokestatic with ValueTypeReturnedAsFields (TooBigToReturnAsFields) @Test(compLevel = CompLevel.C2) public int test83(TooBigToReturnAsFields p) { TooBigToReturnAsFields np = test83_helper(p); @@ -1714,7 +1714,7 @@ public void test83_verifier() { Asserts.assertEQ(result, n); } - // C1->C2 invokestatic with InlineTypeReturnedAsFields (TooBigToReturnAsFields) + // C1->C2 invokestatic with ValueTypeReturnedAsFields (TooBigToReturnAsFields) @Test(compLevel = CompLevel.C1_SIMPLE) public int test84(TooBigToReturnAsFields p) { TooBigToReturnAsFields np = test84_helper(p); @@ -1734,7 +1734,7 @@ public void test84_verifier() { Asserts.assertEQ(result, n); } - // Interpreter->C1 invokestatic with InlineTypeReturnedAsFields (TooBigToReturnAsFields) + // Interpreter->C1 invokestatic with ValueTypeReturnedAsFields (TooBigToReturnAsFields) @Test(compLevel = CompLevel.C1_SIMPLE) public TooBigToReturnAsFields test85(TooBigToReturnAsFields p) { return p; @@ -1747,7 +1747,7 @@ public void test85_verifier() { Asserts.assertEQ(p.a2, tooBig.a2); } - // C1->Interpreter invokestatic with InlineTypeReturnedAsFields (TooBigToReturnAsFields) + // C1->Interpreter invokestatic with ValueTypeReturnedAsFields (TooBigToReturnAsFields) @Test(compLevel = CompLevel.C1_SIMPLE) public int test86(TooBigToReturnAsFields p) { TooBigToReturnAsFields np = test86_helper(p); @@ -1767,10 +1767,10 @@ public void test86_verifier() { } //------------------------------------------------------------------------------- - // Tests for how C1 handles InlineTypeReturnedAsFields in both calls and returns + // Tests for how C1 handles ValueTypeReturnedAsFields in both calls and returns //------------------------------------------------------------------------------- - // C2->C1 invokestatic with InlineTypeReturnedAsFields (RefPoint) + // C2->C1 invokestatic with ValueTypeReturnedAsFields (RefPoint) @Test(compLevel = CompLevel.C2) public RefPoint test87(RefPoint p) { return test87_helper(p); @@ -1788,7 +1788,7 @@ public void test87_verifier() { Asserts.assertEQ(test87(refPointField1), refPointField1); } - // C2->C1 invokestatic with InlineTypeReturnedAsFields (RefPoint with constant null) + // C2->C1 invokestatic with ValueTypeReturnedAsFields (RefPoint with constant null) @Test(compLevel = CompLevel.C2) public RefPoint test88() { return test88_helper(); @@ -1805,7 +1805,7 @@ public void test88_verifier() { Asserts.assertEQ(test88(), null); } - // C1->C2 invokestatic with InlineTypeReturnedAsFields (RefPoint) + // C1->C2 invokestatic with ValueTypeReturnedAsFields (RefPoint) @Test(compLevel = CompLevel.C1_SIMPLE) public RefPoint test89(RefPoint p) { return test89_helper(p); @@ -1959,7 +1959,7 @@ public void test95_verifier(RunInfo info) { } } - // C1->C2 GC handling in StubRoutines::store_inline_type_fields_to_buf() + // C1->C2 GC handling in SharedRuntime::store_value_type_fields_to_buf() @Test(compLevel = CompLevel.C1_SIMPLE) public RefPoint test96(RefPoint rp, boolean b) { RefPoint p = test96_helper(rp); @@ -1977,7 +1977,7 @@ public RefPoint test96_helper(RefPoint rp) { @Run(test = "test96") public void test96_verifier(RunInfo info) { - int count = info.isWarmUp() ? 1 : 20000; // Do enough iteration to cause GC inside StubRoutines::store_inline_type_fields_to_buf + int count = info.isWarmUp() ? 1 : 20000; // Do enough iteration to cause GC inside SharedRuntime::store_value_type_fields_to_buf Number x = new Number(10); // old object for (int i = 0; i < count; i++) { Number y = new Number(i); // new object for each iteraton diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestCastMismatch.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCastMismatch.java similarity index 93% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestCastMismatch.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCastMismatch.java index ca6a914282ed..6a90f7e5777b 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestCastMismatch.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestCastMismatch.java @@ -24,14 +24,14 @@ /** * @test * @bug 8309650 - * @summary Fix mismatch inline type issue during method calls + * @summary Fix mismatch value type issue during method calls * @library /test/lib * @enablePreview * @run main/othervm -XX:-TieredCompilation -Xcomp - * compiler.valhalla.inlinetypes.TestCastMismatch + * compiler.valhalla.valuetypes.TestCastMismatch */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.util.Random; import jdk.test.lib.Utils; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestDeadAllocationRemoval.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestDeadAllocationRemoval.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestDeadAllocationRemoval.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestDeadAllocationRemoval.java index 3987144b314c..13a37f51eade 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestDeadAllocationRemoval.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestDeadAllocationRemoval.java @@ -28,10 +28,10 @@ * @enablePreview * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation - * @run main/othervm -Xbatch compiler.valhalla.inlinetypes.TestDeadAllocationRemoval + * @run main/othervm -Xbatch compiler.valhalla.valuetypes.TestDeadAllocationRemoval */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.vm.annotation.LooselyConsistentValue; import jdk.internal.vm.annotation.NullRestricted; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestDeadLoopLateInliningWithValues.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestDeadLoopLateInliningWithValues.java similarity index 100% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestDeadLoopLateInliningWithValues.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestDeadLoopLateInliningWithValues.java diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestDeadStoreFlat.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestDeadStoreFlat.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestDeadStoreFlat.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestDeadStoreFlat.java index c0189ee0267e..84303d605384 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestDeadStoreFlat.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestDeadStoreFlat.java @@ -34,7 +34,7 @@ * ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; public class TestDeadStoreFlat { static Integer box() { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestDeadSubstitutabilityCallInIdeal.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestDeadSubstitutabilityCallInIdeal.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestDeadSubstitutabilityCallInIdeal.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestDeadSubstitutabilityCallInIdeal.java index 91ea455b8bd6..fb38cd151f40 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestDeadSubstitutabilityCallInIdeal.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestDeadSubstitutabilityCallInIdeal.java @@ -33,7 +33,7 @@ * ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; public class TestDeadSubstitutabilityCallInIdeal { private static int intField; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestDeadInlineTypeFieldOffset.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestDeadValueTypeFieldOffset.java similarity index 80% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestDeadInlineTypeFieldOffset.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestDeadValueTypeFieldOffset.java index 2ef55abfc23e..792da427a8c6 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestDeadInlineTypeFieldOffset.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestDeadValueTypeFieldOffset.java @@ -21,14 +21,14 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.vm.annotation.LooselyConsistentValue; import jdk.internal.vm.annotation.NullRestricted; /* * @test - * @summary Test loads from a dead InlineTypeNode with top field values. + * @summary Test loads from a dead ValueTypeNode with top field values. * @bug 8384202 * @requires vm.compiler2.enabled * @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true") @@ -39,22 +39,22 @@ * -XX:+StressIGVN -XX:StressSeed=8 -XX:+AlwaysIncrementalInline * ${test.main.class} */ -public value class TestDeadInlineTypeFieldOffset { +public value class TestDeadValueTypeFieldOffset { MyValue valueField1; @NullRestricted MyValue valueField2; - TestDeadInlineTypeFieldOffset(MyValue valueField1, MyValue valueField2) { + TestDeadValueTypeFieldOffset(MyValue valueField1, MyValue valueField2) { this.valueField1 = valueField1; this.valueField2 = valueField2; } - TestDeadInlineTypeFieldOffset test1() { - return new TestDeadInlineTypeFieldOffset(null, valueField2); + TestDeadValueTypeFieldOffset test1() { + return new TestDeadValueTypeFieldOffset(null, valueField2); } - TestDeadInlineTypeFieldOffset test2() { - return new TestDeadInlineTypeFieldOffset(valueField1, null); + TestDeadValueTypeFieldOffset test2() { + return new TestDeadValueTypeFieldOffset(valueField1, null); } @LooselyConsistentValue @@ -80,7 +80,7 @@ static value class MyValue { } } - static TestDeadInlineTypeFieldOffset test(TestDeadInlineTypeFieldOffset vt) { + static TestDeadValueTypeFieldOffset test(TestDeadValueTypeFieldOffset vt) { vt = vt.test1(); try { vt = vt.test2(); @@ -93,7 +93,7 @@ static TestDeadInlineTypeFieldOffset test(TestDeadInlineTypeFieldOffset vt) { public static void main(String[] args) { MyValue val = new MyValue(null, new NestedValue(5, 6)); - TestDeadInlineTypeFieldOffset vt = new TestDeadInlineTypeFieldOffset(null, val); + TestDeadValueTypeFieldOffset vt = new TestDeadValueTypeFieldOffset(null, val); for (int i = 0; i < 10_000; ++i) { vt = test(vt); } diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestDeoptimizationWhenBuffering.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestDeoptimizationWhenBuffering.java similarity index 83% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestDeoptimizationWhenBuffering.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestDeoptimizationWhenBuffering.java index 317390464c3e..f234b574f7c3 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestDeoptimizationWhenBuffering.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestDeoptimizationWhenBuffering.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.lang.invoke.*; import java.lang.reflect.Method; @@ -36,7 +36,7 @@ /* * @test id=default - * @summary Test correct execution after deoptimizing from inline type specific runtime calls. + * @summary Test correct execution after deoptimizing from value type specific runtime calls. * @library /testlibrary /test/lib /compiler/whitebox / * @enablePreview * @modules java.base/jdk.internal.value @@ -44,13 +44,13 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -XX:+DeoptimizeALot -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.*::test* - * compiler.valhalla.inlinetypes.TestDeoptimizationWhenBuffering C1 + * -XX:+DeoptimizeALot -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.*::test* + * compiler.valhalla.valuetypes.TestDeoptimizationWhenBuffering C1 */ /* * @test id=no-TLAB - * @summary Test correct execution after deoptimizing from inline type specific runtime calls. + * @summary Test correct execution after deoptimizing from value type specific runtime calls. * @library /testlibrary /test/lib /compiler/whitebox / * @enablePreview * @modules java.base/jdk.internal.value @@ -59,12 +59,12 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch - * compiler.valhalla.inlinetypes.TestDeoptimizationWhenBuffering + * compiler.valhalla.valuetypes.TestDeoptimizationWhenBuffering */ /* * @test id=no-mono-no-field - * @summary Test correct execution after deoptimizing from inline type specific runtime calls. + * @summary Test correct execution after deoptimizing from value type specific runtime calls. * @library /testlibrary /test/lib /compiler/whitebox / * @enablePreview * @modules java.base/jdk.internal.value @@ -73,14 +73,14 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch -XX:-MonomorphicArrayCheck -XX:-AlwaysIncrementalInline - * -XX:-InlineTypePassFieldsAsArgs -XX:-InlineTypeReturnedAsFields -XX:+UseArrayFlattening - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.*::test* - * compiler.valhalla.inlinetypes.TestDeoptimizationWhenBuffering + * -XX:-ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields -XX:+UseArrayFlattening + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.*::test* + * compiler.valhalla.valuetypes.TestDeoptimizationWhenBuffering */ /* * @test id=no-mono-no-field-AII - * @summary Test correct execution after deoptimizing from inline type specific runtime calls. + * @summary Test correct execution after deoptimizing from value type specific runtime calls. * @library /testlibrary /test/lib /compiler/whitebox / * @enablePreview * @modules java.base/jdk.internal.value @@ -89,14 +89,14 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch -XX:-MonomorphicArrayCheck -XX:+AlwaysIncrementalInline - * -XX:-InlineTypePassFieldsAsArgs -XX:-InlineTypeReturnedAsFields -XX:+UseArrayFlattening - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.*::test* - * compiler.valhalla.inlinetypes.TestDeoptimizationWhenBuffering + * -XX:-ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields -XX:+UseArrayFlattening + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.*::test* + * compiler.valhalla.valuetypes.TestDeoptimizationWhenBuffering */ /* * @test id=no-mono - * @summary Test correct execution after deoptimizing from inline type specific runtime calls. + * @summary Test correct execution after deoptimizing from value type specific runtime calls. * @library /testlibrary /test/lib /compiler/whitebox / * @enablePreview * @modules java.base/jdk.internal.value @@ -105,14 +105,14 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch -XX:-MonomorphicArrayCheck -XX:-AlwaysIncrementalInline - * -XX:+InlineTypePassFieldsAsArgs -XX:+InlineTypeReturnedAsFields -XX:+UseArrayFlattening - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.*::test* - * compiler.valhalla.inlinetypes.TestDeoptimizationWhenBuffering + * -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:+UseArrayFlattening + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.*::test* + * compiler.valhalla.valuetypes.TestDeoptimizationWhenBuffering */ /* * @test id=no-mono-AII - * @summary Test correct execution after deoptimizing from inline type specific runtime calls. + * @summary Test correct execution after deoptimizing from value type specific runtime calls. * @library /testlibrary /test/lib /compiler/whitebox / * @enablePreview * @modules java.base/jdk.internal.value @@ -121,14 +121,14 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch -XX:-MonomorphicArrayCheck -XX:+AlwaysIncrementalInline - * -XX:+InlineTypePassFieldsAsArgs -XX:+InlineTypeReturnedAsFields -XX:+UseArrayFlattening - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.*::test* - * compiler.valhalla.inlinetypes.TestDeoptimizationWhenBuffering + * -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:+UseArrayFlattening + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.*::test* + * compiler.valhalla.valuetypes.TestDeoptimizationWhenBuffering */ /* * @test id=no-mono-no-FF - * @summary Test correct execution after deoptimizing from inline type specific runtime calls. + * @summary Test correct execution after deoptimizing from value type specific runtime calls. * @library /testlibrary /test/lib /compiler/whitebox / * @enablePreview * @modules java.base/jdk.internal.value @@ -137,14 +137,14 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch -XX:-MonomorphicArrayCheck -XX:-AlwaysIncrementalInline - * -XX:+InlineTypePassFieldsAsArgs -XX:+InlineTypeReturnedAsFields -XX:+UseArrayFlattening -XX:-UseFieldFlattening - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.*::test* - * compiler.valhalla.inlinetypes.TestDeoptimizationWhenBuffering + * -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:+UseArrayFlattening -XX:-UseFieldFlattening + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.*::test* + * compiler.valhalla.valuetypes.TestDeoptimizationWhenBuffering */ /* * @test id=no-mono-no-FF-AII - * @summary Test correct execution after deoptimizing from inline type specific runtime calls. + * @summary Test correct execution after deoptimizing from value type specific runtime calls. * @library /testlibrary /test/lib /compiler/whitebox / * @enablePreview * @modules java.base/jdk.internal.value @@ -153,9 +153,9 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch -XX:-MonomorphicArrayCheck -XX:+AlwaysIncrementalInline - * -XX:+InlineTypePassFieldsAsArgs -XX:+InlineTypeReturnedAsFields -XX:+UseArrayFlattening -XX:-UseFieldFlattening - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.*::test* - * compiler.valhalla.inlinetypes.TestDeoptimizationWhenBuffering + * -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:+UseArrayFlattening -XX:-UseFieldFlattening + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.*::test* + * compiler.valhalla.valuetypes.TestDeoptimizationWhenBuffering */ public class TestDeoptimizationWhenBuffering { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestEAPhisWithFlatArrayAccesses.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestEAPhisWithFlatArrayAccesses.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestEAPhisWithFlatArrayAccesses.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestEAPhisWithFlatArrayAccesses.java index 32f13845b714..3e4042c5a7bb 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestEAPhisWithFlatArrayAccesses.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestEAPhisWithFlatArrayAccesses.java @@ -30,7 +30,7 @@ * @run main/othervm -XX:-BackgroundCompilation ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; public class TestEAPhisWithFlatArrayAccesses { static int field; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestEAScalarizedArg.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestEAScalarizedArg.java similarity index 94% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestEAScalarizedArg.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestEAScalarizedArg.java index 330e23aa3919..8646be346794 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestEAScalarizedArg.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestEAScalarizedArg.java @@ -26,10 +26,10 @@ * @bug 8377480 * @summary [lworld] incorrect execution due to EA pointer comparison optimization at scalarized call * @enablePreview - * @run main/othervm -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestEAScalarizedArg::notInlined* ${test.main.class} + * @run main/othervm -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestEAScalarizedArg::notInlined* ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; public class TestEAScalarizedArg { static value class MyValue { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestEAWideArg.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestEAWideArg.java similarity index 100% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestEAWideArg.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestEAWideArg.java diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestEliminateAutoBox.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestEliminateAutoBox.java similarity index 91% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestEliminateAutoBox.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestEliminateAutoBox.java index fa1d3fd00cf2..fcfb6d1b46ca 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestEliminateAutoBox.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestEliminateAutoBox.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.*; import jdk.test.lib.Asserts; @@ -66,13 +66,13 @@ public class TestEliminateAutoBox { public static void main(String[] args) { new TestFramework() .addScenarios( - scenario(0, "-XX:+InlineTypePassFieldsAsArgs", "-XX:+InlineTypeReturnedAsFields", DONT_INLINE_BOXES), - scenario(1, "-XX:-InlineTypePassFieldsAsArgs", "-XX:+InlineTypeReturnedAsFields", DONT_INLINE_BOXES), - scenario(2, "-XX:+InlineTypePassFieldsAsArgs", "-XX:-InlineTypeReturnedAsFields", DONT_INLINE_BOXES), - scenario(3, "-XX:-InlineTypePassFieldsAsArgs", "-XX:-InlineTypeReturnedAsFields", DONT_INLINE_BOXES), - scenario(4, "-XX:-InlineTypePassFieldsAsArgs", "-XX:-InlineTypeReturnedAsFields", DONT_INLINE_VALUEOF), - scenario(5, "-XX:+InlineTypePassFieldsAsArgs", "-XX:+InlineTypeReturnedAsFields", INLINE_VALUEOF), - scenario(6, "-XX:-InlineTypePassFieldsAsArgs", "-XX:-InlineTypeReturnedAsFields", INLINE_VALUEOF)) + scenario(0, "-XX:+ValueTypePassFieldsAsArgs", "-XX:+ValueTypeReturnedAsFields", DONT_INLINE_BOXES), + scenario(1, "-XX:-ValueTypePassFieldsAsArgs", "-XX:+ValueTypeReturnedAsFields", DONT_INLINE_BOXES), + scenario(2, "-XX:+ValueTypePassFieldsAsArgs", "-XX:-ValueTypeReturnedAsFields", DONT_INLINE_BOXES), + scenario(3, "-XX:-ValueTypePassFieldsAsArgs", "-XX:-ValueTypeReturnedAsFields", DONT_INLINE_BOXES), + scenario(4, "-XX:-ValueTypePassFieldsAsArgs", "-XX:-ValueTypeReturnedAsFields", DONT_INLINE_VALUEOF), + scenario(5, "-XX:+ValueTypePassFieldsAsArgs", "-XX:+ValueTypeReturnedAsFields", INLINE_VALUEOF), + scenario(6, "-XX:-ValueTypePassFieldsAsArgs", "-XX:-ValueTypeReturnedAsFields", INLINE_VALUEOF)) .start(); } @@ -91,7 +91,7 @@ private static Scenario scenario(int index, String flag1, String flag2, String[] // Eliminate a scalarized Integer.valueOf result. @Test - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, failOn = {IRNode.ALLOC_OF, "Integer", IRNode.STATIC_CALL_OF_METHOD, "Integer::valueOf"}) public static Integer testBoxingInt(int i) { return Integer.valueOf(i); @@ -153,7 +153,7 @@ public void runBoxUnboxExplicitInt() { // Eliminate an implicit Integer unbox followed by an implicit box. @Test @IR(failOn = {IRNode.ALLOC_OF, "Integer", IRNode.STATIC_CALL_OF_METHOD, "Integer::intValue"}) - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, failOn = {IRNode.STATIC_CALL_OF_METHOD, "Integer::valueOf"}) public static Integer testUnboxBoxImplicitInt(Integer i) { int res = i; @@ -176,7 +176,7 @@ public void runUnboxBoxImplicitInt(RunInfo info) { // Eliminate an explicit Integer.intValue followed by valueOf. @Test @IR(failOn = {IRNode.ALLOC_OF, "Integer", IRNode.STATIC_CALL_OF_METHOD, "Integer::intValue"}) - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, failOn = {IRNode.STATIC_CALL_OF_METHOD, "Integer::valueOf"}) public static Integer testUnboxBoxExplicitInt(Integer i) { int res = i.intValue(); @@ -198,7 +198,7 @@ public void runUnboxBoxExplicitInt(RunInfo info) { // Eliminate a scalarized Long.valueOf result with a two-slot field. @Test - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, failOn = {IRNode.ALLOC_OF, "Long", IRNode.STATIC_CALL_OF_METHOD, "Long::valueOf"}) public static Long testBoxingLong(long l) { return Long.valueOf(l); @@ -260,7 +260,7 @@ public void runBoxUnboxExplicitLong() { // Eliminate an implicit Long unbox followed by an implicit box. @Test @IR(failOn = {IRNode.ALLOC_OF, "Long", IRNode.STATIC_CALL_OF_METHOD, "Long::longValue"}) - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, failOn = {IRNode.STATIC_CALL_OF_METHOD, "Long::valueOf"}) public static Long testUnboxBoxImplicitLong(Long l) { long res = l; @@ -283,7 +283,7 @@ public void runUnboxBoxImplicitLong(RunInfo info) { // Eliminate an explicit Long.longValue followed by valueOf. @Test @IR(failOn = {IRNode.ALLOC_OF, "Long", IRNode.STATIC_CALL_OF_METHOD, "Long::longValue"}) - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, failOn = {IRNode.STATIC_CALL_OF_METHOD, "Long::valueOf"}) public static Long testUnboxBoxExplicitLong(Long l) { long res = l.longValue(); @@ -305,7 +305,7 @@ public void runUnboxBoxExplicitLong(RunInfo info) { // Eliminate a scalarized Double.valueOf result with a two-slot field. @Test - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, failOn = {IRNode.ALLOC_OF, "Double", IRNode.STATIC_CALL_OF_METHOD, "Double::valueOf"}) public static Double testBoxingDouble(double d) { return Double.valueOf(d); @@ -367,7 +367,7 @@ public void runBoxUnboxExplicitDouble() { // Eliminate an implicit Double unbox followed by an implicit box. @Test @IR(failOn = {IRNode.ALLOC_OF, "Double", IRNode.STATIC_CALL_OF_METHOD, "Double::doubleValue"}) - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, failOn = {IRNode.STATIC_CALL_OF_METHOD, "Double::valueOf"}) public static Double testUnboxBoxImplicitDouble(Double d) { double res = d; @@ -390,7 +390,7 @@ public void runUnboxBoxImplicitDouble(RunInfo info) { // Eliminate an explicit Double.doubleValue followed by valueOf. @Test @IR(failOn = {IRNode.ALLOC_OF, "Double", IRNode.STATIC_CALL_OF_METHOD, "Double::doubleValue"}) - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, failOn = {IRNode.STATIC_CALL_OF_METHOD, "Double::valueOf"}) public static Double testUnboxBoxExplicitDouble(Double d) { double res = d.doubleValue(); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestExplosiveValueClass.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestExplosiveValueClass.java similarity index 99% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestExplosiveValueClass.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestExplosiveValueClass.java index 151a0290ccfb..af9f52b6377a 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestExplosiveValueClass.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestExplosiveValueClass.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; /* * @test diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFieldNullMarkers.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFieldNullMarkers.java similarity index 94% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFieldNullMarkers.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFieldNullMarkers.java index 55978fc6fbec..061463eb8eb3 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFieldNullMarkers.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFieldNullMarkers.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.vm.annotation.LooselyConsistentValue; import jdk.internal.vm.annotation.NullRestricted; @@ -41,8 +41,8 @@ * java.base/jdk.internal.vm.annotation * @compile TestFieldNullMarkers.java * @run driver jdk.test.lib.helpers.StrictProcessor - * compiler.valhalla.inlinetypes.TestFieldNullMarkers$StrictFieldHolder - * @run main/timeout=300 compiler.valhalla.inlinetypes.TestFieldNullMarkers + * compiler.valhalla.valuetypes.TestFieldNullMarkers$StrictFieldHolder + * @run main/timeout=300 compiler.valhalla.valuetypes.TestFieldNullMarkers */ /* @@ -57,12 +57,12 @@ * java.base/jdk.internal.vm.annotation * @compile TestFieldNullMarkers.java * @run driver jdk.test.lib.helpers.StrictProcessor - * compiler.valhalla.inlinetypes.TestFieldNullMarkers$StrictFieldHolder + * compiler.valhalla.valuetypes.TestFieldNullMarkers$StrictFieldHolder * @run main/othervm/timeout=300 -Xbatch * -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions * -XX:-UseNullableAtomicValueFlattening -XX:-UseNullFreeAtomicValueFlattening -XX:-UseNullFreeNonAtomicValueFlattening - * compiler.valhalla.inlinetypes.TestFieldNullMarkers + * compiler.valhalla.valuetypes.TestFieldNullMarkers */ /* @@ -77,12 +77,12 @@ * java.base/jdk.internal.vm.annotation * @compile TestFieldNullMarkers.java * @run driver jdk.test.lib.helpers.StrictProcessor - * compiler.valhalla.inlinetypes.TestFieldNullMarkers$StrictFieldHolder + * compiler.valhalla.valuetypes.TestFieldNullMarkers$StrictFieldHolder * @run main/othervm/timeout=300 -Xbatch * -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions * -XX:-UseNullableAtomicValueFlattening -XX:-UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening - * compiler.valhalla.inlinetypes.TestFieldNullMarkers + * compiler.valhalla.valuetypes.TestFieldNullMarkers */ /* @@ -97,12 +97,12 @@ * java.base/jdk.internal.vm.annotation * @compile TestFieldNullMarkers.java * @run driver jdk.test.lib.helpers.StrictProcessor - * compiler.valhalla.inlinetypes.TestFieldNullMarkers$StrictFieldHolder + * compiler.valhalla.valuetypes.TestFieldNullMarkers$StrictFieldHolder * @run main/othervm/timeout=300 -Xbatch * -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions * -XX:-UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:-UseNullFreeNonAtomicValueFlattening - * compiler.valhalla.inlinetypes.TestFieldNullMarkers + * compiler.valhalla.valuetypes.TestFieldNullMarkers */ /* @@ -117,12 +117,12 @@ * java.base/jdk.internal.vm.annotation * @compile TestFieldNullMarkers.java * @run driver jdk.test.lib.helpers.StrictProcessor - * compiler.valhalla.inlinetypes.TestFieldNullMarkers$StrictFieldHolder + * compiler.valhalla.valuetypes.TestFieldNullMarkers$StrictFieldHolder * @run main/othervm/timeout=300 -Xbatch * -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions * -XX:-UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening - * compiler.valhalla.inlinetypes.TestFieldNullMarkers + * compiler.valhalla.valuetypes.TestFieldNullMarkers */ /* @@ -137,12 +137,12 @@ * java.base/jdk.internal.vm.annotation * @compile TestFieldNullMarkers.java * @run driver jdk.test.lib.helpers.StrictProcessor - * compiler.valhalla.inlinetypes.TestFieldNullMarkers$StrictFieldHolder + * compiler.valhalla.valuetypes.TestFieldNullMarkers$StrictFieldHolder * @run main/othervm/timeout=300 -Xbatch * -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions * -XX:+UseNullableAtomicValueFlattening -XX:-UseNullFreeAtomicValueFlattening -XX:-UseNullFreeNonAtomicValueFlattening - * compiler.valhalla.inlinetypes.TestFieldNullMarkers + * compiler.valhalla.valuetypes.TestFieldNullMarkers */ /* @@ -157,12 +157,12 @@ * java.base/jdk.internal.vm.annotation * @compile TestFieldNullMarkers.java * @run driver jdk.test.lib.helpers.StrictProcessor - * compiler.valhalla.inlinetypes.TestFieldNullMarkers$StrictFieldHolder + * compiler.valhalla.valuetypes.TestFieldNullMarkers$StrictFieldHolder * @run main/othervm/timeout=300 -Xbatch * -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions * -XX:+UseNullableAtomicValueFlattening -XX:-UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening - * compiler.valhalla.inlinetypes.TestFieldNullMarkers + * compiler.valhalla.valuetypes.TestFieldNullMarkers */ /* @@ -177,12 +177,12 @@ * java.base/jdk.internal.vm.annotation * @compile TestFieldNullMarkers.java * @run driver jdk.test.lib.helpers.StrictProcessor - * compiler.valhalla.inlinetypes.TestFieldNullMarkers$StrictFieldHolder + * compiler.valhalla.valuetypes.TestFieldNullMarkers$StrictFieldHolder * @run main/othervm/timeout=300 -Xbatch * -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions * -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:-UseNullFreeNonAtomicValueFlattening - * compiler.valhalla.inlinetypes.TestFieldNullMarkers + * compiler.valhalla.valuetypes.TestFieldNullMarkers */ /* @@ -197,12 +197,12 @@ * java.base/jdk.internal.vm.annotation * @compile TestFieldNullMarkers.java * @run driver jdk.test.lib.helpers.StrictProcessor - * compiler.valhalla.inlinetypes.TestFieldNullMarkers$StrictFieldHolder + * compiler.valhalla.valuetypes.TestFieldNullMarkers$StrictFieldHolder * @run main/othervm/timeout=300 -Xbatch * -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions * -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening - * compiler.valhalla.inlinetypes.TestFieldNullMarkers + * compiler.valhalla.valuetypes.TestFieldNullMarkers */ /* @@ -217,13 +217,13 @@ * java.base/jdk.internal.vm.annotation * @compile TestFieldNullMarkers.java * @run driver jdk.test.lib.helpers.StrictProcessor - * compiler.valhalla.inlinetypes.TestFieldNullMarkers$StrictFieldHolder + * compiler.valhalla.valuetypes.TestFieldNullMarkers$StrictFieldHolder * @run main/othervm/timeout=300 -Xbatch * -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions * -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening * -XX:CompileCommand=dontinline,*::testHelper* - * compiler.valhalla.inlinetypes.TestFieldNullMarkers + * compiler.valhalla.valuetypes.TestFieldNullMarkers */ /* @@ -238,13 +238,13 @@ * java.base/jdk.internal.vm.annotation * @compile TestFieldNullMarkers.java * @run driver jdk.test.lib.helpers.StrictProcessor - * compiler.valhalla.inlinetypes.TestFieldNullMarkers$StrictFieldHolder + * compiler.valhalla.valuetypes.TestFieldNullMarkers$StrictFieldHolder * @run main/othervm/timeout=300 -Xbatch * -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions * -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening - * -XX:+InlineTypeReturnedAsFields -XX:+InlineTypePassFieldsAsArgs - * compiler.valhalla.inlinetypes.TestFieldNullMarkers + * -XX:+ValueTypeReturnedAsFields -XX:+ValueTypePassFieldsAsArgs + * compiler.valhalla.valuetypes.TestFieldNullMarkers */ /* @@ -259,13 +259,13 @@ * java.base/jdk.internal.vm.annotation * @compile TestFieldNullMarkers.java * @run driver jdk.test.lib.helpers.StrictProcessor - * compiler.valhalla.inlinetypes.TestFieldNullMarkers$StrictFieldHolder + * compiler.valhalla.valuetypes.TestFieldNullMarkers$StrictFieldHolder * @run main/othervm/timeout=300 -Xbatch * -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions * -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening - * -XX:-InlineTypeReturnedAsFields -XX:-InlineTypePassFieldsAsArgs - * compiler.valhalla.inlinetypes.TestFieldNullMarkers + * -XX:-ValueTypeReturnedAsFields -XX:-ValueTypePassFieldsAsArgs + * compiler.valhalla.valuetypes.TestFieldNullMarkers */ /* @@ -280,13 +280,13 @@ * java.base/jdk.internal.vm.annotation * @compile TestFieldNullMarkers.java * @run driver jdk.test.lib.helpers.StrictProcessor - * compiler.valhalla.inlinetypes.TestFieldNullMarkers$StrictFieldHolder + * compiler.valhalla.valuetypes.TestFieldNullMarkers$StrictFieldHolder * @run main/othervm/timeout=300 -Xbatch * -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions * -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening - * -XX:+InlineTypeReturnedAsFields -XX:-InlineTypePassFieldsAsArgs - * compiler.valhalla.inlinetypes.TestFieldNullMarkers + * -XX:+ValueTypeReturnedAsFields -XX:-ValueTypePassFieldsAsArgs + * compiler.valhalla.valuetypes.TestFieldNullMarkers */ /* @@ -301,13 +301,13 @@ * java.base/jdk.internal.vm.annotation * @compile TestFieldNullMarkers.java * @run driver jdk.test.lib.helpers.StrictProcessor - * compiler.valhalla.inlinetypes.TestFieldNullMarkers$StrictFieldHolder + * compiler.valhalla.valuetypes.TestFieldNullMarkers$StrictFieldHolder * @run main/othervm/timeout=300 -Xbatch * -XX:+UnlockDiagnosticVMOptions * -XX:+UnlockExperimentalVMOptions * -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening - * -XX:-InlineTypeReturnedAsFields -XX:+InlineTypePassFieldsAsArgs - * compiler.valhalla.inlinetypes.TestFieldNullMarkers + * -XX:-ValueTypeReturnedAsFields -XX:+ValueTypePassFieldsAsArgs + * compiler.valhalla.valuetypes.TestFieldNullMarkers */ public class TestFieldNullMarkers { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayAliasesCardMark.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatArrayAliasesCardMark.java similarity index 96% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayAliasesCardMark.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatArrayAliasesCardMark.java index 5cd6d3b5c11d..d28e3e8dc584 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayAliasesCardMark.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatArrayAliasesCardMark.java @@ -29,10 +29,10 @@ * @enablePreview * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation - * @run main/othervm -XX:-BackgroundCompilation compiler.valhalla.inlinetypes.TestFlatArrayAliasesCardMark + * @run main/othervm -XX:-BackgroundCompilation compiler.valhalla.valuetypes.TestFlatArrayAliasesCardMark */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.value.ValueClass; import jdk.internal.vm.annotation.LooselyConsistentValue; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayCASAssert.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatArrayCASAssert.java similarity index 100% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayCASAssert.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatArrayCASAssert.java diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayCheckExpansion.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatArrayCheckExpansion.java similarity index 99% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayCheckExpansion.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatArrayCheckExpansion.java index e3afb9138f59..f1a2fa8c4146 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayCheckExpansion.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatArrayCheckExpansion.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.value.ValueClass; import jdk.test.lib.Asserts; @@ -127,4 +127,3 @@ public static void main(String[] args) { } } } - diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayCheckHoisting.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatArrayCheckHoisting.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayCheckHoisting.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatArrayCheckHoisting.java index 6c2c7de0041d..ef0da588d09c 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayCheckHoisting.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatArrayCheckHoisting.java @@ -34,7 +34,7 @@ * ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; public class TestFlatArrayCheckHoisting { // A and C arrays are flat, B is too large to flatten and I has identity diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayLoadPinning.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatArrayLoadPinning.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayLoadPinning.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatArrayLoadPinning.java index 4997ac2c64f6..bd0093e7ef3a 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayLoadPinning.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatArrayLoadPinning.java @@ -35,7 +35,7 @@ * ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.value.ValueClass; import jdk.internal.vm.annotation.LooselyConsistentValue; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayMemoryPhi.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatArrayMemoryPhi.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayMemoryPhi.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatArrayMemoryPhi.java index 1051e301b48a..3253bc2d10ac 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayMemoryPhi.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatArrayMemoryPhi.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.value.ValueClass; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayThreshold.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatArrayThreshold.java similarity index 95% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayThreshold.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatArrayThreshold.java index 2b1d1a6e36eb..5c491dfde18d 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatArrayThreshold.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatArrayThreshold.java @@ -29,15 +29,15 @@ * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @run main/othervm -Xbatch - * compiler.valhalla.inlinetypes.TestFlatArrayThreshold + * compiler.valhalla.valuetypes.TestFlatArrayThreshold * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:FlatArrayElementMaxOops=1 -Xbatch - * compiler.valhalla.inlinetypes.TestFlatArrayThreshold + * compiler.valhalla.valuetypes.TestFlatArrayThreshold * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseArrayFlattening -Xbatch - * compiler.valhalla.inlinetypes.TestFlatArrayThreshold + * compiler.valhalla.valuetypes.TestFlatArrayThreshold */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatInArraySpeculation.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatInArraySpeculation.java similarity index 99% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatInArraySpeculation.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatInArraySpeculation.java index fdf9eea67592..efeb3757807b 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatInArraySpeculation.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatInArraySpeculation.java @@ -32,7 +32,7 @@ * @run main ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; public class TestFlatInArraySpeculation { static boolean flag; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatInArraysFolding.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatInArraysFolding.java similarity index 99% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatInArraysFolding.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatInArraysFolding.java index 2aa7bd6dfa96..6194c590fc53 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatInArraysFolding.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatInArraysFolding.java @@ -48,7 +48,7 @@ * @run driver ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.*; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatTwoOopField.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatTwoOopField.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatTwoOopField.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatTwoOopField.java index cfaef1920adc..e5c98d9d0aac 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestFlatTwoOopField.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestFlatTwoOopField.java @@ -33,7 +33,7 @@ * ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.vm.annotation.NullRestricted; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestGenerated.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestGenerated.java similarity index 97% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestGenerated.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestGenerated.java index bf533984e68b..27c8ff4820b4 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestGenerated.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestGenerated.java @@ -33,19 +33,19 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xbatch - * compiler.valhalla.inlinetypes.TestGenerated + * compiler.valhalla.valuetypes.TestGenerated * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xbatch -XX:ForceNonTearable=* - * compiler.valhalla.inlinetypes.TestGenerated + * compiler.valhalla.valuetypes.TestGenerated * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xbatch -XX:-UseArrayFlattening - * compiler.valhalla.inlinetypes.TestGenerated + * compiler.valhalla.valuetypes.TestGenerated * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI * -Xbatch -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening - * compiler.valhalla.inlinetypes.TestGenerated + * compiler.valhalla.valuetypes.TestGenerated */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.value.ValueClass; import jdk.internal.vm.annotation.LooselyConsistentValue; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestGetCyclicField.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestGetCyclicField.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestGetCyclicField.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestGetCyclicField.java index 836a0293f323..257086636920 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestGetCyclicField.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestGetCyclicField.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.misc.Unsafe; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestGetFlatValueNullableNonAtomic.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestGetFlatValueNullableNonAtomic.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestGetFlatValueNullableNonAtomic.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestGetFlatValueNullableNonAtomic.java index 0edea05be58a..3ef5d14beb5b 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestGetFlatValueNullableNonAtomic.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestGetFlatValueNullableNonAtomic.java @@ -36,7 +36,7 @@ * ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.lang.reflect.Field; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestGetfieldChains.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestGetfieldChains.java similarity index 97% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestGetfieldChains.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestGetfieldChains.java index 7afc7152d4dc..f48469b743e3 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestGetfieldChains.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestGetfieldChains.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.CompLevel; import compiler.lib.ir_framework.Run; @@ -113,7 +113,7 @@ public static void main(String[] args) { "-Xcomp") }; - InlineTypes.getFramework() + ValueTypes.getFramework() .addScenarios(scenarios) .addFlags("--enable-preview", "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED", @@ -187,7 +187,7 @@ public void test4_verifier() { Asserts.assertNE(iae, null); StackTraceElement st = iae.getStackTrace()[0]; Asserts.assertEQ(st.getMethodName(), "getP1Y"); - Asserts.assertTrue(iae.getMessage().contains("class compiler.valhalla.inlinetypes.NamedRectangleP tried to access private field compiler.valhalla.inlinetypes.RectangleP.p1")); + Asserts.assertTrue(iae.getMessage().contains("class compiler.valhalla.valuetypes.NamedRectangleP tried to access private field compiler.valhalla.valuetypes.RectangleP.p1")); } // Chain of getfields but the last getfield triggers a NoSuchFieldError @@ -209,7 +209,7 @@ public void test5_verifier() { Asserts.assertNE(nsfe, null); StackTraceElement st = nsfe.getStackTrace()[0]; Asserts.assertEQ(st.getMethodName(), "getP1X"); - Asserts.assertEQ(nsfe.getMessage(), "Class compiler.valhalla.inlinetypes.PointN does not have member field 'int x'"); + Asserts.assertEQ(nsfe.getMessage(), "Class compiler.valhalla.valuetypes.PointN does not have member field 'int x'"); } @LooselyConsistentValue diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestHashcodeFastPath.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestHashcodeFastPath.java similarity index 99% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestHashcodeFastPath.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestHashcodeFastPath.java index 1238ccc37b6f..7871b767560e 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestHashcodeFastPath.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestHashcodeFastPath.java @@ -219,7 +219,7 @@ * @run main ${test.main.class} 1:nofast:nointrinsics */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import static compiler.lib.generators.Generators.G; import compiler.lib.ir_framework.*; @@ -257,7 +257,7 @@ static RunSettings parseSetting(String arg) { } public static void main(String[] args) { - Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; + Scenario[] scenarios = ValueTypes.DEFAULT_SCENARIOS; RunSettings settings = parseSetting(args[0]); Scenario scenario = scenarios[settings.scenario]; if (!settings.useHashCodeFastPath) { @@ -267,7 +267,7 @@ public static void main(String[] args) { scenario.addFlags("-XX:DisableIntrinsic=_identityHashCode"); } scenario.addFlags("-XX:CompileCommand=exclude,*::h"); - InlineTypes.getFramework() + ValueTypes.getFramework() .addScenarios(scenario) .start(); } diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestImplicitNullCheckInIC.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestImplicitNullCheckInIC.java similarity index 94% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestImplicitNullCheckInIC.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestImplicitNullCheckInIC.java index 4a3c7bf8bfd5..665ea9053ac0 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestImplicitNullCheckInIC.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestImplicitNullCheckInIC.java @@ -27,15 +27,15 @@ * @bug 8375086 * @library /test/lib * @enablePreview - * @run main compiler.valhalla.inlinetypes.TestImplicitNullCheckInIC + * @run main compiler.valhalla.valuetypes.TestImplicitNullCheckInIC * @run main/othervm -Xbatch -XX:TieredStopAtLevel=1 * -XX:CompileCommand=compileonly,*TestImplicitNullCheckInIC*::test* * -XX:CompileCommand=compileonly,*TestImplicitNullCheckInIC*::callee * -XX:CompileCommand=compileonly,java.lang.Integer::compareTo - * compiler.valhalla.inlinetypes.TestImplicitNullCheckInIC + * compiler.valhalla.valuetypes.TestImplicitNullCheckInIC */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; public class TestImplicitNullCheckInIC { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIncorrectlyEliminatedStoreToFlatArray.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestIncorrectlyEliminatedStoreToFlatArray.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIncorrectlyEliminatedStoreToFlatArray.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestIncorrectlyEliminatedStoreToFlatArray.java index 8cb26b598a6b..24b5a26db7eb 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIncorrectlyEliminatedStoreToFlatArray.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestIncorrectlyEliminatedStoreToFlatArray.java @@ -36,7 +36,7 @@ */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.value.ValueClass; public class TestIncorrectlyEliminatedStoreToFlatArray { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestIntrinsics.java similarity index 99% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestIntrinsics.java index e455d7ee68c8..55c202ce1210 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestIntrinsics.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.misc.Unsafe; import jdk.test.lib.Asserts; @@ -36,8 +36,8 @@ import jdk.internal.vm.annotation.NullRestricted; import jdk.test.whitebox.WhiteBox; -import static compiler.valhalla.inlinetypes.InlineTypes.rI; -import static compiler.valhalla.inlinetypes.InlineTypes.rL; +import static compiler.valhalla.valuetypes.ValueTypes.rI; +import static compiler.valhalla.valuetypes.ValueTypes.rL; import static compiler.lib.ir_framework.IRNode.CALL_UNSAFE; import static compiler.lib.ir_framework.IRNode.LOAD; @@ -154,11 +154,11 @@ public TestIntrinsics() { public static void main(String[] args) { - Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; + Scenario[] scenarios = ValueTypes.DEFAULT_SCENARIOS; scenarios[3].addFlags("-XX:+UseArrayFlattening", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck"); scenarios[4].addFlags("-XX:+UnlockExperimentalVMOptions", "-XX:PerMethodSpecTrapLimit=0", "-XX:PerMethodTrapLimit=0", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck"); - InlineTypes.getFramework() + ValueTypes.getFramework() .addScenarios(scenarios[Integer.parseInt(args[0])]) .addFlags("-Xbootclasspath/a:.", "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", "-XX:CompileCommand=inline,jdk.internal.misc.Unsafe::*", @@ -1429,7 +1429,7 @@ public void test65_verifier() { Asserts.assertEQ(test63_vt, vt); } - // compareAndSet to flattened field in object, non-inline arguments to compare and set + // compareAndSet to flattened field in object, non-value arguments to compare and set @Test public boolean test66(Object oldVal, Object newVal) { if (TEST63_VT_FLATTENED) { @@ -1554,7 +1554,7 @@ public void test69_verifier() { Asserts.assertEQ(test63_vt, vt); } - // compareAndExchange to flattened field in object, non-inline arguments to compare and set + // compareAndExchange to flattened field in object, non-value arguments to compare and set @Test public Object test70(Object oldVal, Object newVal) { if (TEST63_VT_FLATTENED) { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIsAssignableFrom.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestIsAssignableFrom.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIsAssignableFrom.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestIsAssignableFrom.java index fd532da93ec6..896ed11bdfae 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIsAssignableFrom.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestIsAssignableFrom.java @@ -33,7 +33,7 @@ * ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIsInstance.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestIsInstance.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIsInstance.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestIsInstance.java index e5d30dbddfca..41663d24e9da 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIsInstance.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestIsInstance.java @@ -21,12 +21,12 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; /* * @test * @summary Test correctness of the isInstance intrinsic with deep class hierarchies. - * @run main/othervm -Xbatch compiler.valhalla.inlinetypes.TestIsInstance + * @run main/othervm -Xbatch compiler.valhalla.valuetypes.TestIsInstance */ public class TestIsInstance { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIsSubstitutableReresolution.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestIsSubstitutableReresolution.java similarity index 92% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIsSubstitutableReresolution.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestIsSubstitutableReresolution.java index f646fe231b15..d3403e23cfa1 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIsSubstitutableReresolution.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestIsSubstitutableReresolution.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; @@ -31,8 +31,8 @@ * @library /testlibrary /test/lib * @summary Verify that call reresolution works for C2 compiled calls to java.lang.runtime.ValueObjectMethods::isSubstitutable0. * @enablePreview - * @run main/othervm -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestIsSubstitutableReresolution::test - * compiler.valhalla.inlinetypes.TestIsSubstitutableReresolution + * @run main/othervm -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestIsSubstitutableReresolution::test + * compiler.valhalla.valuetypes.TestIsSubstitutableReresolution */ value class MyValueIsSubstReresolution { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestJNICalls.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestJNICalls.java similarity index 95% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestJNICalls.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestJNICalls.java index c4a41f5e5d64..7c69d9f7e799 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestJNICalls.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestJNICalls.java @@ -21,13 +21,13 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; import compiler.lib.ir_framework.*; -import static compiler.valhalla.inlinetypes.InlineTypes.rI; -import static compiler.valhalla.inlinetypes.InlineTypes.rL; +import static compiler.valhalla.valuetypes.ValueTypes.rI; +import static compiler.valhalla.valuetypes.ValueTypes.rL; /* * @test @@ -117,9 +117,9 @@ public class TestJNICalls { public static void main(String[] args) { - Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; + Scenario[] scenarios = ValueTypes.DEFAULT_SCENARIOS; - InlineTypes.getFramework() + ValueTypes.getFramework() .addScenarios(scenarios[Integer.parseInt(args[0])]) .addHelperClasses(MyValue1.class) .start(); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLWorld.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLWorld.java similarity index 95% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLWorld.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLWorld.java index f4187db48981..b858dea5c58f 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLWorld.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLWorld.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.*; import jdk.test.lib.Asserts; @@ -39,7 +39,7 @@ import jdk.internal.vm.annotation.LooselyConsistentValue; import jdk.internal.vm.annotation.NullRestricted; -import static compiler.valhalla.inlinetypes.InlineTypes.*; +import static compiler.valhalla.valuetypes.ValueTypes.*; import static compiler.lib.ir_framework.IRNode.ALLOC; import static compiler.lib.ir_framework.IRNode.ALLOC_OF_MYVALUE_KLASS; @@ -52,20 +52,20 @@ import static compiler.lib.ir_framework.IRNode.LOAD; import static compiler.lib.ir_framework.IRNode.LOAD_OF_ANY_KLASS; import static compiler.lib.ir_framework.IRNode.LOAD_P; -import static compiler.lib.ir_framework.IRNode.LOAD_UNKNOWN_INLINE; +import static compiler.lib.ir_framework.IRNode.LOAD_UNKNOWN_VALUE; import static compiler.lib.ir_framework.IRNode.LOOP; import static compiler.lib.ir_framework.IRNode.MEMBAR; import static compiler.lib.ir_framework.IRNode.NULL_CHECK_TRAP; import static compiler.lib.ir_framework.IRNode.PREDICATE_TRAP; import static compiler.lib.ir_framework.IRNode.STATIC_CALL_OF_METHOD; import static compiler.lib.ir_framework.IRNode.STORE_OF_ANY_KLASS; -import static compiler.lib.ir_framework.IRNode.STORE_UNKNOWN_INLINE; +import static compiler.lib.ir_framework.IRNode.STORE_UNKNOWN_VALUE; import static compiler.lib.ir_framework.IRNode.UNSTABLE_IF_TRAP; /* * @test * @key randomness - * @summary Test inline types in LWorld. + * @summary Test value types in LWorld. * @library /test/lib /test/jdk/java/lang/invoke/common / * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64") * @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true") @@ -79,7 +79,7 @@ /* * @test * @key randomness - * @summary Test inline types in LWorld. + * @summary Test value types in LWorld. * @library /test/lib /test/jdk/java/lang/invoke/common / * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64") * @enablePreview @@ -92,7 +92,7 @@ /* * @test * @key randomness - * @summary Test inline types in LWorld. + * @summary Test value types in LWorld. * @library /test/lib /test/jdk/java/lang/invoke/common / * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64") * @enablePreview @@ -105,7 +105,7 @@ /* * @test * @key randomness - * @summary Test inline types in LWorld. + * @summary Test value types in LWorld. * @library /test/lib /test/jdk/java/lang/invoke/common / * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64") * @enablePreview @@ -118,7 +118,7 @@ /* * @test * @key randomness - * @summary Test inline types in LWorld. + * @summary Test value types in LWorld. * @library /test/lib /test/jdk/java/lang/invoke/common / * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64") * @enablePreview @@ -131,7 +131,7 @@ /* * @test * @key randomness - * @summary Test inline types in LWorld. + * @summary Test value types in LWorld. * @library /test/lib /test/jdk/java/lang/invoke/common / * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64") * @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true") @@ -145,7 +145,7 @@ /* * @test * @key randomness - * @summary Test inline types in LWorld. + * @summary Test value types in LWorld. * @library /test/lib /test/jdk/java/lang/invoke/common / * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64") * @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true") @@ -177,11 +177,11 @@ public static void main(String[] args) { Class class2 = Test141Value.class; class2.getDeclaredFields(); - Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; + Scenario[] scenarios = ValueTypes.DEFAULT_SCENARIOS; scenarios[3].addFlags("-XX:+UseArrayFlattening", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck"); scenarios[4].addFlags("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck"); - InlineTypes.getFramework() + ValueTypes.getFramework() // TODO 8337821: Temporarily increased MemLimit - remove again with JDK-8378328 once fixed. .addFlags("-XX:CompileCommand=MemLimit,*.*,0") .addScenarios(scenarios[Integer.parseInt(args[0])]) @@ -211,7 +211,7 @@ protected long hash() { return testValue1.hash(); } - // Test passing an inline type as an Object + // Test passing a value type as an Object @DontInline public Object test1_dontinline1(Object o) { return o; @@ -248,7 +248,7 @@ public void test1_verifier() { Asserts.assertEQ(test1().hash(), hash()); } - // Test storing/loading inline types to/from Object and inline type fields + // Test storing/loading value types to/from Object and value type fields Object objectField1 = null; Object objectField2 = null; Object objectField3 = null; @@ -314,7 +314,7 @@ public void test2_verifier() { Asserts.assertEQ(result, 11*vt.hash() + 2*def.hashPrimitive()); } - // Test merging inline types and objects + // Test merging value types and objects @Test public Object test3(int state) { Object res = null; @@ -360,7 +360,7 @@ public void test3_verifier() { Asserts.assertEQ(testValue2, result); } - // Test merging inline types and objects in loops + // Test merging value types and objects in loops @Test public Object test4(int iters) { Object res = new NonValueClass(rI); @@ -384,7 +384,7 @@ public void test4_verifier() { Asserts.assertEQ(vt, result2); } - // Test inline types in object variables that are live at safepoint + // Test value types in object variables that are live at safepoint @Test @IR(failOn = {ALLOC_OF_MYVALUE_KLASS, STORE_OF_ANY_KLASS, LOOP}) public long test5(MyValue1 arg, boolean deopt, Method m) { @@ -406,7 +406,7 @@ public void test5_verifier(RunInfo info) { Asserts.assertEQ(result, 4*hash()); } - // Test comparing inline types with objects + // Test comparing value types with objects @Test public boolean test6(Object arg) { Object vt = MyValue1.createWithFieldsInline(rI, rL); @@ -423,7 +423,7 @@ public void test6_verifier() { Asserts.assertFalse(result); } - // merge of inline type and non-inline type + // merge of value type and non-value type @Test public Object test7(boolean flag) { Object res = null; @@ -458,7 +458,7 @@ public void test8_verifier() { Asserts.assertEQ(test8(false), valueField1); } - // merge of inline types in a loop, stored in an object local + // merge of value types in a loop, stored in an object local @Test public Object test9() { Object o = valueField1; @@ -474,7 +474,7 @@ public void test9_verifier() { Asserts.assertEQ(test9(), MyValue1.setX(valueField1, valueField1.x + 7)); } - // merge of inline types in an object local + // merge of value types in an object local @ForceInline public Object test10_helper() { return valueField1; @@ -535,7 +535,7 @@ public void test11_verifier() { Asserts.assertEQ(test11().hash(), hash()); } - // Test storing/loading inline types to/from interface and inline type fields + // Test storing/loading value types to/from interface and value type fields MyInterface interfaceField1 = null; MyInterface interfaceField2 = null; MyInterface interfaceField3 = null; @@ -598,7 +598,7 @@ public long hash() { } } - // Test merging inline types and interfaces + // Test merging value types and interfaces @Test public MyInterface test13(int state) { MyInterface res = null; @@ -636,7 +636,7 @@ public void test13_verifier() { Asserts.assertEQ(result, null); } - // Test merging inline types and interfaces in loops + // Test merging value types and interfaces in loops @Test public MyInterface test14(int iters) { MyInterface res = new MyObject1(rI); @@ -660,7 +660,7 @@ public void test14_verifier() { Asserts.assertEQ(vt, result2); } - // Test inline types in interface variables that are live at safepoint + // Test value types in interface variables that are live at safepoint @Test @IR(failOn = {ALLOC_OF_MYVALUE_KLASS, STORE_OF_ANY_KLASS, LOOP}) public long test15(MyValue1 arg, boolean deopt, Method m) { @@ -678,7 +678,7 @@ public void test15_verifier(RunInfo info) { Asserts.assertEQ(result, 4*hash()); } - // Test comparing inline types with interfaces + // Test comparing value types with interfaces @Test public boolean test16(Object arg) { MyInterface vt = MyValue1.createWithFieldsInline(rI, rL); @@ -695,7 +695,7 @@ public void test16_verifier() { Asserts.assertFalse(result); } - // Test subtype check when casting to inline type + // Test subtype check when casting to value type @Test @IR(failOn = {ALLOC_OF_MYVALUE_KLASS}) public MyValue1 test17(MyValue1 vt, Object obj) { @@ -791,7 +791,7 @@ public void test20_verifier() { private static final NonValueClass[] testNonValueArray = new NonValueClass[42]; - // Test load from (flattened) inline type array disguised as object array + // Test load from (flattened) value type array disguised as object array @Test public Object test21(Object[] oa, int index) { return oa[index]; @@ -803,7 +803,7 @@ public void test21_verifier() { Asserts.assertEQ(result.hash(), hash()); } - // Test load from (flattened) inline type array disguised as interface array + // Test load from (flattened) value type array disguised as interface array @Test public Object test22Interface(MyInterface[] ia, int index) { return ia[index]; @@ -815,7 +815,7 @@ public void test22Interface_verifier() { Asserts.assertEQ(result.hash(), hash()); } - // Test load from (flattened) inline type array disguised as abstract array + // Test load from (flattened) value type array disguised as abstract array @Test public Object test22Abstract(MyAbstract[] ia, int index) { return ia[index]; @@ -827,7 +827,7 @@ public void test22Abstract_verifier() { Asserts.assertEQ(result.hash(), hash()); } - // Test inline store to (flattened) inline type array disguised as object array + // Test inline store to (flattened) value type array disguised as object array @ForceInline public void test23_inline(Object[] oa, Object o, int index) { oa[index] = o; @@ -896,7 +896,7 @@ public void test25_verifier() { } } - // Test inline store to (flattened) inline type array disguised as interface array + // Test inline store to (flattened) value type array disguised as interface array @ForceInline public void test26Interface_inline(MyInterface[] ia, MyInterface i, int index) { ia[index] = i; @@ -944,7 +944,7 @@ public void test27Interface_verifier() { } } - // Test inline store to (flattened) inline type array disguised as abstract array + // Test inline store to (flattened) value type array disguised as abstract array @ForceInline public void test26Abstract_inline(MyAbstract[] ia, MyAbstract i, int index) { ia[index] = i; @@ -992,7 +992,7 @@ public void test27Abstract_verifier() { } } - // Test object store to (flattened) inline type array disguised as object array + // Test object store to (flattened) value type array disguised as object array @ForceInline public void test28_inline(Object[] oa, Object o, int index) { oa[index] = o; @@ -1062,7 +1062,7 @@ public void test30_verifier() { } } - // Test inline store to (flattened) inline type array disguised as interface array + // Test inline store to (flattened) value type array disguised as interface array @ForceInline public void test31Interface_inline(MyInterface[] ia, MyInterface i, int index) { ia[index] = i; @@ -1110,7 +1110,7 @@ public void test32Interface_verifier() { } } - // Test inline store to (flattened) inline type array disguised as abstract array + // Test inline store to (flattened) value type array disguised as abstract array @ForceInline public void test31Abstract_inline(MyAbstract[] ia, MyAbstract i, int index) { ia[index] = i; @@ -1158,7 +1158,7 @@ public void test32Abstract_verifier() { } } - // Test writing null to a (flattened) inline type array disguised as object array + // Test writing null to a (flattened) value type array disguised as object array @ForceInline public void test33_inline(Object[] oa, Object o, int index) { oa[index] = o; @@ -1181,7 +1181,7 @@ public void test33_verifier() { Asserts.assertEQ(testValue1Array[index].hash(), hash()); } - // Test writing constant null to a (flattened) inline type array disguised as object array + // Test writing constant null to a (flattened) value type array disguised as object array @ForceInline public void test34_inline(Object[] oa, Object o, int index) { @@ -1205,7 +1205,7 @@ public void test34_verifier() { Asserts.assertEQ(testValue1Array[index].hash(), hash()); } - // Test writing constant null to a (flattened) inline type array + // Test writing constant null to a (flattened) value type array private static final MethodHandle setArrayElementNull = InstructionHelper.buildMethodHandle(MethodHandles.lookup(), "setArrayElementNull", @@ -1237,7 +1237,7 @@ public void test35_verifier() throws Throwable { Asserts.assertEQ(testValue1Array[index].hash(), hash()); } - // Test writing an inline type to a null inline type array + // Test writing a value type to a null value type array @Test public void test36(MyValue1[] va, MyValue1 vt, int index) { va[index] = vt; @@ -1282,7 +1282,7 @@ public void test37_verifier() { testValue1Array[index] = testValue1; } - // Test merging of inline type arrays + // Test merging of value type arrays @ForceInline public Object[] test38_inline() { @@ -1446,9 +1446,9 @@ public void test39_verifier() { Asserts.assertEQ(testValue1, ((MyValue1[][])result)[index][index]); } - // Test instanceof with inline types and arrays + // Test instanceof with value types and arrays @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, failOn = {ALLOC}) public long test40(Object o, int index) { if (o instanceof MyValue1) { @@ -1600,7 +1600,7 @@ public void test45_verifier() throws Throwable { Asserts.assertEQ(testValue1Array[index].hash(), hash()); } - // instanceof tests with inline types + // instanceof tests with value types @Test @IR(failOn = {ALLOC}) public boolean test46(MyValue1 vt) { @@ -1666,7 +1666,7 @@ public void test50_verifier() { Asserts.assertFalse(test49(new NonValueClass(42))); } - // Inline type with some non-flattened fields + // Value type with some non-flattened fields @LooselyConsistentValue static value class Test51Value { Object objectField1; @@ -1755,7 +1755,7 @@ public long test(Test51Value holder, MyValue1 vt1, Object vt2) { static MyValue1 test51_arg2 = MyValue1.DEFAULT; static Object test51_arg3; - // Same as test2 but with field holder being an inline type + // Same as test2 but with field holder being a value type @Test public long test51() { return test51_arg1.test(test51_arg1, test51_arg2, test51_arg3); @@ -1775,7 +1775,7 @@ public void test51_verifier() { Asserts.assertEQ(result, 9*vt.hash() + def.hashPrimitive()); } - // Access non-flattened, uninitialized inline type field with inline type holder + // Access non-flattened, uninitialized value type field with value type holder @Test @IR(failOn = {ALLOC_OF_MYVALUE_KLASS}) public void test52(Test51Value holder) { @@ -1791,7 +1791,7 @@ public void test52_verifier() { test52(vt); } - // Merging inline types of different types + // Merging value types of different types @Test public Object test53(Object o, boolean b) { MyValue1 vt = MyValue1.createWithFieldsInline(rI, rL); @@ -1834,11 +1834,11 @@ public void test55_verifier() { Asserts.assertEQ(testValue2, result2); } - // Test synchronization on inline types + // Test synchronization on value types @Test public void test56(Object vt) { synchronized (vt) { - throw new RuntimeException("test56 failed: synchronization on inline type should not succeed"); + throw new RuntimeException("test56 failed: synchronization on value type should not succeed"); } } @@ -1855,7 +1855,7 @@ public void test56_verifier() { @ForceInline public void test57_inline(Object vt) { synchronized (vt) { - throw new RuntimeException("test57 failed: synchronization on inline type should not succeed"); + throw new RuntimeException("test57 failed: synchronization on value type should not succeed"); } } @@ -1878,7 +1878,7 @@ public void test57_verifier() { @ForceInline public void test58_inline(Object vt) { synchronized (vt) { - throw new RuntimeException("test58 failed: synchronization on inline type should not succeed"); + throw new RuntimeException("test58 failed: synchronization on value type should not succeed"); } } @@ -1905,7 +1905,7 @@ public void test59(Object o, boolean b) { Object sync = b ? vt : o; synchronized (sync) { if (b) { - throw new RuntimeException("test59 failed: synchronization on inline type should not succeed"); + throw new RuntimeException("test59 failed: synchronization on value type should not succeed"); } } } @@ -1926,7 +1926,7 @@ public void test60(boolean b) { MyValue1 vt = MyValue1.createWithFieldsInline(rI, rL); Object sync = b ? vt : testValue2; synchronized (sync) { - throw new RuntimeException("test60 failed: synchronization on inline type should not succeed"); + throw new RuntimeException("test60 failed: synchronization on value type should not succeed"); } } @@ -2000,7 +2000,7 @@ public void test63_verifier() { throw new RuntimeException("test63 failed: no exception thrown"); } - // type system test with interface and inline type + // type system test with interface and value type @ForceInline public MyInterface test64Interface_helper(MyValue1 vt) { return vt; @@ -2016,7 +2016,7 @@ public void test64Interface_verifier() { test64Interface(testValue1); } - // type system test with abstract and inline type + // type system test with abstract and value type @ForceInline public MyAbstract test64Abstract_helper(MyValue1 vt) { return vt; @@ -2082,7 +2082,7 @@ public void test68_verifier() { Asserts.assertEQ(array[0], obj); } - // Test conversion between an inline type and java.lang.Object without an allocation + // Test conversion between a value type and java.lang.Object without an allocation @ForceInline public Object test69_sum(Object a, Object b) { int sum = ((MyValue1)a).x + ((MyValue1)b).x; @@ -2151,7 +2151,7 @@ public void test70Abstract_verifier() { Asserts.assertEQ(result, rI * testValue1Array.length); } - // Test that allocated inline type is not used in non-dominated path + // Test that allocated value type is not used in non-dominated path public MyValue1 test71_inline(Object obj) { MyValue1 vt = MyValue1.createWithFieldsInline(rI, rL); try { @@ -2175,7 +2175,7 @@ public void test71_verifier() { Asserts.assertEquals(vt.hash(), hash()); } - // Test calling a method on an uninitialized inline type + // Test calling a method on an uninitialized value type @LooselyConsistentValue value class Test72Value { int x = 0; @@ -2246,7 +2246,7 @@ public void test75_verifier() { test75(42); } - // Casting an NonValueClass to a inline type should throw a ClassCastException + // Casting an NonValueClass to a value type should throw a ClassCastException @ForceInline public MyValue1 test77_helper(Object o) { return (MyValue1)o; @@ -2270,7 +2270,7 @@ public void test77_verifier() throws Throwable { } } - // Casting a null NonValueClass to a nullable inline type should not throw + // Casting a null NonValueClass to a nullable value type should not throw @ForceInline public MyValue1 test78_helper(Object o) { return (MyValue1)o; @@ -2291,7 +2291,7 @@ public void test78_verifier() throws Throwable { } } - // Casting an NonValueClass to a nullable inline type should throw a ClassCastException + // Casting an NonValueClass to a nullable value type should throw a ClassCastException @ForceInline public MyValue1 test79_helper(Object o) { return (MyValue1)o; @@ -2315,7 +2315,7 @@ public void test79_verifier() throws Throwable { } } - // Test flattened field with non-flattened (but flattenable) inline type field + // Test flattened field with non-flattened (but flattenable) value type field @LooselyConsistentValue static value class Small { int i; @@ -2398,7 +2398,7 @@ public void test81_verifier() { Asserts.assertEQ(result, 10*rI); } - // Test check for null free array when storing to inline type array + // Test check for null free array when storing to value type array @Test public void test82(Object[] dst, Object v) { dst[0] = v; @@ -2484,8 +2484,8 @@ public void test84_verifier(RunInfo info) { @Test @IR(applyIf = {"UseArrayFlattening", "true"}, - counts = {COUNTED_LOOP, "= 2", LOAD_UNKNOWN_INLINE, "= 1"}, - // Match on PHASEIDEALLOOP2 before load_unknown_inline gets duplicated in pre/main/post + counts = {COUNTED_LOOP, "= 2", LOAD_UNKNOWN_VALUE, "= 1"}, + // Match on PHASEIDEALLOOP2 before load_unknown_value gets duplicated in pre/main/post phase = {CompilePhase.PHASEIDEALLOOP2}) public void test85(Object[] src, Object[] dst) { for (int i = 0; i < src.length; i++) { @@ -2628,7 +2628,7 @@ public Test92Value() { // TODO 8355382 The optimization only applies to null-free, flat arrays @IR(applyIfAnd = {"UseArrayFlattening", "true", "UseNullableAtomicValueFlattening", "false"}, counts = {CLASS_CHECK_TRAP, "= 2"}, - failOn = {LOAD_UNKNOWN_INLINE, ALLOC, MEMBAR}) + failOn = {LOAD_UNKNOWN_VALUE, ALLOC, MEMBAR}) public Object test92(Object[] array) { // Dummy loops to ensure we run enough passes of split if for (int i = 0; i < 2; i++) { @@ -2696,7 +2696,7 @@ public void test93_verifier(RunInfo info) { // TODO 8355382 The optimization only applies to null-free, flat arrays @IR(applyIfAnd = {"UseArrayFlattening", "true", "UseNullableAtomicValueFlattening", "false"}, counts = {CLASS_CHECK_TRAP, "= 2", LOOP, "= 1"}, - failOn = {LOAD_UNKNOWN_INLINE, ALLOC, MEMBAR}) + failOn = {LOAD_UNKNOWN_VALUE, ALLOC, MEMBAR}) public int test94(Object[] array) { int res = 0; for (int i = 1; i < 4; i *= 2) { @@ -2790,7 +2790,7 @@ public void test97_verifier() { Asserts.assertEQ(test97().hash(), hash()); } - // Test storing/loading inline types to/from abstract and inline type fields + // Test storing/loading value types to/from abstract and value type fields MyAbstract abstractField1 = null; MyAbstract abstractField2 = null; MyAbstract abstractField3 = null; @@ -2853,7 +2853,7 @@ public long hash() { } } - // Test merging inline types and abstract classes + // Test merging value types and abstract classes @Test public MyAbstract test99(int state) { MyAbstract res = null; @@ -2891,7 +2891,7 @@ public void test99_verifier() { Asserts.assertEQ(result, null); } - // Test merging inline types and abstract classes in loops + // Test merging value types and abstract classes in loops @Test public MyAbstract test100(int iters) { MyAbstract res = new MyObject2(rI); @@ -2915,7 +2915,7 @@ public void test100_verifier() { Asserts.assertEQ(vt, result2); } - // Test inline types in abstract class variables that are live at safepoint + // Test value types in abstract class variables that are live at safepoint @Test @IR(failOn = {ALLOC_OF_MYVALUE_KLASS, STORE_OF_ANY_KLASS, LOOP}) public long test101(MyValue1 arg, boolean deopt, Method m) { @@ -2937,7 +2937,7 @@ public void test101_verifier(RunInfo info) { Asserts.assertEQ(result, 4*hash()); } - // Test comparing inline types with abstract classes + // Test comparing value types with abstract classes @Test public boolean test102(Object arg) { MyAbstract vt = MyValue1.createWithFieldsInline(rI, rL); @@ -2954,7 +2954,7 @@ public void test102_verifier() { Asserts.assertFalse(result); } - // An abstract class with a non-static field can never be implemented by an inline type + // An abstract class with a non-static field can never be implemented by a value type abstract class NoValueImplementors1 { int field = 42; } @@ -2969,7 +2969,7 @@ class MyObject4 extends NoValueImplementors1 { // Loading from an abstract class array does not require a flatness check if the abstract class has a non-static field @Test - @IR(failOn = {ALLOC, MEMBAR, LOAD_UNKNOWN_INLINE, STORE_UNKNOWN_INLINE, INLINE_ARRAY_NULL_GUARD}) + @IR(failOn = {ALLOC, MEMBAR, LOAD_UNKNOWN_VALUE, STORE_UNKNOWN_VALUE, INLINE_ARRAY_NULL_GUARD}) public NoValueImplementors1 test103(NoValueImplementors1[] array, int i) { return array[i]; } @@ -2991,7 +2991,7 @@ public void test103_verifier() { // Storing to an abstract class array does not require a flatness/null check if the abstract class has a non-static field @Test - @IR(failOn = {ALLOC, LOAD_UNKNOWN_INLINE, STORE_UNKNOWN_INLINE, INLINE_ARRAY_NULL_GUARD}) + @IR(failOn = {ALLOC, LOAD_UNKNOWN_VALUE, STORE_UNKNOWN_VALUE, INLINE_ARRAY_NULL_GUARD}) public NoValueImplementors1 test104(NoValueImplementors1[] array, NoValueImplementors1 v, MyObject3 o, int i) { array[0] = v; array[1] = array[0]; @@ -3025,7 +3025,7 @@ public void test104_verifier() { Asserts.assertEquals(result, v); } - // An abstract class with a single, non-inline implementor + // An abstract class with a single, non-value implementor abstract class NoValueImplementors2 { } @@ -3036,7 +3036,7 @@ class MyObject5 extends NoValueImplementors2 { // Loading from an abstract class array does not require a flatness check if the abstract class has no inline implementor @Test - @IR(failOn = {ALLOC, MEMBAR, LOAD_UNKNOWN_INLINE, STORE_UNKNOWN_INLINE, INLINE_ARRAY_NULL_GUARD}) + @IR(failOn = {ALLOC, MEMBAR, LOAD_UNKNOWN_VALUE, STORE_UNKNOWN_VALUE, INLINE_ARRAY_NULL_GUARD}) public NoValueImplementors2 test105(NoValueImplementors2[] array, int i) { return array[i]; } @@ -3054,7 +3054,7 @@ public void test105_verifier() { // Storing to an abstract class array does not require a flatness/null check if the abstract class has no inline implementor @Test - @IR(failOn = {ALLOC, LOAD_UNKNOWN_INLINE, STORE_UNKNOWN_INLINE, INLINE_ARRAY_NULL_GUARD}) + @IR(failOn = {ALLOC, LOAD_UNKNOWN_VALUE, STORE_UNKNOWN_VALUE, INLINE_ARRAY_NULL_GUARD}) public NoValueImplementors2 test106(NoValueImplementors2[] array, NoValueImplementors2 v, MyObject5 o, int i) { array[0] = v; array[1] = array[0]; @@ -3085,8 +3085,8 @@ public void test106_verifier() { @Test @IR(applyIf = {"UseArrayFlattening", "true"}, - failOn = {STORE_UNKNOWN_INLINE, INLINE_ARRAY_NULL_GUARD}, - counts = {COUNTED_LOOP, "= 2", LOAD_UNKNOWN_INLINE, "= 2"}, + failOn = {STORE_UNKNOWN_VALUE, INLINE_ARRAY_NULL_GUARD}, + counts = {COUNTED_LOOP, "= 2", LOAD_UNKNOWN_VALUE, "= 2"}, // Match on CCP since we are removing one of the unswitched loop versions later due to being empty phase = {CompilePhase.CCP1}) public void test107(Object[] src1, Object[] src2) { @@ -3117,8 +3117,8 @@ public void test107_verifier(RunInfo info) { @Test @IR(applyIf = {"UseArrayFlattening", "true"}, - failOn = {LOAD_UNKNOWN_INLINE, INLINE_ARRAY_NULL_GUARD}, - counts = {COUNTED_LOOP, "= 4", STORE_UNKNOWN_INLINE, "= 9"}) + failOn = {LOAD_UNKNOWN_VALUE, INLINE_ARRAY_NULL_GUARD}, + counts = {COUNTED_LOOP, "= 4", STORE_UNKNOWN_VALUE, "= 9"}) public void test108(Object[] dst1, Object[] dst2, Object o1, Object o2) { for (int i = 0; i < dst1.length; i++) { dst1[i] = o1; @@ -3274,7 +3274,7 @@ static GenericBox box(long val) { long[] lArr = {0L, rL, 0L, rL, 0L, rL, 0L, rL, 0L, rL}; - // Test removal of allocations when inline type instance is wrapped into box object + // Test removal of allocations when value type instance is wrapped into box object @Test @IR(failOn = {ALLOC, MEMBAR}, counts = {PREDICATE_TRAP, "= 1"}) @@ -3500,7 +3500,7 @@ static InterfaceBox2 box_dynamic(long val) { } } - // Same as tests above but with ZERO hidden in field of another inline type + // Same as tests above but with ZERO hidden in field of another value type @Test @IR(failOn = {ALLOC, MEMBAR}, counts = {PREDICATE_TRAP, "= 1"}) @@ -3545,7 +3545,7 @@ public void test115_verifier() { MyValueEmpty fEmpty3; MyValueEmpty fEmpty4 = new MyValueEmpty(); - // Test fields loads/stores with empty inline types + // Test fields loads/stores with empty value types @Test public void test116() { fEmpty1 = fEmpty4; @@ -3562,7 +3562,7 @@ public void test116_verifier() { Asserts.assertEquals(fEmpty3, fEmpty4); } - // Test array loads/stores with empty inline types + // Test array loads/stores with empty value types @Test public MyValueEmpty test117(MyValueEmpty[] arr1, MyValueEmpty[] arr2) { arr1[0] = arr2[0]; @@ -3578,7 +3578,7 @@ public void test117_verifier() { Asserts.assertEquals(arr1[0], new MyValueEmpty()); } - // Test acmp with empty inline types + // Test acmp with empty value types @Test public boolean test118(MyValueEmpty v1, MyValueEmpty v2, Object o1) { return (v1 == v2) && (v2 == o1); @@ -3612,7 +3612,7 @@ static value class MixedContainer { @NullRestricted static final MixedContainer mixedContainer = new MixedContainer(); - // Test re-allocation of empty inline type array during deoptimization + // Test re-allocation of empty value type array during deoptimization @Test public void test119(boolean deopt, Method m) { MyValueEmpty[] array1 = new MyValueEmpty[] { empty, null }; @@ -3635,7 +3635,7 @@ public void test119_verifier(RunInfo info) { test119(!info.isWarmUp(), info.getTest()); } - // Test optimization of empty inline type field stores + // Test optimization of empty value type field stores @Test @IR(failOn = {ALLOC, LOAD_OF_ANY_KLASS, STORE_OF_ANY_KLASS, NULL_CHECK_TRAP, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) public void test120() { @@ -3650,7 +3650,7 @@ public void test120_verifier() { Asserts.assertEquals(fEmpty1, empty); } - // Test removal of empty inline type field loads + // Test removal of empty value type field loads @Test @IR(failOn = {LOAD_OF_ANY_KLASS, STORE_OF_ANY_KLASS, FIELD_ACCESS, NULL_CHECK_TRAP, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) public boolean test121() { @@ -3664,9 +3664,9 @@ public void test121_verifier() { Asserts.assertTrue(res); } - // Verify that empty inline type field loads check for null holder + // Verify that empty value type field loads check for null holder @Test - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, failOn = {ALLOC}) public MyValueEmpty test122(TestLWorld t) { return t.fEmpty3; @@ -3684,7 +3684,7 @@ public void test122_verifier() { } } - // Verify that empty inline type field stores check for null holder + // Verify that empty value type field stores check for null holder @Test @IR(failOn = {ALLOC}) public void test123(TestLWorld t) { @@ -3732,7 +3732,7 @@ public void test125_verifier() { test125(null); } - // Test inline type that can only be scalarized after loop opts + // Test value type that can only be scalarized after loop opts @Test @IR(failOn = {ALLOC, LOAD_OF_ANY_KLASS, STORE_OF_ANY_KLASS}) public long test126(boolean trap) { @@ -3794,7 +3794,7 @@ public void test127_verifier(RunInfo info) { } } - // Test inline type that can only be scalarized after CCP + // Test value type that can only be scalarized after CCP @Test @IR(failOn = {ALLOC, LOAD_OF_ANY_KLASS, STORE_OF_ANY_KLASS}) public long test128(boolean trap) { @@ -3856,7 +3856,7 @@ public void test129_verifier(RunInfo info) { } } - // Lock on inline type (known after inlining) + // Lock on value type (known after inlining) @ForceInline public Object test130_inlinee() { return MyValue1.createWithFieldsInline(rI, rL); @@ -3871,7 +3871,7 @@ public Object test130_inlinee() { public void test130() { Object obj = test130_inlinee(); synchronized (obj) { - throw new RuntimeException("test130 failed: synchronization on inline type should not succeed"); + throw new RuntimeException("test130 failed: synchronization on value type should not succeed"); } } @@ -3896,7 +3896,7 @@ public Object test131_inlinee() { public void test131() { Object obj = test131_inlinee(); synchronized (obj) { - throw new RuntimeException("test131 failed: synchronization on inline type should not succeed"); + throw new RuntimeException("test131 failed: synchronization on value type should not succeed"); } } @@ -3910,7 +3910,7 @@ public void test131_verifier() { } } - // Test locking on object that is known to be an inline type only after CCP + // Test locking on object that is known to be a value type only after CCP @Test @IR(failOn = {ALLOC_OF_MYVALUE_KLASS, LOAD_OF_ANY_KLASS, STORE_OF_ANY_KLASS}) public void test132() { @@ -3923,7 +3923,7 @@ public void test132() { obj = vt; } synchronized (obj) { - throw new RuntimeException("test132 failed: synchronization on inline type should not succeed"); + throw new RuntimeException("test132 failed: synchronization on value type should not succeed"); } } @@ -3938,13 +3938,13 @@ public void test132_verifier() { } } - // Test conditional locking on inline type and non-escaping object + // Test conditional locking on value type and non-escaping object @Test public void test133(boolean b) { Object obj = b ? new NonValueClass(rI) : MyValue2.createWithFieldsInline(rI, rD); synchronized (obj) { if (!b) { - throw new RuntimeException("test133 failed: synchronization on inline type should not succeed"); + throw new RuntimeException("test133 failed: synchronization on value type should not succeed"); } } } @@ -3960,7 +3960,7 @@ public void test133_verifier() { } } - // Variant with non-scalarized inline type + // Variant with non-scalarized value type @Test @IR(failOn = {ALLOC}) public void test134(boolean b) { @@ -3983,7 +3983,7 @@ public void test134_verifier() { } } - // Test that acmp of the same inline object is removed + // Test that acmp of the same value object is removed @Test @IR(failOn = {ALLOC, LOAD_OF_ANY_KLASS, STORE_OF_ANY_KLASS, NULL_CHECK_TRAP, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) public boolean test135() { @@ -4013,7 +4013,7 @@ public void test136_verifier() { Asserts.assertTrue(test136(true)); } - // Test that acmp of different inline objects with same content is removed + // Test that acmp of different value objects with same content is removed @Test @IR(failOn = {ALLOC, LOAD_OF_ANY_KLASS, STORE_OF_ANY_KLASS, NULL_CHECK_TRAP, UNSTABLE_IF_TRAP, PREDICATE_TRAP, STATIC_CALL_OF_METHOD, "isSubstitutable.*"}) public boolean test137(int i) { @@ -4060,7 +4060,7 @@ static value class Test139Wrapper { } @Test - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, failOn = {ALLOC}) @IR(failOn = {LOAD_OF_ANY_KLASS, STORE_OF_ANY_KLASS, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) public MyValueEmpty test139() { @@ -4074,7 +4074,7 @@ public void test139_verifier() { Asserts.assertEquals(empty, new MyValueEmpty()); } - // Test calling a method on a loaded but not linked inline type + // Test calling a method on a loaded but not linked value type @LooselyConsistentValue value class Test140Value { int x = 0; @@ -4098,7 +4098,7 @@ public void test140_verifier() { Asserts.assertEquals(result, 0); } - // Test calling a method on a linked but not initialized inline type + // Test calling a method on a linked but not initialized value type @LooselyConsistentValue value class Test141Value { int x = 0; @@ -4122,7 +4122,7 @@ public void test141_verifier() { Asserts.assertEquals(result, 0); } - // Test that virtual calls on inline type receivers are properly inlined + // Test that virtual calls on value type receivers are properly inlined @Test @IR(failOn = {ALLOC, LOAD_OF_ANY_KLASS, STORE_OF_ANY_KLASS}) public long test142() { @@ -4143,7 +4143,7 @@ public void test142_verifier() { Asserts.assertEquals(res, testValue2.hash()); } - // Test merging of buffered inline types + // Test merging of buffered value types @Test public Object test144(int i) { if (i == 0) { @@ -4175,7 +4175,7 @@ public void test144_verifier() { return_(); }); - // Test inline type connected to result node + // Test value type connected to result node @Test @IR(failOn = {ALLOC}) public MyValue1 test146(Object obj) { @@ -4223,9 +4223,9 @@ public void test149_verifier() { Asserts.assertEQ(test149(null), null); } - // Test post-parse call devirtualization with inline type receiver + // Test post-parse call devirtualization with value type receiver @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, failOn = {ALLOC_OF_MYVALUE_KLASS}) @IR(failOn = {DYNAMIC_CALL_OF_METHOD, "MyValue2::hash"}, counts = {STATIC_CALL_OF_METHOD, "MyValue2::hash", "= 1"}) @@ -4419,7 +4419,7 @@ public void test155_verifier(RunInfo info) { @NullRestricted final static MyValue1 test157Cache = MyValue1.createWithFieldsInline(rI, 0); - // Test merging buffered inline type from field load with non-buffered inline type + // Test merging buffered value type from field load with non-buffered value type @Test public MyValue1 test157(long val) { return (val == 0L) ? test157Cache : MyValue1.createWithFieldsInline(rI, val); @@ -4476,10 +4476,10 @@ value static class UniqueValueSubClass extends AbstractValueClassSingleSubclass @Test public void testUniqueConcreteValueSubKlass(boolean flag) { - // C2 should recognize that even though we do not know the exact layout of the underlying inline type of the + // C2 should recognize that even though we do not know the exact layout of the underlying value type of the // abstract field abstractValueClassSingleSubclass (i.e. cannot scalarize), we only have a unique concrete sub // class from which we know at compile time whether it can be scalarized or not. This unique sub class - // optimization was missing, resulting in a missing InlineTypeNode assertion failure. + // optimization was missing, resulting in a missing ValueTypeNode assertion failure. doNothing(abstractValueClassSingleSubclass, flag ? 23 : 34); } @@ -4704,7 +4704,7 @@ static void testFlatArrayInexactObjectStore_NullRestricted_NonAtomic(Object o, b // The type of 'oArr' is inexact here because we merge two arrays. Since both arrays are flat, 'oArr' is also flat: // Type: flat:narrowoop: java/lang/Object:NotNull * (flat in array)[int:2] // Since the type is inexact, we do not know the exact flat array layout statically and thus need to fall back - // to call "store_unknown_inline_Type()" at runtime where we know the flat array layout + // to call "store_unknown_value_Type()" at runtime where we know the flat array layout oArr[0] = o; } @@ -4719,7 +4719,7 @@ static Object testFlatArrayInexactObjectLoad_NullRestricted_NonAtomic(boolean fl // The type of 'oArr' is inexact here because we merge two arrays. Since both arrays are flat, 'oArr' is also flat: // Type: flat:narrowoop: java/lang/Object:NotNull * (flat in array)[int:2] // Since the type is inexact, we do not know the exact flat array layout statically and thus need to fall back - // to call "load_unknown_inline_Type()" at runtime where we know the flat array layout + // to call "load_unknown_value_Type()" at runtime where we know the flat array layout return oArr[0]; } @@ -4733,7 +4733,7 @@ static void testFlatArrayInexactAbstractValueClassStore_NullRestricted_NonAtomic avArr = SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_NON_ATOMIC; } // Same as testFlatArrayInexactObjectStore_NullRestricted_NonAtomic() but the inexact type is with an abstract value class: - // flat:narrowoop: compiler/valhalla/inlinetypes/TestLWorld$AbstractValueClassWithByte:NotNull * (flat in array)[int:2] + // flat:narrowoop: compiler/valhalla/valuetypes/TestLWorld$AbstractValueClassWithByte:NotNull * (flat in array)[int:2] avArr[0] = abstractValueClassWithByte; } @@ -4746,7 +4746,7 @@ static AbstractValueClassWithByte testFlatArrayInexactAbstractValueClassLoad_Nul avArr = SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_NON_ATOMIC; } // Same as testFlatArrayInexactObjectLoad_NullRestricted_NonAtomic() but the inexact type is with an abstract value class: - // flat:narrowoop: compiler/valhalla/inlinetypes/TestLWorld$AbstractValueClassWithByte:NotNull * (flat in array)[int:2] + // flat:narrowoop: compiler/valhalla/valuetypes/TestLWorld$AbstractValueClassWithByte:NotNull * (flat in array)[int:2] return avArr[0]; } @@ -4794,7 +4794,7 @@ static void testFlatArrayInexactObjectStore_NullRestricted_Atomic(Object o, bool // The type of 'oArr' is inexact here because we merge two arrays. Since both arrays are flat, 'oArr' is also flat: // Type: flat:narrowoop: java/lang/Object:NotNull * (flat in array)[int:2] // Since the type is inexact, we do not know the exact flat array layout statically and thus need to fall back - // to call "store_unknown_inline_Type()" at runtime where we know the flat array layout + // to call "store_unknown_value_Type()" at runtime where we know the flat array layout oArr[0] = o; } @@ -4809,7 +4809,7 @@ static Object testFlatArrayInexactObjectLoad_NullRestricted_Atomic(boolean flag) // The type of 'oArr' is inexact here because we merge two arrays. Since both arrays are flat, 'oArr' is also flat: // Type: flat:narrowoop: java/lang/Object:NotNull * (flat in array)[int:2] // Since the type is inexact, we do not know the exact flat array layout statically and thus need to fall back - // to call "load_unknown_inline_Type()" at runtime where we know the flat array layout + // to call "load_unknown_value_Type()" at runtime where we know the flat array layout return oArr[0]; } @@ -4822,7 +4822,7 @@ static void testFlatArrayInexactAbstractValueClassStore_NullRestricted_Atomic(Ab avArr = SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_ATOMIC; } // Same as testFlatArrayInexactObjectStore_NullRestricted_Atomic() but the inexact type is with an abstract value class: - // flat:narrowoop: compiler/valhalla/inlinetypes/TestLWorld$AbstractValueClassWithByte:NotNull * (flat in array)[int:2] + // flat:narrowoop: compiler/valhalla/valuetypes/TestLWorld$AbstractValueClassWithByte:NotNull * (flat in array)[int:2] avArr[0] = abstractValueClassWithByte; } @@ -4835,7 +4835,7 @@ static AbstractValueClassWithByte testFlatArrayInexactAbstractValueClassLoad_Nul avArr = SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULL_RESTRICTED_ATOMIC; } // Same as testFlatArrayInexactObjectLoad_NullRestricted_Atomic() but the inexact type is with an abstract value class: - // flat:narrowoop: compiler/valhalla/inlinetypes/TestLWorld$AbstractValueClassWithByte:NotNull * (flat in array)[int:2] + // flat:narrowoop: compiler/valhalla/valuetypes/TestLWorld$AbstractValueClassWithByte:NotNull * (flat in array)[int:2] return avArr[0]; } @@ -4883,7 +4883,7 @@ static void testFlatArrayInexactObjectStore_Nullable_Atomic(Object o, boolean fl // The type of 'oArr' is inexact here because we merge two arrays. Since both arrays are flat, 'oArr' is also flat: // Type: flat:narrowoop: java/lang/Object * (flat in array)[int:2] // Since the type is inexact, we do not know the exact flat array layout statically and thus need to fall back - // to call "store_unknown_inline_Type()" at runtime where we know the flat array layout + // to call "store_unknown_value_Type()" at runtime where we know the flat array layout oArr[0] = o; } @@ -4898,7 +4898,7 @@ static Object testFlatArrayInexactObjectLoad_Nullable_Atomic(boolean flag) { // The type of 'oArr' is inexact here because we merge two arrays. Since both arrays are flat, 'oArr' is also flat: // Type: flat:narrowoop: java/lang/Object * (flat in array)[int:2] // Since the type is inexact, we do not know the exact flat array layout statically and thus need to fall back - // to call "load_unknown_inline_Type()" at runtime where we know the flat array layout + // to call "load_unknown_value_Type()" at runtime where we know the flat array layout return oArr[0]; } @@ -4911,7 +4911,7 @@ static void testFlatArrayInexactAbstractValueClassStore_Nullable_Atomic(Abstract avArr = SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULLABLE_ATOMIC; } // Same as testFlatArrayInexactObjectStore_Nullable_Atomic() but the inexact type is with an abstract value class: - // flat:narrowoop: compiler/valhalla/inlinetypes/TestLWorld$AbstractValueClassWithByte * (flat in array)[int:2] + // flat:narrowoop: compiler/valhalla/valuetypes/TestLWorld$AbstractValueClassWithByte * (flat in array)[int:2] avArr[0] = abstractValueClassWithByte; } @@ -4924,7 +4924,7 @@ static AbstractValueClassWithByte testFlatArrayInexactAbstractValueClassLoad_Nul avArr = SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_NULLABLE_ATOMIC; } // Same as testFlatArrayInexactObjectLoad_Nullable_Atomic() but the inexact type is with an abstract value class: - // flat:narrowoop: compiler/valhalla/inlinetypes/TestLWorld$AbstractValueClassWithByte * (flat in array)[int:2] + // flat:narrowoop: compiler/valhalla/valuetypes/TestLWorld$AbstractValueClassWithByte * (flat in array)[int:2] return avArr[0]; } @@ -4996,7 +4996,7 @@ static void testFlatArrayInexactAbstractValueClassStore_Ref(AbstractValueClassWi avArr = SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_REF; } // Same as testFlatArrayInexactObjectStore_Ref() but the inexact type is with an abstract value class: - // narrowoop: compiler/valhalla/inlinetypes/TestLWorld$AbstractValueClassWithByte * [int:2] + // narrowoop: compiler/valhalla/valuetypes/TestLWorld$AbstractValueClassWithByte * [int:2] avArr[0] = abstractValueClassWithByte; } @@ -5009,7 +5009,7 @@ static AbstractValueClassWithByte testFlatArrayInexactAbstractValueClassLoad_Ref avArr = SUB_VALUE_CLASS_WITH_FLOAT_ARRAY_REF; } // Same as testFlatArrayInexactObjectLoad_Ref() but the inexact type is with an abstract value class: - // narrowoop: compiler/valhalla/inlinetypes/TestLWorld$AbstractValueClassWithByte * [int:2] + // narrowoop: compiler/valhalla/valuetypes/TestLWorld$AbstractValueClassWithByte * [int:2] return avArr[0]; } @@ -5197,7 +5197,7 @@ public Object getter(Object o) { // Verify that the substitutability runtime call is removed if (at least) one of the arguments has a known type @Test @IR(failOn = {ALLOC, STORE_OF_ANY_KLASS, STATIC_CALL_OF_METHOD, "isSubstitutable.*"}) - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, counts = {LOAD, "= 0"}) // Need to load from non-flat 'integerValue' fields public boolean test174(AllPrimitives x, AllPrimitives y) { return getter(x) == getter(y); @@ -5237,7 +5237,7 @@ public void test175_verifier() { // Same as test174 but only one operand has a known type @Test @IR(failOn = {ALLOC, STORE_OF_ANY_KLASS, STATIC_CALL_OF_METHOD, "isSubstitutable.*"}) - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, counts = {LOAD, "= 13"}) // Need to load the fields from 'y' public boolean test176(AllPrimitives x, Object y) { return getter(x) == getter(y); @@ -5263,7 +5263,7 @@ public void test176_verifier() { // Same as above but type of 'y' is only known after loop opts @Test @IR(failOn = {ALLOC, STORE_OF_ANY_KLASS, STATIC_CALL_OF_METHOD, "isSubstitutable.*"}) - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, counts = {LOAD, "= 12"}) // Need to load the fields from 'x' public boolean test177(Object x, AllPrimitives y) { Object val = null; @@ -5760,23 +5760,23 @@ static value class BadCastV4 extends BadCastA2 {} static BadCastV4 v4BadCast = new BadCastV4(); @Test - static void testBadCastToInlineKlass() { + static void testBadCastToValueKlass() { // triggers in do_get_xxx() - // 'a2' is null-free and an abstract value class and thus an InstanceKlass -> cannot cast to InlineKlass + // 'a2' is null-free and an abstract value class and thus an InstanceKlass -> cannot cast to ValueKlass a2BadCast = aBadCast.a2; // C1: trigger in access_field() for ByteCodes::_putfield // C2: triggers in do_set_xxx() // in BadCastV(), we assign 'a' which is null-free and an abstract value class and thus an InstanceKlass - // -> cannot cast to InlineKlass + // -> cannot cast to ValueKlass new BadCastV(); } - @Run(test = "testBadCastToInlineKlass") + @Run(test = "testBadCastToValueKlass") @Warmup(0) - public static void testBadCastToInlineKlass_verifier() { + public static void testBadCastToValueKlass_verifier() { try { - testBadCastToInlineKlass(); + testBadCastToValueKlass(); Asserts.fail("should not reach"); } catch (NullPointerException e) { // expected diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLWorldProfiling.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLWorldProfiling.java similarity index 96% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLWorldProfiling.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLWorldProfiling.java index a45ab06e49c8..0f23146e8b56 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLWorldProfiling.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLWorldProfiling.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.*; import jdk.test.lib.Asserts; @@ -34,7 +34,7 @@ import jdk.internal.vm.annotation.NullRestricted; import static compiler.lib.ir_framework.IRNode.*; -import static compiler.valhalla.inlinetypes.InlineTypes.*; +import static compiler.valhalla.valuetypes.ValueTypes.*; /* * @test @@ -97,7 +97,7 @@ public static void main(String[] args) { "-XX:-TieredCompilation") }; - InlineTypes.getFramework() + ValueTypes.getFramework() .addScenarios(scenarios) .addFlags("-XX:+UnlockDiagnosticVMOptions", "-XX:+IgnoreUnrecognizedVMOptions", "--enable-preview", "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED", @@ -203,9 +203,9 @@ public NonValueClass2(int x) { @Test @IR(applyIfOr = {"UseArrayLoadStoreProfile", "true", "TypeProfileLevel", "= 222"}, - failOn = {LOAD_UNKNOWN_INLINE}) + failOn = {LOAD_UNKNOWN_VALUE}) @IR(applyIfAnd={"UseACmpProfile", "false", "TypeProfileLevel", "!= 222"}, - counts = {LOAD_UNKNOWN_INLINE, "= 1"}) + counts = {LOAD_UNKNOWN_VALUE, "= 1"}) public Object test1(Object[] array) { return array[0]; } @@ -224,9 +224,9 @@ public void test1_verifier(RunInfo info) { @Test @IR(applyIfOr = {"UseArrayLoadStoreProfile", "true", "TypeProfileLevel", "= 222"}, - failOn = {LOAD_UNKNOWN_INLINE}) + failOn = {LOAD_UNKNOWN_VALUE}) @IR(applyIfAnd = {"UseArrayLoadStoreProfile", "false", "TypeProfileLevel", "!= 222"}, - counts = {LOAD_UNKNOWN_INLINE, "= 1"}) + counts = {LOAD_UNKNOWN_VALUE, "= 1"}) public Object test2(Object[] array) { return array[0]; } @@ -244,7 +244,7 @@ public void test2_verifier(RunInfo info) { } @Test - @IR(counts = {LOAD_UNKNOWN_INLINE, "= 1"}) + @IR(counts = {LOAD_UNKNOWN_VALUE, "= 1"}) public Object test3(Object[] array) { return array[0]; } @@ -260,9 +260,9 @@ public void test3_verifier() { @Test @IR(applyIf = {"UseArrayLoadStoreProfile", "true"}, - failOn = {LOAD_UNKNOWN_INLINE}) + failOn = {LOAD_UNKNOWN_VALUE}) @IR(applyIf = {"UseArrayLoadStoreProfile", "false"}, - counts = {LOAD_UNKNOWN_INLINE, "= 1"}) + counts = {LOAD_UNKNOWN_VALUE, "= 1"}) public Object test4(Object[] array) { return array[0]; } @@ -282,7 +282,7 @@ public void test4_verifier(RunInfo info) { } @Test - @IR(counts = {LOAD_UNKNOWN_INLINE, "= 1"}) + @IR(counts = {LOAD_UNKNOWN_VALUE, "= 1"}) public Object test5(Object[] array) { return array[0]; } @@ -402,9 +402,9 @@ public void test8_verifier(RunInfo info) { @Test @IR(applyIfOr = {"UseArrayLoadStoreProfile", "true", "TypeProfileLevel", "= 222"}, - failOn = {STORE_UNKNOWN_INLINE}) + failOn = {STORE_UNKNOWN_VALUE}) @IR(applyIfAnd = {"UseArrayLoadStoreProfile", "false", "TypeProfileLevel", "!= 222"}, - counts = {STORE_UNKNOWN_INLINE, "= 1"}) + counts = {STORE_UNKNOWN_VALUE, "= 1"}) public void test9(Object[] array, Object v) { array[0] = v; } @@ -418,9 +418,9 @@ public void test9_verifier() { @Test @IR(applyIfOr = {"UseArrayLoadStoreProfile", "true", "TypeProfileLevel", "= 222"}, - failOn = {STORE_UNKNOWN_INLINE}) + failOn = {STORE_UNKNOWN_VALUE}) @IR(applyIfAnd = {"UseArrayLoadStoreProfile", "false", "TypeProfileLevel", "!= 222"}, - counts = {STORE_UNKNOWN_INLINE, "= 1"}) + counts = {STORE_UNKNOWN_VALUE, "= 1"}) public void test10(Object[] array, Object v) { array[0] = v; } @@ -432,7 +432,7 @@ public void test10_verifier() { } @Test - @IR(counts = {STORE_UNKNOWN_INLINE, "= 1"}) + @IR(counts = {STORE_UNKNOWN_VALUE, "= 1"}) public void test11(Object[] array, Object v) { array[0] = v; } @@ -446,9 +446,9 @@ public void test11_verifier() { @Test @IR(applyIf = {"UseArrayLoadStoreProfile", "true"}, - failOn = {STORE_UNKNOWN_INLINE}) + failOn = {STORE_UNKNOWN_VALUE}) @IR(applyIf = {"UseArrayLoadStoreProfile", "false"}, - counts = {STORE_UNKNOWN_INLINE, "= 1"}) + counts = {STORE_UNKNOWN_VALUE, "= 1"}) public void test12(Object[] array, Object v) { array[0] = v; } @@ -461,7 +461,7 @@ public void test12_verifier() { } @Test - @IR(counts = {STORE_UNKNOWN_INLINE, "= 1"}) + @IR(counts = {STORE_UNKNOWN_VALUE, "= 1"}) public void test13(Object[] array, Object v) { array[0] = v; } @@ -519,9 +519,9 @@ static value class NotFlattenable { @Test @IR(applyIfOr = {"UseArrayLoadStoreProfile", "true", "TypeProfileLevel", "= 222"}, counts = {NULL_CHECK_TRAP, "= 2"}, - failOn = {STORE_UNKNOWN_INLINE}) + failOn = {STORE_UNKNOWN_VALUE}) @IR(applyIfAnd = {"UseArrayLoadStoreProfile", "false", "TypeProfileLevel", "!= 222"}, - counts = {NULL_CHECK_TRAP, "= 2", STORE_UNKNOWN_INLINE, "= 1"}) + counts = {NULL_CHECK_TRAP, "= 2", STORE_UNKNOWN_VALUE, "= 1"}) public void test15(Object[] array, Object v) { array[0] = v; } @@ -541,9 +541,9 @@ public void test15_verifier() { @Test @IR(applyIf = {"UseArrayLoadStoreProfile", "true"}, counts = {NULL_CHECK_TRAP, "= 2"}, - failOn = {STORE_UNKNOWN_INLINE}) + failOn = {STORE_UNKNOWN_VALUE}) @IR(applyIf = {"UseArrayLoadStoreProfile", "false"}, - counts = {NULL_CHECK_TRAP, "= 2", STORE_UNKNOWN_INLINE, "= 1"}) + counts = {NULL_CHECK_TRAP, "= 2", STORE_UNKNOWN_VALUE, "= 1"}) public void test16(Object[] array, Object v) { array[0] = v; } @@ -564,9 +564,9 @@ public void test16_verifier() { @Test @IR(applyIf = {"UseArrayLoadStoreProfile", "true"}, counts = {NULL_CHECK_TRAP, "= 1"}, - failOn = {STORE_UNKNOWN_INLINE}) + failOn = {STORE_UNKNOWN_VALUE}) @IR(applyIf = {"UseArrayLoadStoreProfile", "false"}, - counts = {NULL_CHECK_TRAP, "= 2", STORE_UNKNOWN_INLINE, "= 1"}) + counts = {NULL_CHECK_TRAP, "= 2", STORE_UNKNOWN_VALUE, "= 1"}) public void test17(Object[] array, Object v) { array[0] = v; } @@ -587,9 +587,9 @@ public void test18_helper(Object[] array, Object v) { @Test @IR(applyIf = {"UseArrayLoadStoreProfile", "true"}, counts = {NULL_CHECK_TRAP, "= 1"}, - failOn = {STORE_UNKNOWN_INLINE}) + failOn = {STORE_UNKNOWN_VALUE}) @IR(applyIf = {"UseArrayLoadStoreProfile", "false"}, - counts = {NULL_CHECK_TRAP, "= 2", STORE_UNKNOWN_INLINE, "= 1"}) + counts = {NULL_CHECK_TRAP, "= 2", STORE_UNKNOWN_VALUE, "= 1"}) public Object test18(Object[] array, Object v1) { Object v2 = array[0]; test18_helper(array, v1); @@ -610,9 +610,9 @@ public void test18_verifier() { @Test @IR(applyIf = {"UseArrayLoadStoreProfile", "true"}, - failOn = {LOAD_UNKNOWN_INLINE}) + failOn = {LOAD_UNKNOWN_VALUE}) @IR(applyIf = {"UseArrayLoadStoreProfile", "false"}, - counts = {LOAD_UNKNOWN_INLINE, "= 1"}) + counts = {LOAD_UNKNOWN_VALUE, "= 1"}) public Object test19(Object[] array) { return array[0]; } @@ -628,9 +628,9 @@ public void test19_verifier() { @Test @IR(applyIf = {"UseArrayLoadStoreProfile", "true"}, - failOn = {STORE_UNKNOWN_INLINE}) + failOn = {STORE_UNKNOWN_VALUE}) @IR(applyIf = {"UseArrayLoadStoreProfile", "false"}, - counts = {STORE_UNKNOWN_INLINE, "= 1"}) + counts = {STORE_UNKNOWN_VALUE, "= 1"}) public void test20(Object[] array, Object o) { array[0] = o; } diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLateInlineSharedInlineType.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLateInlineSharedValueType.java similarity index 87% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLateInlineSharedInlineType.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLateInlineSharedValueType.java index c8846c913cff..00c530aa2032 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLateInlineSharedInlineType.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLateInlineSharedValueType.java @@ -32,13 +32,13 @@ * ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -public value class TestLateInlineSharedInlineType { +public value class TestLateInlineSharedValueType { static final MethodHandle MH1; static final MethodHandle MH2; static volatile Object vSink; @@ -53,17 +53,17 @@ public Integer getInteger() { static { try { - MH1 = MethodHandles.lookup().findVirtual(TestLateInlineSharedInlineType.class, "getInteger", MethodType.methodType(Integer.class)); - MH2 = MH1.asType(MethodType.methodType(Object.class, TestLateInlineSharedInlineType.class)); + MH1 = MethodHandles.lookup().findVirtual(TestLateInlineSharedValueType.class, "getInteger", MethodType.methodType(Integer.class)); + MH2 = MH1.asType(MethodType.methodType(Object.class, TestLateInlineSharedValueType.class)); } catch (ReflectiveOperationException e) { throw new ExceptionInInitializerError(e); } } // Below tests all trigger the same bug but with slightly different failure modes: - // Field 'integer' is represented by a (shared) InlineTypeNode and buffered on the + // Field 'integer' is represented by a (shared) ValueTypeNode and buffered on the // first store to sink. Late MH inlining updates that node's oop input in-place to - // a newly created, later buffer. InlineTypeNode::Ideal() then removes the first + // a newly created, later buffer. ValueTypeNode::Ideal() then removes the first // buffer as redundant re-allocation and rewires an earlier use to the later buffer. // We assert with "Bad immediate dominator info." when walking the dominator chain @@ -90,7 +90,7 @@ void test3() throws Throwable { public static void main(String[] args) throws Throwable { for (int i = 0; i < 50_000; i++) { - TestLateInlineSharedInlineType test = new TestLateInlineSharedInlineType(); + TestLateInlineSharedValueType test = new TestLateInlineSharedValueType(); test.test1(); test.test2(); test.test3(); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLateInliningIncorrectArgs.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLateInliningIncorrectArgs.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLateInliningIncorrectArgs.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLateInliningIncorrectArgs.java index 5a35909a4fba..98ed34f972a3 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLateInliningIncorrectArgs.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLateInliningIncorrectArgs.java @@ -28,7 +28,7 @@ * @run main/othervm -XX:-BackgroundCompilation -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; public class TestLateInliningIncorrectArgs { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLoadRefinedArrayKlass.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLoadRefinedArrayKlass.java similarity index 99% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLoadRefinedArrayKlass.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLoadRefinedArrayKlass.java index 83606535f359..8c34485ea6d9 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLoadRefinedArrayKlass.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLoadRefinedArrayKlass.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.lang.reflect.Array; import java.util.Arrays; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLoadingDefaultRefinedArrayKlass.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLoadingDefaultRefinedArrayKlass.java similarity index 93% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLoadingDefaultRefinedArrayKlass.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLoadingDefaultRefinedArrayKlass.java index ec8f1a788909..ec4e96997354 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLoadingDefaultRefinedArrayKlass.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLoadingDefaultRefinedArrayKlass.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.lang.reflect.Array; import java.util.Arrays; @@ -42,18 +42,18 @@ * @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 - * compiler.valhalla.inlinetypes.TestLoadingDefaultRefinedArrayKlass + * compiler.valhalla.valuetypes.TestLoadingDefaultRefinedArrayKlass * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI * -Xbatch -XX:CompileCommand=dontinline,*TestLoadingDefaultRefinedArrayKlass::test* * -XX:+UseArrayFlattening -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening - * compiler.valhalla.inlinetypes.TestLoadingDefaultRefinedArrayKlass + * compiler.valhalla.valuetypes.TestLoadingDefaultRefinedArrayKlass * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xbatch -XX:CompileCommand=dontinline,*TestLoadingDefaultRefinedArrayKlass::test* * -XX:-UseArrayFlattening - * compiler.valhalla.inlinetypes.TestLoadingDefaultRefinedArrayKlass + * compiler.valhalla.valuetypes.TestLoadingDefaultRefinedArrayKlass * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xcomp -XX:CompileCommand=compileonly,*TestLoadingDefaultRefinedArrayKlass::test* -XX:-TieredCompilation - * compiler.valhalla.inlinetypes.TestLoadingDefaultRefinedArrayKlass + * compiler.valhalla.valuetypes.TestLoadingDefaultRefinedArrayKlass */ public class TestLoadingDefaultRefinedArrayKlass { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLoopUnswitchingWithFlatArrayCheck.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLoopUnswitchingWithFlatArrayCheck.java similarity index 93% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLoopUnswitchingWithFlatArrayCheck.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLoopUnswitchingWithFlatArrayCheck.java index f91d82ab6f5b..dc280929a065 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestLoopUnswitchingWithFlatArrayCheck.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLoopUnswitchingWithFlatArrayCheck.java @@ -26,10 +26,10 @@ * @bug 8275276 * @summary Test loop unswitching with flat array checks. * @enablePreview - * @run main/othervm -Xcomp -XX:CompileCommand=compileonly,TestLoopUnswitchingWithFlatArrayCheck::test compiler.valhalla.inlinetypes.TestLoopUnswitchingWithFlatArrayCheck + * @run main/othervm -Xcomp -XX:CompileCommand=compileonly,TestLoopUnswitchingWithFlatArrayCheck::test compiler.valhalla.valuetypes.TestLoopUnswitchingWithFlatArrayCheck */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; public class TestLoopUnswitchingWithFlatArrayCheck { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMakeFromOopReturnValue.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMakeFromOopReturnValue.java similarity index 93% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMakeFromOopReturnValue.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMakeFromOopReturnValue.java index c45a3f4a8dc2..80abe153cc8a 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMakeFromOopReturnValue.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMakeFromOopReturnValue.java @@ -21,17 +21,17 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; /* * @test * @bug 8380434 - * @summary When trying to predict a virtual call that returns an inline type, + * @summary When trying to predict a virtual call that returns a value type, * we want to make sure to both branches (inlined call and dynamic call) - * result in an InlineType so that we do not accidentally try to use - * an unbuffered InlineType as an oop. + * result in a ValueType so that we do not accidentally try to use + * an unbuffered ValueType as an oop. * @library /test/lib / * @enablePreview * @run main/othervm -XX:+UnlockExperimentalVMOptions diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMarkWordLoadIdealization.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMarkWordLoadIdealization.java similarity index 87% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMarkWordLoadIdealization.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMarkWordLoadIdealization.java index e5a9e5674329..f9ea8fb6fa73 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMarkWordLoadIdealization.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMarkWordLoadIdealization.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.*; import jdk.internal.misc.Unsafe; @@ -47,7 +47,7 @@ public class TestMarkWordLoadIdealization { // initialized by TestFramework first. static class WB { static final long MARK_WORD_OFFSET = WhiteBox.getWhiteBox().getMarkWordOffset(); - static final long INLINE_TYPE_PATTERN = WhiteBox.getWhiteBox().getInlineTypePattern(); + static final long VALUE_TYPE_PATTERN = WhiteBox.getWhiteBox().getValueTypePattern(); static final long NULL_FREE_ARRAY_BIT_IN_PLACE = WhiteBox.getWhiteBox().getNullFreeArrayBitInPlace(); static final long FLAT_ARRAY_BIT_IN_PLACE = WhiteBox.getWhiteBox().getFlatArrayBitInPlace(); } @@ -70,14 +70,14 @@ public static void main(String[] args) { @Test @IR(failOn = IRNode.LOAD_L) - public static boolean testInlineTypePatternBitLoadNegativeIdealization() { - return (UNSAFE.getLong(IDENTITY_OBJECT, WB.MARK_WORD_OFFSET) & WB.INLINE_TYPE_PATTERN) != 0L; + public static boolean testValueTypePatternBitLoadNegativeIdealization() { + return (UNSAFE.getLong(IDENTITY_OBJECT, WB.MARK_WORD_OFFSET) & WB.VALUE_TYPE_PATTERN) != 0L; } @Test @IR(failOn = IRNode.LOAD_L) - public static boolean testInlineTypePatternBitLoadPositiveIdealization() { - return (UNSAFE.getLong(VALUE_OBJECT, WB.MARK_WORD_OFFSET) & WB.INLINE_TYPE_PATTERN) != 0L; + public static boolean testValueTypePatternBitLoadPositiveIdealization() { + return (UNSAFE.getLong(VALUE_OBJECT, WB.MARK_WORD_OFFSET) & WB.VALUE_TYPE_PATTERN) != 0L; } @Test @@ -104,15 +104,15 @@ public static boolean testFlatArrayBitLoadPositiveIdealization() { return (UNSAFE.getLong(VALUE_OBJECT_ARRAY, WB.MARK_WORD_OFFSET) & WB.FLAT_ARRAY_BIT_IN_PLACE) != 0L; } - @Run(test = {"testInlineTypePatternBitLoadNegativeIdealization", - "testInlineTypePatternBitLoadPositiveIdealization", + @Run(test = {"testValueTypePatternBitLoadNegativeIdealization", + "testValueTypePatternBitLoadPositiveIdealization", "testNullFreeArrayBitLoadNegativeIdealization", "testNullFreeArrayBitLoadPositiveIdealization", "testFlatArrayBitLoadNegativeIdealization", "testFlatArrayBitLoadPositiveIdealization"}) void run() { - Asserts.assertFalse(testInlineTypePatternBitLoadNegativeIdealization()); - Asserts.assertTrue(testInlineTypePatternBitLoadPositiveIdealization()); + Asserts.assertFalse(testValueTypePatternBitLoadNegativeIdealization()); + Asserts.assertTrue(testValueTypePatternBitLoadPositiveIdealization()); Asserts.assertFalse(testNullFreeArrayBitLoadNegativeIdealization()); Asserts.assertTrue(testNullFreeArrayBitLoadPositiveIdealization()); Asserts.assertFalse(testFlatArrayBitLoadNegativeIdealization()); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMeetingAryPtr.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMeetingAryPtr.java similarity index 95% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMeetingAryPtr.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMeetingAryPtr.java index 727a17f379e7..edd388c2833d 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMeetingAryPtr.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMeetingAryPtr.java @@ -29,11 +29,11 @@ * java.base/jdk.internal.vm.annotation * @enablePreview * @run main/othervm -Xcomp -XX:CompileOnly=*TestMeetingAryPtr*::test* -XX:+UnlockDiagnosticVMOptions -XX:+StressCCP - * -XX:RepeatCompilation=100 compiler.valhalla.inlinetypes.TestMeetingAryPtr - * @run main compiler.valhalla.inlinetypes.TestMeetingAryPtr + * -XX:RepeatCompilation=100 compiler.valhalla.valuetypes.TestMeetingAryPtr + * @run main compiler.valhalla.valuetypes.TestMeetingAryPtr */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.value.ValueClass; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMemBars.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMemBars.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMemBars.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMemBars.java index ce88460ae199..47ca45325e06 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMemBars.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMemBars.java @@ -29,10 +29,10 @@ * @enablePreview * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation - * @run main/othervm -Xbatch compiler.valhalla.inlinetypes.TestMemBars + * @run main/othervm -Xbatch compiler.valhalla.valuetypes.TestMemBars */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.value.ValueClass; import jdk.internal.vm.annotation.NullRestricted; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMethodHandles.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMethodHandles.java similarity index 95% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMethodHandles.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMethodHandles.java index 150e0baaedec..35b745a3e21d 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMethodHandles.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMethodHandles.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.*; import jdk.test.lib.Asserts; @@ -36,17 +36,17 @@ import static compiler.lib.ir_framework.IRNode.ALLOC_ARRAY_OF_MYVALUE_KLASS; import static compiler.lib.ir_framework.IRNode.ALLOC_OF_MYVALUE_KLASS; -import static compiler.lib.ir_framework.IRNode.STORE_INLINE_FIELDS; +import static compiler.lib.ir_framework.IRNode.STORE_VALUE_FIELDS; import static compiler.lib.ir_framework.IRNode.STORE_OF_ANY_KLASS; -import static compiler.valhalla.inlinetypes.InlineTypes.*; +import static compiler.valhalla.valuetypes.ValueTypes.*; import static compiler.lib.ir_framework.IRNode.STATIC_CALL; /* * @test * @key randomness - * @summary Test method handle support for inline types + * @summary Test method handle support for value types * @library /test/lib / * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64") * @requires vm.opt.AbortVMOnCompilationFailure != true @@ -60,7 +60,7 @@ /* * @test * @key randomness - * @summary Test method handle support for inline types + * @summary Test method handle support for value types * @library /test/lib / * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64") * @requires vm.opt.AbortVMOnCompilationFailure != true @@ -74,7 +74,7 @@ /* * @test * @key randomness - * @summary Test method handle support for inline types + * @summary Test method handle support for value types * @library /test/lib / * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64") * @requires vm.opt.AbortVMOnCompilationFailure != true @@ -88,7 +88,7 @@ /* * @test * @key randomness - * @summary Test method handle support for inline types + * @summary Test method handle support for value types * @library /test/lib / * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64") * @requires vm.opt.AbortVMOnCompilationFailure != true @@ -102,7 +102,7 @@ /* * @test * @key randomness - * @summary Test method handle support for inline types + * @summary Test method handle support for value types * @library /test/lib / * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64") * @requires vm.opt.AbortVMOnCompilationFailure != true @@ -116,7 +116,7 @@ /* * @test * @key randomness - * @summary Test method handle support for inline types + * @summary Test method handle support for value types * @library /test/lib / * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64") * @requires vm.opt.AbortVMOnCompilationFailure != true @@ -130,7 +130,7 @@ /* * @test * @key randomness - * @summary Test method handle support for inline types + * @summary Test method handle support for value types * @library /test/lib / * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64") * @requires vm.opt.AbortVMOnCompilationFailure != true @@ -237,14 +237,14 @@ public TestMethodHandles() { } public static void main(String[] args) { - Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; + Scenario[] scenarios = ValueTypes.DEFAULT_SCENARIOS; // Prevent inlining through MethodHandle linkTo adapters to stress the calling convention scenarios[2].addFlags("-DVerifyIR=false", "-XX:CompileCommand=dontinline,java.lang.invoke.DirectMethodHandle::internalMemberName"); scenarios[4].addFlags("-XX:CompileCommand=dontinline,java.lang.invoke.DirectMethodHandle::internalMemberName"); - InlineTypes.getFramework() + ValueTypes.getFramework() .addScenarios(scenarios[Integer.parseInt(args[0])]) .addFlags("-XX:CompileCommand=inline,java.lang.invoke.MethodHandleImpl::*") .addFlags("-XX:CompileCommand=inline,java.lang.invoke.LambdaForm*::*") @@ -268,9 +268,9 @@ MyValue3 test1_target() { static final MethodHandle test1_mh; @Test - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, failOn = {ALLOC_OF_MYVALUE_KLASS, STORE_OF_ANY_KLASS, STATIC_CALL}) - @IR(applyIf = {"InlineTypeReturnedAsFields", "false"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "false"}, counts = {ALLOC_OF_MYVALUE_KLASS, "= 1"}) // TODO: JDK-8380875 // STORE_OF_ANY_KLASS, "= 14"}) @@ -367,7 +367,7 @@ public void test4_verifier() throws Throwable { Asserts.assertEQ(i, test4_vt.x); } - // Test method handle call with inline type argument + // Test method handle call with value type argument public int test5_target(MyValue1 vt) { return vt.x; } @@ -415,8 +415,8 @@ boolean test6_test() { static final MethodHandle test6_mh; @Test - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, - failOn = {ALLOC_OF_MYVALUE_KLASS, ALLOC_ARRAY_OF_MYVALUE_KLASS, STORE_OF_ANY_KLASS, STORE_INLINE_FIELDS}) + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, + failOn = {ALLOC_OF_MYVALUE_KLASS, ALLOC_ARRAY_OF_MYVALUE_KLASS, STORE_OF_ANY_KLASS, STORE_VALUE_FIELDS}) public MyValue3 test6() throws Throwable { return (MyValue3)test6_mh.invokeExact(this); } @@ -535,8 +535,8 @@ boolean test9_test2() { static final MethodHandle test9_mh; @Test - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, - failOn = {ALLOC_OF_MYVALUE_KLASS, ALLOC_ARRAY_OF_MYVALUE_KLASS, STORE_OF_ANY_KLASS, STORE_INLINE_FIELDS}) + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, + failOn = {ALLOC_OF_MYVALUE_KLASS, ALLOC_ARRAY_OF_MYVALUE_KLASS, STORE_OF_ANY_KLASS, STORE_VALUE_FIELDS}) public MyValue3 test9() throws Throwable { return (MyValue3)test9_mh.invokeExact(this); } @@ -621,7 +621,7 @@ static boolean test11_test() { static final MethodHandle test11_mh; static MethodHandle test11_mh2; - // Check that a buffered inline type returned by a compiled lambda form + // Check that a buffered value type returned by a compiled lambda form // is properly handled by the caller. @Test public long test11() throws Throwable { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMismatchHandling.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMismatchHandling.java similarity index 94% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMismatchHandling.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMismatchHandling.java index 6a5bb8290a9c..1a0a56e26e69 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMismatchHandling.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMismatchHandling.java @@ -33,34 +33,34 @@ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:-Inline -XX:-InlineAccessors -XX:-UseBimorphicInlining -XX:-UseCHA -XX:-UseTypeProfile - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestMismatchHandling::test* - * compiler.valhalla.inlinetypes.TestMismatchHandling + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestMismatchHandling::test* + * compiler.valhalla.valuetypes.TestMismatchHandling * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:-Inline -XX:-InlineAccessors -XX:-UseBimorphicInlining -XX:-UseCHA -XX:-UseTypeProfile * -XX:CompileCommand=compileonly,*::method - * compiler.valhalla.inlinetypes.TestMismatchHandling + * compiler.valhalla.valuetypes.TestMismatchHandling * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:-Inline -XX:-InlineAccessors -XX:-UseBimorphicInlining -XX:-UseCHA -XX:-UseTypeProfile - * compiler.valhalla.inlinetypes.TestMismatchHandling + * compiler.valhalla.valuetypes.TestMismatchHandling * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:-Inline -XX:-InlineAccessors -XX:-UseBimorphicInlining -XX:-UseCHA -XX:-UseTypeProfile - * -XX:-InlineTypePassFieldsAsArgs - * compiler.valhalla.inlinetypes.TestMismatchHandling + * -XX:-ValueTypePassFieldsAsArgs + * compiler.valhalla.valuetypes.TestMismatchHandling * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:-Inline -XX:-InlineAccessors -XX:-UseBimorphicInlining -XX:-UseCHA -XX:-UseTypeProfile - * -XX:-InlineTypeReturnedAsFields - * compiler.valhalla.inlinetypes.TestMismatchHandling + * -XX:-ValueTypeReturnedAsFields + * compiler.valhalla.valuetypes.TestMismatchHandling * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+DeoptimizeNMethodBarriersALot - * compiler.valhalla.inlinetypes.TestMismatchHandling + * compiler.valhalla.valuetypes.TestMismatchHandling * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * compiler.valhalla.inlinetypes.TestMismatchHandling + * compiler.valhalla.valuetypes.TestMismatchHandling */ // ##################################### WARNING ###################################### @@ -85,7 +85,7 @@ sed -i 's/class MyValue/value class MyValue/g' TestMismatchHandlingGenerator.java */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.lang.reflect.Method; import java.util.ArrayList; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMismatchHandling.jcod b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMismatchHandling.jcod similarity index 83% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMismatchHandling.jcod rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMismatchHandling.jcod index 167ded12f1bc..60041397953b 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMismatchHandling.jcod +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMismatchHandling.jcod @@ -1,11 +1,11 @@ -class compiler/valhalla/inlinetypes/MyValue1Mismatch { +class compiler/valhalla/valuetypes/MyValue1Mismatch { 0xCAFEBABE; 65535; // minor version 72; // version [] { // Constant Pool ; // first element is empty class #2; // #1 - Utf8 "compiler/valhalla/inlinetypes/MyValue1Mismatch"; // #2 + Utf8 "compiler/valhalla/valuetypes/MyValue1Mismatch"; // #2 Field #1 #4; // #3 NameAndType #5 #6; // #4 Utf8 "x"; // #5 @@ -103,15 +103,15 @@ class compiler/valhalla/inlinetypes/MyValue1Mismatch { #19; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/MyValue1Mismatch -class compiler/valhalla/inlinetypes/MyValue2Mismatch { +} // end class compiler/valhalla/valuetypes/MyValue1Mismatch +class compiler/valhalla/valuetypes/MyValue2Mismatch { 0xCAFEBABE; 65535; // minor version 72; // version [] { // Constant Pool ; // first element is empty class #2; // #1 - Utf8 "compiler/valhalla/inlinetypes/MyValue2Mismatch"; // #2 + Utf8 "compiler/valhalla/valuetypes/MyValue2Mismatch"; // #2 Field #1 #4; // #3 NameAndType #5 #6; // #4 Utf8 "x"; // #5 @@ -209,15 +209,15 @@ class compiler/valhalla/inlinetypes/MyValue2Mismatch { #19; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/MyValue2Mismatch -class compiler/valhalla/inlinetypes/MyValue3Mismatch { +} // end class compiler/valhalla/valuetypes/MyValue2Mismatch +class compiler/valhalla/valuetypes/MyValue3Mismatch { 0xCAFEBABE; 65535; // minor version 72; // version [] { // Constant Pool ; // first element is empty class #2; // #1 - Utf8 "compiler/valhalla/inlinetypes/MyValue3Mismatch"; // #2 + Utf8 "compiler/valhalla/valuetypes/MyValue3Mismatch"; // #2 Field #1 #4; // #3 NameAndType #5 #6; // #4 Utf8 "x"; // #5 @@ -315,15 +315,15 @@ class compiler/valhalla/inlinetypes/MyValue3Mismatch { #19; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/MyValue3Mismatch -class compiler/valhalla/inlinetypes/MyValue4Mismatch { +} // end class compiler/valhalla/valuetypes/MyValue3Mismatch +class compiler/valhalla/valuetypes/MyValue4Mismatch { 0xCAFEBABE; 65535; // minor version 72; // version [] { // Constant Pool ; // first element is empty class #2; // #1 - Utf8 "compiler/valhalla/inlinetypes/MyValue4Mismatch"; // #2 + Utf8 "compiler/valhalla/valuetypes/MyValue4Mismatch"; // #2 Field #1 #4; // #3 NameAndType #5 #6; // #4 Utf8 "x"; // #5 @@ -341,7 +341,7 @@ class compiler/valhalla/inlinetypes/MyValue4Mismatch { Utf8 "LineNumberTable"; // #17 Utf8 "verify"; // #18 Utf8 "make"; // #19 - Utf8 "()Lcompiler/valhalla/inlinetypes/MyValue4Mismatch;"; // #20 + Utf8 "()Lcompiler/valhalla/valuetypes/MyValue4Mismatch;"; // #20 Utf8 "SourceFile"; // #21 Utf8 "TestMismatchHandlingGenerator.java"; // #22 } // Constant Pool @@ -448,15 +448,15 @@ class compiler/valhalla/inlinetypes/MyValue4Mismatch { #22; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/MyValue4Mismatch -class compiler/valhalla/inlinetypes/MyValue5Mismatch { +} // end class compiler/valhalla/valuetypes/MyValue4Mismatch +class compiler/valhalla/valuetypes/MyValue5Mismatch { 0xCAFEBABE; 65535; // minor version 72; // version [] { // Constant Pool ; // first element is empty class #2; // #1 - Utf8 "compiler/valhalla/inlinetypes/MyValue5Mismatch"; // #2 + Utf8 "compiler/valhalla/valuetypes/MyValue5Mismatch"; // #2 Field #1 #4; // #3 NameAndType #5 #6; // #4 Utf8 "x"; // #5 @@ -469,14 +469,14 @@ class compiler/valhalla/inlinetypes/MyValue5Mismatch { Utf8 "()V"; // #12 Method #1 #9; // #13 class #15; // #14 - Utf8 "compiler/valhalla/inlinetypes/Verifiable"; // #15 + Utf8 "compiler/valhalla/valuetypes/Verifiable"; // #15 Utf8 "ConstantValue"; // #16 int 0x0000002A; // #17 Utf8 "Code"; // #18 Utf8 "LineNumberTable"; // #19 Utf8 "verify"; // #20 Utf8 "make"; // #21 - Utf8 "()Lcompiler/valhalla/inlinetypes/MyValue5Mismatch;"; // #22 + Utf8 "()Lcompiler/valhalla/valuetypes/MyValue5Mismatch;"; // #22 Utf8 "SourceFile"; // #23 Utf8 "TestMismatchHandlingGenerator.java"; // #24 } // Constant Pool @@ -584,15 +584,15 @@ class compiler/valhalla/inlinetypes/MyValue5Mismatch { #24; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/MyValue5Mismatch -class compiler/valhalla/inlinetypes/MyValue6Mismatch { +} // end class compiler/valhalla/valuetypes/MyValue5Mismatch +class compiler/valhalla/valuetypes/MyValue6Mismatch { 0xCAFEBABE; 65535; // minor version 72; // version [] { // Constant Pool ; // first element is empty class #2; // #1 - Utf8 "compiler/valhalla/inlinetypes/MyValue6Mismatch"; // #2 + Utf8 "compiler/valhalla/valuetypes/MyValue6Mismatch"; // #2 Field #1 #4; // #3 NameAndType #5 #6; // #4 Utf8 "x"; // #5 @@ -605,14 +605,14 @@ class compiler/valhalla/inlinetypes/MyValue6Mismatch { Utf8 "()V"; // #12 Method #1 #9; // #13 class #15; // #14 - Utf8 "compiler/valhalla/inlinetypes/Verifiable"; // #15 + Utf8 "compiler/valhalla/valuetypes/Verifiable"; // #15 Utf8 "ConstantValue"; // #16 int 0x0000002A; // #17 Utf8 "Code"; // #18 Utf8 "LineNumberTable"; // #19 Utf8 "verify"; // #20 Utf8 "make"; // #21 - Utf8 "()Lcompiler/valhalla/inlinetypes/MyValue6Mismatch;"; // #22 + Utf8 "()Lcompiler/valhalla/valuetypes/MyValue6Mismatch;"; // #22 Utf8 "SourceFile"; // #23 Utf8 "TestMismatchHandlingGenerator.java"; // #24 } // Constant Pool @@ -720,15 +720,15 @@ class compiler/valhalla/inlinetypes/MyValue6Mismatch { #24; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/MyValue6Mismatch -class compiler/valhalla/inlinetypes/MyValue7Mismatch { +} // end class compiler/valhalla/valuetypes/MyValue6Mismatch +class compiler/valhalla/valuetypes/MyValue7Mismatch { 0xCAFEBABE; 65535; // minor version 72; // version [] { // Constant Pool ; // first element is empty class #2; // #1 - Utf8 "compiler/valhalla/inlinetypes/MyValue7Mismatch"; // #2 + Utf8 "compiler/valhalla/valuetypes/MyValue7Mismatch"; // #2 Field #1 #4; // #3 NameAndType #5 #6; // #4 Utf8 "x"; // #5 @@ -826,15 +826,15 @@ class compiler/valhalla/inlinetypes/MyValue7Mismatch { #19; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/MyValue7Mismatch -class compiler/valhalla/inlinetypes/Verifiable { +} // end class compiler/valhalla/valuetypes/MyValue7Mismatch +class compiler/valhalla/valuetypes/Verifiable { 0xCAFEBABE; 65535; // minor version 72; // version [] { // Constant Pool ; // first element is empty class #2; // #1 - Utf8 "compiler/valhalla/inlinetypes/Verifiable"; // #2 + Utf8 "compiler/valhalla/valuetypes/Verifiable"; // #2 class #4; // #3 Utf8 "java/lang/Object"; // #4 Utf8 "verify"; // #5 @@ -868,8 +868,8 @@ class compiler/valhalla/inlinetypes/Verifiable { #8; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/Verifiable -class compiler/valhalla/inlinetypes/B { +} // end class compiler/valhalla/valuetypes/Verifiable +class compiler/valhalla/valuetypes/B { 0xCAFEBABE; 65535; // minor version 72; // version @@ -878,24 +878,24 @@ class compiler/valhalla/inlinetypes/B { Method #2 #3; // #1 class #4; // #2 NameAndType #5 #6; // #3 - Utf8 "compiler/valhalla/inlinetypes/A"; // #4 + Utf8 "compiler/valhalla/valuetypes/A"; // #4 Utf8 ""; // #5 Utf8 "()V"; // #6 Method #8 #9; // #7 class #10; // #8 NameAndType #11 #6; // #9 - Utf8 "compiler/valhalla/inlinetypes/MyValue1Mismatch"; // #10 + Utf8 "compiler/valhalla/valuetypes/MyValue1Mismatch"; // #10 Utf8 "verify"; // #11 class #13; // #12 - Utf8 "compiler/valhalla/inlinetypes/B"; // #13 + Utf8 "compiler/valhalla/valuetypes/B"; // #13 Utf8 "Code"; // #14 Utf8 "LineNumberTable"; // #15 Utf8 "method"; // #16 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue1Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue1Mismatch;"; // #17 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue1Mismatch;)Lcompiler/valhalla/valuetypes/MyValue1Mismatch;"; // #17 Utf8 "SourceFile"; // #18 Utf8 "TestMismatchHandlingGenerator.java"; // #19 Utf8 "LoadableDescriptors"; // #20 - Utf8 "Lcompiler/valhalla/inlinetypes/MyValue1Mismatch;"; // #21 + Utf8 "Lcompiler/valhalla/valuetypes/MyValue1Mismatch;"; // #21 } // Constant Pool 0x0020; // access @@ -968,23 +968,23 @@ class compiler/valhalla/inlinetypes/B { 0x00010015; } // end LoadableDescriptors } // Attributes -} // end class compiler/valhalla/inlinetypes/B -class compiler/valhalla/inlinetypes/I3 { +} // end class compiler/valhalla/valuetypes/B +class compiler/valhalla/valuetypes/I3 { 0xCAFEBABE; 65535; // minor version 72; // version [] { // Constant Pool ; // first element is empty class #2; // #1 - Utf8 "compiler/valhalla/inlinetypes/I3"; // #2 + Utf8 "compiler/valhalla/valuetypes/I3"; // #2 class #4; // #3 Utf8 "java/lang/Object"; // #4 Utf8 "method"; // #5 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;"; // #6 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue2Mismatch;)Lcompiler/valhalla/valuetypes/MyValue2Mismatch;"; // #6 Utf8 "SourceFile"; // #7 Utf8 "TestMismatchHandlingGenerator.java"; // #8 Utf8 "LoadableDescriptors"; // #9 - Utf8 "Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;"; // #10 + Utf8 "Lcompiler/valhalla/valuetypes/MyValue2Mismatch;"; // #10 } // Constant Pool 0x0600; // access @@ -1016,25 +1016,25 @@ class compiler/valhalla/inlinetypes/I3 { 0x0001000A; } // end LoadableDescriptors } // Attributes -} // end class compiler/valhalla/inlinetypes/I3 -class compiler/valhalla/inlinetypes/I4 { +} // end class compiler/valhalla/valuetypes/I3 +class compiler/valhalla/valuetypes/I4 { 0xCAFEBABE; 65535; // minor version 72; // version [] { // Constant Pool ; // first element is empty class #2; // #1 - Utf8 "compiler/valhalla/inlinetypes/I4"; // #2 + Utf8 "compiler/valhalla/valuetypes/I4"; // #2 class #4; // #3 Utf8 "java/lang/Object"; // #4 class #6; // #5 - Utf8 "compiler/valhalla/inlinetypes/I3"; // #6 + Utf8 "compiler/valhalla/valuetypes/I3"; // #6 Utf8 "method"; // #7 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;"; // #8 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue2Mismatch;)Lcompiler/valhalla/valuetypes/MyValue2Mismatch;"; // #8 Utf8 "SourceFile"; // #9 Utf8 "TestMismatchHandlingGenerator.java"; // #10 Utf8 "LoadableDescriptors"; // #11 - Utf8 "Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;"; // #12 + Utf8 "Lcompiler/valhalla/valuetypes/MyValue2Mismatch;"; // #12 } // Constant Pool 0x0600; // access @@ -1067,8 +1067,8 @@ class compiler/valhalla/inlinetypes/I4 { 0x0001000C; } // end LoadableDescriptors } // Attributes -} // end class compiler/valhalla/inlinetypes/I4 -class compiler/valhalla/inlinetypes/E { +} // end class compiler/valhalla/valuetypes/I4 +class compiler/valhalla/valuetypes/E { 0xCAFEBABE; 65535; // minor version 72; // version @@ -1083,20 +1083,20 @@ class compiler/valhalla/inlinetypes/E { Method #8 #9; // #7 class #10; // #8 NameAndType #11 #6; // #9 - Utf8 "compiler/valhalla/inlinetypes/MyValue2Mismatch"; // #10 + Utf8 "compiler/valhalla/valuetypes/MyValue2Mismatch"; // #10 Utf8 "verify"; // #11 class #13; // #12 - Utf8 "compiler/valhalla/inlinetypes/E"; // #13 + Utf8 "compiler/valhalla/valuetypes/E"; // #13 class #15; // #14 - Utf8 "compiler/valhalla/inlinetypes/I4"; // #15 + Utf8 "compiler/valhalla/valuetypes/I4"; // #15 Utf8 "Code"; // #16 Utf8 "LineNumberTable"; // #17 Utf8 "method"; // #18 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;"; // #19 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue2Mismatch;)Lcompiler/valhalla/valuetypes/MyValue2Mismatch;"; // #19 Utf8 "SourceFile"; // #20 Utf8 "TestMismatchHandlingGenerator.java"; // #21 Utf8 "LoadableDescriptors"; // #22 - Utf8 "Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;"; // #23 + Utf8 "Lcompiler/valhalla/valuetypes/MyValue2Mismatch;"; // #23 } // Constant Pool 0x0020; // access @@ -1170,8 +1170,8 @@ class compiler/valhalla/inlinetypes/E { 0x00010017; } // end LoadableDescriptors } // Attributes -} // end class compiler/valhalla/inlinetypes/E -class compiler/valhalla/inlinetypes/G { +} // end class compiler/valhalla/valuetypes/E +class compiler/valhalla/valuetypes/G { 0xCAFEBABE; 65535; // minor version 72; // version @@ -1186,22 +1186,22 @@ class compiler/valhalla/inlinetypes/G { Method #8 #9; // #7 class #10; // #8 NameAndType #11 #6; // #9 - Utf8 "compiler/valhalla/inlinetypes/MyValue2Mismatch"; // #10 + Utf8 "compiler/valhalla/valuetypes/MyValue2Mismatch"; // #10 Utf8 "verify"; // #11 class #13; // #12 - Utf8 "compiler/valhalla/inlinetypes/G"; // #13 + Utf8 "compiler/valhalla/valuetypes/G"; // #13 class #15; // #14 - Utf8 "compiler/valhalla/inlinetypes/I2"; // #15 + Utf8 "compiler/valhalla/valuetypes/I2"; // #15 class #17; // #16 - Utf8 "compiler/valhalla/inlinetypes/I4"; // #17 + Utf8 "compiler/valhalla/valuetypes/I4"; // #17 Utf8 "Code"; // #18 Utf8 "LineNumberTable"; // #19 Utf8 "method"; // #20 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;"; // #21 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue2Mismatch;)Lcompiler/valhalla/valuetypes/MyValue2Mismatch;"; // #21 Utf8 "SourceFile"; // #22 Utf8 "TestMismatchHandlingGenerator.java"; // #23 Utf8 "LoadableDescriptors"; // #24 - Utf8 "Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;"; // #25 + Utf8 "Lcompiler/valhalla/valuetypes/MyValue2Mismatch;"; // #25 } // Constant Pool 0x0020; // access @@ -1276,8 +1276,8 @@ class compiler/valhalla/inlinetypes/G { 0x00010019; } // end LoadableDescriptors } // Attributes -} // end class compiler/valhalla/inlinetypes/G -class compiler/valhalla/inlinetypes/J { +} // end class compiler/valhalla/valuetypes/G +class compiler/valhalla/valuetypes/J { 0xCAFEBABE; 65535; // minor version 72; // version @@ -1292,18 +1292,18 @@ class compiler/valhalla/inlinetypes/J { Method #8 #9; // #7 class #10; // #8 NameAndType #11 #6; // #9 - Utf8 "compiler/valhalla/inlinetypes/MyValue3Mismatch"; // #10 + Utf8 "compiler/valhalla/valuetypes/MyValue3Mismatch"; // #10 Utf8 "verify"; // #11 class #13; // #12 - Utf8 "compiler/valhalla/inlinetypes/J"; // #13 + Utf8 "compiler/valhalla/valuetypes/J"; // #13 Utf8 "Code"; // #14 Utf8 "LineNumberTable"; // #15 Utf8 "method"; // #16 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue3Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue3Mismatch;"; // #17 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue3Mismatch;)Lcompiler/valhalla/valuetypes/MyValue3Mismatch;"; // #17 Utf8 "SourceFile"; // #18 Utf8 "TestMismatchHandlingGenerator.java"; // #19 Utf8 "LoadableDescriptors"; // #20 - Utf8 "Lcompiler/valhalla/inlinetypes/MyValue3Mismatch;"; // #21 + Utf8 "Lcompiler/valhalla/valuetypes/MyValue3Mismatch;"; // #21 } // Constant Pool 0x0020; // access @@ -1376,8 +1376,8 @@ class compiler/valhalla/inlinetypes/J { 0x00010015; } // end LoadableDescriptors } // Attributes -} // end class compiler/valhalla/inlinetypes/J -class compiler/valhalla/inlinetypes/K { +} // end class compiler/valhalla/valuetypes/J +class compiler/valhalla/valuetypes/K { 0xCAFEBABE; 65535; // minor version 72; // version @@ -1386,24 +1386,24 @@ class compiler/valhalla/inlinetypes/K { Method #2 #3; // #1 class #4; // #2 NameAndType #5 #6; // #3 - Utf8 "compiler/valhalla/inlinetypes/J"; // #4 + Utf8 "compiler/valhalla/valuetypes/J"; // #4 Utf8 ""; // #5 Utf8 "()V"; // #6 Method #8 #9; // #7 class #10; // #8 NameAndType #11 #6; // #9 - Utf8 "compiler/valhalla/inlinetypes/MyValue3Mismatch"; // #10 + Utf8 "compiler/valhalla/valuetypes/MyValue3Mismatch"; // #10 Utf8 "verify"; // #11 class #13; // #12 - Utf8 "compiler/valhalla/inlinetypes/K"; // #13 + Utf8 "compiler/valhalla/valuetypes/K"; // #13 Utf8 "Code"; // #14 Utf8 "LineNumberTable"; // #15 Utf8 "method"; // #16 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue3Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue3Mismatch;"; // #17 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue3Mismatch;)Lcompiler/valhalla/valuetypes/MyValue3Mismatch;"; // #17 Utf8 "SourceFile"; // #18 Utf8 "TestMismatchHandlingGenerator.java"; // #19 Utf8 "LoadableDescriptors"; // #20 - Utf8 "Lcompiler/valhalla/inlinetypes/MyValue3Mismatch;"; // #21 + Utf8 "Lcompiler/valhalla/valuetypes/MyValue3Mismatch;"; // #21 } // Constant Pool 0x0020; // access @@ -1476,8 +1476,8 @@ class compiler/valhalla/inlinetypes/K { 0x00010015; } // end LoadableDescriptors } // Attributes -} // end class compiler/valhalla/inlinetypes/K -class compiler/valhalla/inlinetypes/L { +} // end class compiler/valhalla/valuetypes/K +class compiler/valhalla/valuetypes/L { 0xCAFEBABE; 65535; // minor version 72; // version @@ -1486,26 +1486,26 @@ class compiler/valhalla/inlinetypes/L { Method #2 #3; // #1 class #4; // #2 NameAndType #5 #6; // #3 - Utf8 "compiler/valhalla/inlinetypes/K"; // #4 + Utf8 "compiler/valhalla/valuetypes/K"; // #4 Utf8 ""; // #5 Utf8 "()V"; // #6 Method #8 #9; // #7 class #10; // #8 NameAndType #11 #6; // #9 - Utf8 "compiler/valhalla/inlinetypes/MyValue3Mismatch"; // #10 + Utf8 "compiler/valhalla/valuetypes/MyValue3Mismatch"; // #10 Utf8 "verify"; // #11 class #13; // #12 - Utf8 "compiler/valhalla/inlinetypes/L"; // #13 + Utf8 "compiler/valhalla/valuetypes/L"; // #13 class #15; // #14 - Utf8 "compiler/valhalla/inlinetypes/I5"; // #15 + Utf8 "compiler/valhalla/valuetypes/I5"; // #15 Utf8 "Code"; // #16 Utf8 "LineNumberTable"; // #17 Utf8 "method"; // #18 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue3Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue3Mismatch;"; // #19 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue3Mismatch;)Lcompiler/valhalla/valuetypes/MyValue3Mismatch;"; // #19 Utf8 "SourceFile"; // #20 Utf8 "TestMismatchHandlingGenerator.java"; // #21 Utf8 "LoadableDescriptors"; // #22 - Utf8 "Lcompiler/valhalla/inlinetypes/MyValue3Mismatch;"; // #23 + Utf8 "Lcompiler/valhalla/valuetypes/MyValue3Mismatch;"; // #23 } // Constant Pool 0x0020; // access @@ -1579,8 +1579,8 @@ class compiler/valhalla/inlinetypes/L { 0x00010017; } // end LoadableDescriptors } // Attributes -} // end class compiler/valhalla/inlinetypes/L -class compiler/valhalla/inlinetypes/P { +} // end class compiler/valhalla/valuetypes/L +class compiler/valhalla/valuetypes/P { 0xCAFEBABE; 65535; // minor version 72; // version @@ -1595,20 +1595,20 @@ class compiler/valhalla/inlinetypes/P { Method #8 #9; // #7 class #10; // #8 NameAndType #11 #6; // #9 - Utf8 "compiler/valhalla/inlinetypes/MyValue7Mismatch"; // #10 + Utf8 "compiler/valhalla/valuetypes/MyValue7Mismatch"; // #10 Utf8 "verify"; // #11 class #13; // #12 - Utf8 "compiler/valhalla/inlinetypes/P"; // #13 + Utf8 "compiler/valhalla/valuetypes/P"; // #13 class #15; // #14 - Utf8 "compiler/valhalla/inlinetypes/I6"; // #15 + Utf8 "compiler/valhalla/valuetypes/I6"; // #15 Utf8 "Code"; // #16 Utf8 "LineNumberTable"; // #17 Utf8 "method"; // #18 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue7Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue7Mismatch;"; // #19 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue7Mismatch;)Lcompiler/valhalla/valuetypes/MyValue7Mismatch;"; // #19 Utf8 "SourceFile"; // #20 Utf8 "TestMismatchHandlingGenerator.java"; // #21 Utf8 "LoadableDescriptors"; // #22 - Utf8 "Lcompiler/valhalla/inlinetypes/MyValue7Mismatch;"; // #23 + Utf8 "Lcompiler/valhalla/valuetypes/MyValue7Mismatch;"; // #23 } // Constant Pool 0x0020; // access @@ -1682,8 +1682,8 @@ class compiler/valhalla/inlinetypes/P { 0x00010017; } // end LoadableDescriptors } // Attributes -} // end class compiler/valhalla/inlinetypes/P -class compiler/valhalla/inlinetypes/Q { +} // end class compiler/valhalla/valuetypes/P +class compiler/valhalla/valuetypes/Q { 0xCAFEBABE; 65535; // minor version 72; // version @@ -1698,18 +1698,18 @@ class compiler/valhalla/inlinetypes/Q { Method #8 #9; // #7 class #10; // #8 NameAndType #11 #6; // #9 - Utf8 "compiler/valhalla/inlinetypes/MyValue7Mismatch"; // #10 + Utf8 "compiler/valhalla/valuetypes/MyValue7Mismatch"; // #10 Utf8 "verify"; // #11 class #13; // #12 - Utf8 "compiler/valhalla/inlinetypes/Q"; // #13 + Utf8 "compiler/valhalla/valuetypes/Q"; // #13 Utf8 "Code"; // #14 Utf8 "LineNumberTable"; // #15 Utf8 "method"; // #16 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue7Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue7Mismatch;"; // #17 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue7Mismatch;)Lcompiler/valhalla/valuetypes/MyValue7Mismatch;"; // #17 Utf8 "SourceFile"; // #18 Utf8 "TestMismatchHandlingGenerator.java"; // #19 Utf8 "LoadableDescriptors"; // #20 - Utf8 "Lcompiler/valhalla/inlinetypes/MyValue7Mismatch;"; // #21 + Utf8 "Lcompiler/valhalla/valuetypes/MyValue7Mismatch;"; // #21 } // Constant Pool 0x0020; // access @@ -1782,8 +1782,8 @@ class compiler/valhalla/inlinetypes/Q { 0x00010015; } // end LoadableDescriptors } // Attributes -} // end class compiler/valhalla/inlinetypes/Q -class compiler/valhalla/inlinetypes/R { +} // end class compiler/valhalla/valuetypes/Q +class compiler/valhalla/valuetypes/R { 0xCAFEBABE; 65535; // minor version 72; // version @@ -1792,24 +1792,24 @@ class compiler/valhalla/inlinetypes/R { Method #2 #3; // #1 class #4; // #2 NameAndType #5 #6; // #3 - Utf8 "compiler/valhalla/inlinetypes/Q"; // #4 + Utf8 "compiler/valhalla/valuetypes/Q"; // #4 Utf8 ""; // #5 Utf8 "()V"; // #6 Method #8 #9; // #7 class #10; // #8 NameAndType #11 #6; // #9 - Utf8 "compiler/valhalla/inlinetypes/MyValue7Mismatch"; // #10 + Utf8 "compiler/valhalla/valuetypes/MyValue7Mismatch"; // #10 Utf8 "verify"; // #11 class #13; // #12 - Utf8 "compiler/valhalla/inlinetypes/R"; // #13 + Utf8 "compiler/valhalla/valuetypes/R"; // #13 Utf8 "Code"; // #14 Utf8 "LineNumberTable"; // #15 Utf8 "method"; // #16 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue7Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue7Mismatch;"; // #17 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue7Mismatch;)Lcompiler/valhalla/valuetypes/MyValue7Mismatch;"; // #17 Utf8 "SourceFile"; // #18 Utf8 "TestMismatchHandlingGenerator.java"; // #19 Utf8 "LoadableDescriptors"; // #20 - Utf8 "Lcompiler/valhalla/inlinetypes/MyValue7Mismatch;"; // #21 + Utf8 "Lcompiler/valhalla/valuetypes/MyValue7Mismatch;"; // #21 } // Constant Pool 0x0020; // access @@ -1882,8 +1882,8 @@ class compiler/valhalla/inlinetypes/R { 0x00010015; } // end LoadableDescriptors } // Attributes -} // end class compiler/valhalla/inlinetypes/R -class compiler/valhalla/inlinetypes/S { +} // end class compiler/valhalla/valuetypes/R +class compiler/valhalla/valuetypes/S { 0xCAFEBABE; 65535; // minor version 72; // version @@ -1892,26 +1892,26 @@ class compiler/valhalla/inlinetypes/S { Method #2 #3; // #1 class #4; // #2 NameAndType #5 #6; // #3 - Utf8 "compiler/valhalla/inlinetypes/R"; // #4 + Utf8 "compiler/valhalla/valuetypes/R"; // #4 Utf8 ""; // #5 Utf8 "()V"; // #6 Method #8 #9; // #7 class #10; // #8 NameAndType #11 #6; // #9 - Utf8 "compiler/valhalla/inlinetypes/MyValue7Mismatch"; // #10 + Utf8 "compiler/valhalla/valuetypes/MyValue7Mismatch"; // #10 Utf8 "verify"; // #11 class #13; // #12 - Utf8 "compiler/valhalla/inlinetypes/S"; // #13 + Utf8 "compiler/valhalla/valuetypes/S"; // #13 class #15; // #14 - Utf8 "compiler/valhalla/inlinetypes/I6"; // #15 + Utf8 "compiler/valhalla/valuetypes/I6"; // #15 Utf8 "Code"; // #16 Utf8 "LineNumberTable"; // #17 Utf8 "method"; // #18 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue7Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue7Mismatch;"; // #19 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue7Mismatch;)Lcompiler/valhalla/valuetypes/MyValue7Mismatch;"; // #19 Utf8 "SourceFile"; // #20 Utf8 "TestMismatchHandlingGenerator.java"; // #21 Utf8 "LoadableDescriptors"; // #22 - Utf8 "Lcompiler/valhalla/inlinetypes/MyValue7Mismatch;"; // #23 + Utf8 "Lcompiler/valhalla/valuetypes/MyValue7Mismatch;"; // #23 } // Constant Pool 0x0020; // access @@ -1985,8 +1985,8 @@ class compiler/valhalla/inlinetypes/S { 0x00010017; } // end LoadableDescriptors } // Attributes -} // end class compiler/valhalla/inlinetypes/S -class compiler/valhalla/inlinetypes/TestMismatchHandlingHelper { +} // end class compiler/valhalla/valuetypes/S +class compiler/valhalla/valuetypes/TestMismatchHandlingHelper { 0xCAFEBABE; 65535; // minor version 72; // version @@ -1999,70 +1999,70 @@ class compiler/valhalla/inlinetypes/TestMismatchHandlingHelper { Utf8 ""; // #5 Utf8 "()V"; // #6 class #8; // #7 - Utf8 "compiler/valhalla/inlinetypes/MyValue1Mismatch"; // #8 + Utf8 "compiler/valhalla/valuetypes/MyValue1Mismatch"; // #8 Method #7 #3; // #9 Method #11 #12; // #10 class #13; // #11 NameAndType #14 #15; // #12 - Utf8 "compiler/valhalla/inlinetypes/A"; // #13 + Utf8 "compiler/valhalla/valuetypes/A"; // #13 Utf8 "method"; // #14 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue1Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue1Mismatch;"; // #15 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue1Mismatch;)Lcompiler/valhalla/valuetypes/MyValue1Mismatch;"; // #15 Method #7 #17; // #16 NameAndType #18 #6; // #17 Utf8 "verify"; // #18 Method #20 #12; // #19 class #21; // #20 - Utf8 "compiler/valhalla/inlinetypes/B"; // #21 + Utf8 "compiler/valhalla/valuetypes/B"; // #21 Method #23 #12; // #22 class #24; // #23 - Utf8 "compiler/valhalla/inlinetypes/C"; // #24 + Utf8 "compiler/valhalla/valuetypes/C"; // #24 class #26; // #25 - Utf8 "compiler/valhalla/inlinetypes/MyValue2Mismatch"; // #26 + Utf8 "compiler/valhalla/valuetypes/MyValue2Mismatch"; // #26 Method #25 #3; // #27 InterfaceMethod #29 #30; // #28 class #31; // #29 NameAndType #14 #32; // #30 - Utf8 "compiler/valhalla/inlinetypes/I1"; // #31 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;"; // #32 + Utf8 "compiler/valhalla/valuetypes/I1"; // #31 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue2Mismatch;)Lcompiler/valhalla/valuetypes/MyValue2Mismatch;"; // #32 Method #25 #17; // #33 InterfaceMethod #35 #30; // #34 class #36; // #35 - Utf8 "compiler/valhalla/inlinetypes/I2"; // #36 + Utf8 "compiler/valhalla/valuetypes/I2"; // #36 Method #38 #30; // #37 class #39; // #38 - Utf8 "compiler/valhalla/inlinetypes/D"; // #39 + Utf8 "compiler/valhalla/valuetypes/D"; // #39 InterfaceMethod #41 #30; // #40 class #42; // #41 - Utf8 "compiler/valhalla/inlinetypes/I3"; // #42 + Utf8 "compiler/valhalla/valuetypes/I3"; // #42 InterfaceMethod #44 #30; // #43 class #45; // #44 - Utf8 "compiler/valhalla/inlinetypes/I4"; // #45 + Utf8 "compiler/valhalla/valuetypes/I4"; // #45 Method #47 #30; // #46 class #48; // #47 - Utf8 "compiler/valhalla/inlinetypes/E"; // #48 + Utf8 "compiler/valhalla/valuetypes/E"; // #48 class #50; // #49 - Utf8 "compiler/valhalla/inlinetypes/MyValue3Mismatch"; // #50 + Utf8 "compiler/valhalla/valuetypes/MyValue3Mismatch"; // #50 Method #49 #3; // #51 InterfaceMethod #53 #54; // #52 class #55; // #53 NameAndType #14 #56; // #54 - Utf8 "compiler/valhalla/inlinetypes/I5"; // #55 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue3Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue3Mismatch;"; // #56 + Utf8 "compiler/valhalla/valuetypes/I5"; // #55 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue3Mismatch;)Lcompiler/valhalla/valuetypes/MyValue3Mismatch;"; // #56 Method #49 #17; // #57 Method #59 #54; // #58 class #60; // #59 - Utf8 "compiler/valhalla/inlinetypes/H"; // #60 + Utf8 "compiler/valhalla/valuetypes/H"; // #60 Method #62 #54; // #61 class #63; // #62 - Utf8 "compiler/valhalla/inlinetypes/J"; // #63 + Utf8 "compiler/valhalla/valuetypes/J"; // #63 Method #65 #54; // #64 class #66; // #65 - Utf8 "compiler/valhalla/inlinetypes/K"; // #66 + Utf8 "compiler/valhalla/valuetypes/K"; // #66 Method #68 #69; // #67 class #70; // #68 NameAndType #14 #71; // #69 - Utf8 "compiler/valhalla/inlinetypes/M"; // #70 - Utf8 "(Z)Lcompiler/valhalla/inlinetypes/MyValue4Mismatch;"; // #71 + Utf8 "compiler/valhalla/valuetypes/M"; // #70 + Utf8 "(Z)Lcompiler/valhalla/valuetypes/MyValue4Mismatch;"; // #71 Method #73 #74; // #72 class #75; // #73 NameAndType #76 #77; // #74 @@ -2079,69 +2079,69 @@ class compiler/valhalla/inlinetypes/TestMismatchHandlingHelper { Method #86 #87; // #85 class #88; // #86 NameAndType #14 #89; // #87 - Utf8 "compiler/valhalla/inlinetypes/N"; // #88 - Utf8 "(Z)Lcompiler/valhalla/inlinetypes/MyValue5Mismatch;"; // #89 + Utf8 "compiler/valhalla/valuetypes/N"; // #88 + Utf8 "(Z)Lcompiler/valhalla/valuetypes/MyValue5Mismatch;"; // #89 InterfaceMethod #91 #17; // #90 class #92; // #91 - Utf8 "compiler/valhalla/inlinetypes/Verifiable"; // #92 + Utf8 "compiler/valhalla/valuetypes/Verifiable"; // #92 Method #94 #30; // #93 class #95; // #94 - Utf8 "compiler/valhalla/inlinetypes/F"; // #95 + Utf8 "compiler/valhalla/valuetypes/F"; // #95 Method #97 #30; // #96 class #98; // #97 - Utf8 "compiler/valhalla/inlinetypes/G"; // #98 + Utf8 "compiler/valhalla/valuetypes/G"; // #98 Method #100 #54; // #99 class #101; // #100 - Utf8 "compiler/valhalla/inlinetypes/L"; // #101 + Utf8 "compiler/valhalla/valuetypes/L"; // #101 Method #103 #104; // #102 class #105; // #103 NameAndType #14 #106; // #104 - Utf8 "compiler/valhalla/inlinetypes/O"; // #105 - Utf8 "(Z)Lcompiler/valhalla/inlinetypes/MyValue6Mismatch;"; // #106 + Utf8 "compiler/valhalla/valuetypes/O"; // #105 + Utf8 "(Z)Lcompiler/valhalla/valuetypes/MyValue6Mismatch;"; // #106 Method #108 #17; // #107 class #109; // #108 - Utf8 "compiler/valhalla/inlinetypes/MyValue6Mismatch"; // #109 + Utf8 "compiler/valhalla/valuetypes/MyValue6Mismatch"; // #109 class #111; // #110 - Utf8 "compiler/valhalla/inlinetypes/MyValue7Mismatch"; // #111 + Utf8 "compiler/valhalla/valuetypes/MyValue7Mismatch"; // #111 Method #110 #3; // #112 InterfaceMethod #114 #115; // #113 class #116; // #114 NameAndType #14 #117; // #115 - Utf8 "compiler/valhalla/inlinetypes/I6"; // #116 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue7Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue7Mismatch;"; // #117 + Utf8 "compiler/valhalla/valuetypes/I6"; // #116 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue7Mismatch;)Lcompiler/valhalla/valuetypes/MyValue7Mismatch;"; // #117 Method #110 #17; // #118 Method #120 #115; // #119 class #121; // #120 - Utf8 "compiler/valhalla/inlinetypes/P"; // #121 + Utf8 "compiler/valhalla/valuetypes/P"; // #121 Method #123 #115; // #122 class #124; // #123 - Utf8 "compiler/valhalla/inlinetypes/Q"; // #124 + Utf8 "compiler/valhalla/valuetypes/Q"; // #124 Method #126 #115; // #125 class #127; // #126 - Utf8 "compiler/valhalla/inlinetypes/R"; // #127 + Utf8 "compiler/valhalla/valuetypes/R"; // #127 class #129; // #128 - Utf8 "compiler/valhalla/inlinetypes/TestMismatchHandlingHelper"; // #129 + Utf8 "compiler/valhalla/valuetypes/TestMismatchHandlingHelper"; // #129 Utf8 "Code"; // #130 Utf8 "LineNumberTable"; // #131 Utf8 "test1"; // #132 - Utf8 "(Lcompiler/valhalla/inlinetypes/A;Lcompiler/valhalla/inlinetypes/A;Lcompiler/valhalla/inlinetypes/A;Lcompiler/valhalla/inlinetypes/A;Lcompiler/valhalla/inlinetypes/A;Lcompiler/valhalla/inlinetypes/B;Lcompiler/valhalla/inlinetypes/B;Lcompiler/valhalla/inlinetypes/C;)V"; // #133 + Utf8 "(Lcompiler/valhalla/valuetypes/A;Lcompiler/valhalla/valuetypes/A;Lcompiler/valhalla/valuetypes/A;Lcompiler/valhalla/valuetypes/A;Lcompiler/valhalla/valuetypes/A;Lcompiler/valhalla/valuetypes/B;Lcompiler/valhalla/valuetypes/B;Lcompiler/valhalla/valuetypes/C;)V"; // #133 Utf8 "test2"; // #134 - Utf8 "(Lcompiler/valhalla/inlinetypes/I1;Lcompiler/valhalla/inlinetypes/I1;Lcompiler/valhalla/inlinetypes/I1;Lcompiler/valhalla/inlinetypes/I1;Lcompiler/valhalla/inlinetypes/I1;Lcompiler/valhalla/inlinetypes/I1;Lcompiler/valhalla/inlinetypes/I2;Lcompiler/valhalla/inlinetypes/I2;Lcompiler/valhalla/inlinetypes/I2;Lcompiler/valhalla/inlinetypes/I2;Lcompiler/valhalla/inlinetypes/I2;Lcompiler/valhalla/inlinetypes/I2;Lcompiler/valhalla/inlinetypes/I3;Lcompiler/valhalla/inlinetypes/I3;Lcompiler/valhalla/inlinetypes/I3;Lcompiler/valhalla/inlinetypes/I3;Lcompiler/valhalla/inlinetypes/I3;Lcompiler/valhalla/inlinetypes/I3;Lcompiler/valhalla/inlinetypes/I4;Lcompiler/valhalla/inlinetypes/I4;Lcompiler/valhalla/inlinetypes/I4;Lcompiler/valhalla/inlinetypes/I4;Lcompiler/valhalla/inlinetypes/I4;Lcompiler/valhalla/inlinetypes/I4;Lcompiler/valhalla/inlinetypes/D;Lcompiler/valhalla/inlinetypes/E;)V"; // #135 + Utf8 "(Lcompiler/valhalla/valuetypes/I1;Lcompiler/valhalla/valuetypes/I1;Lcompiler/valhalla/valuetypes/I1;Lcompiler/valhalla/valuetypes/I1;Lcompiler/valhalla/valuetypes/I1;Lcompiler/valhalla/valuetypes/I1;Lcompiler/valhalla/valuetypes/I2;Lcompiler/valhalla/valuetypes/I2;Lcompiler/valhalla/valuetypes/I2;Lcompiler/valhalla/valuetypes/I2;Lcompiler/valhalla/valuetypes/I2;Lcompiler/valhalla/valuetypes/I2;Lcompiler/valhalla/valuetypes/I3;Lcompiler/valhalla/valuetypes/I3;Lcompiler/valhalla/valuetypes/I3;Lcompiler/valhalla/valuetypes/I3;Lcompiler/valhalla/valuetypes/I3;Lcompiler/valhalla/valuetypes/I3;Lcompiler/valhalla/valuetypes/I4;Lcompiler/valhalla/valuetypes/I4;Lcompiler/valhalla/valuetypes/I4;Lcompiler/valhalla/valuetypes/I4;Lcompiler/valhalla/valuetypes/I4;Lcompiler/valhalla/valuetypes/I4;Lcompiler/valhalla/valuetypes/D;Lcompiler/valhalla/valuetypes/E;)V"; // #135 Utf8 "test3"; // #136 - Utf8 "(Lcompiler/valhalla/inlinetypes/I5;Lcompiler/valhalla/inlinetypes/I5;Lcompiler/valhalla/inlinetypes/I5;Lcompiler/valhalla/inlinetypes/J;Lcompiler/valhalla/inlinetypes/J;Lcompiler/valhalla/inlinetypes/J;Lcompiler/valhalla/inlinetypes/J;Lcompiler/valhalla/inlinetypes/J;Lcompiler/valhalla/inlinetypes/H;Lcompiler/valhalla/inlinetypes/K;)V"; // #137 + Utf8 "(Lcompiler/valhalla/valuetypes/I5;Lcompiler/valhalla/valuetypes/I5;Lcompiler/valhalla/valuetypes/I5;Lcompiler/valhalla/valuetypes/J;Lcompiler/valhalla/valuetypes/J;Lcompiler/valhalla/valuetypes/J;Lcompiler/valhalla/valuetypes/J;Lcompiler/valhalla/valuetypes/J;Lcompiler/valhalla/valuetypes/H;Lcompiler/valhalla/valuetypes/K;)V"; // #137 Utf8 "test4"; // #138 - Utf8 "(Lcompiler/valhalla/inlinetypes/M;Z)V"; // #139 + Utf8 "(Lcompiler/valhalla/valuetypes/M;Z)V"; // #139 Utf8 "StackMapTable"; // #140 Utf8 "test5"; // #141 - Utf8 "(Lcompiler/valhalla/inlinetypes/N;Z)V"; // #142 + Utf8 "(Lcompiler/valhalla/valuetypes/N;Z)V"; // #142 Utf8 "test6"; // #143 - Utf8 "(Lcompiler/valhalla/inlinetypes/F;Lcompiler/valhalla/inlinetypes/G;Lcompiler/valhalla/inlinetypes/L;)V"; // #144 + Utf8 "(Lcompiler/valhalla/valuetypes/F;Lcompiler/valhalla/valuetypes/G;Lcompiler/valhalla/valuetypes/L;)V"; // #144 Utf8 "test7"; // #145 - Utf8 "(Lcompiler/valhalla/inlinetypes/O;Z)Lcompiler/valhalla/inlinetypes/Verifiable;"; // #146 + Utf8 "(Lcompiler/valhalla/valuetypes/O;Z)Lcompiler/valhalla/valuetypes/Verifiable;"; // #146 Utf8 "test7TriggerCalleeCompilation"; // #147 - Utf8 "(Lcompiler/valhalla/inlinetypes/O;)V"; // #148 + Utf8 "(Lcompiler/valhalla/valuetypes/O;)V"; // #148 Utf8 "test8"; // #149 - Utf8 "(Lcompiler/valhalla/inlinetypes/I6;Lcompiler/valhalla/inlinetypes/I6;Lcompiler/valhalla/inlinetypes/I6;Lcompiler/valhalla/inlinetypes/Q;Lcompiler/valhalla/inlinetypes/Q;Lcompiler/valhalla/inlinetypes/Q;Lcompiler/valhalla/inlinetypes/Q;Lcompiler/valhalla/inlinetypes/Q;Lcompiler/valhalla/inlinetypes/P;Lcompiler/valhalla/inlinetypes/R;)V"; // #150 + Utf8 "(Lcompiler/valhalla/valuetypes/I6;Lcompiler/valhalla/valuetypes/I6;Lcompiler/valhalla/valuetypes/I6;Lcompiler/valhalla/valuetypes/Q;Lcompiler/valhalla/valuetypes/Q;Lcompiler/valhalla/valuetypes/Q;Lcompiler/valhalla/valuetypes/Q;Lcompiler/valhalla/valuetypes/Q;Lcompiler/valhalla/valuetypes/P;Lcompiler/valhalla/valuetypes/R;)V"; // #150 Utf8 "SourceFile"; // #151 Utf8 "TestMismatchHandlingGenerator.java"; // #152 } // Constant Pool @@ -2413,7 +2413,7 @@ class compiler/valhalla/inlinetypes/TestMismatchHandlingHelper { } // end LineNumberTable ; Attr(#140) { // StackMapTable - [] { // + [] { // 13b; // same_frame 25b; // same_frame } @@ -2449,7 +2449,7 @@ class compiler/valhalla/inlinetypes/TestMismatchHandlingHelper { } // end LineNumberTable ; Attr(#140) { // StackMapTable - [] { // + [] { // 252b, 16, []z{O,91}; // append_frame 1 } } // end StackMapTable @@ -2599,8 +2599,8 @@ class compiler/valhalla/inlinetypes/TestMismatchHandlingHelper { #152; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/TestMismatchHandlingHelper -class compiler/valhalla/inlinetypes/A { +} // end class compiler/valhalla/valuetypes/TestMismatchHandlingHelper +class compiler/valhalla/valuetypes/A { 0xCAFEBABE; 0; // minor version 72; // version @@ -2615,14 +2615,14 @@ class compiler/valhalla/inlinetypes/A { Method #8 #9; // #7 class #10; // #8 NameAndType #11 #6; // #9 - Utf8 "compiler/valhalla/inlinetypes/MyValue1Mismatch"; // #10 + Utf8 "compiler/valhalla/valuetypes/MyValue1Mismatch"; // #10 Utf8 "verify"; // #11 class #13; // #12 - Utf8 "compiler/valhalla/inlinetypes/A"; // #13 + Utf8 "compiler/valhalla/valuetypes/A"; // #13 Utf8 "Code"; // #14 Utf8 "LineNumberTable"; // #15 Utf8 "method"; // #16 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue1Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue1Mismatch;"; // #17 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue1Mismatch;)Lcompiler/valhalla/valuetypes/MyValue1Mismatch;"; // #17 Utf8 "SourceFile"; // #18 Utf8 "TestMismatchHandlingGenerator.java"; // #19 } // Constant Pool @@ -2693,8 +2693,8 @@ class compiler/valhalla/inlinetypes/A { #19; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/A -class compiler/valhalla/inlinetypes/C { +} // end class compiler/valhalla/valuetypes/A +class compiler/valhalla/valuetypes/C { 0xCAFEBABE; 0; // minor version 72; // version @@ -2703,20 +2703,20 @@ class compiler/valhalla/inlinetypes/C { Method #2 #3; // #1 class #4; // #2 NameAndType #5 #6; // #3 - Utf8 "compiler/valhalla/inlinetypes/B"; // #4 + Utf8 "compiler/valhalla/valuetypes/B"; // #4 Utf8 ""; // #5 Utf8 "()V"; // #6 Method #8 #9; // #7 class #10; // #8 NameAndType #11 #6; // #9 - Utf8 "compiler/valhalla/inlinetypes/MyValue1Mismatch"; // #10 + Utf8 "compiler/valhalla/valuetypes/MyValue1Mismatch"; // #10 Utf8 "verify"; // #11 class #13; // #12 - Utf8 "compiler/valhalla/inlinetypes/C"; // #13 + Utf8 "compiler/valhalla/valuetypes/C"; // #13 Utf8 "Code"; // #14 Utf8 "LineNumberTable"; // #15 Utf8 "method"; // #16 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue1Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue1Mismatch;"; // #17 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue1Mismatch;)Lcompiler/valhalla/valuetypes/MyValue1Mismatch;"; // #17 Utf8 "SourceFile"; // #18 Utf8 "TestMismatchHandlingGenerator.java"; // #19 } // Constant Pool @@ -2787,19 +2787,19 @@ class compiler/valhalla/inlinetypes/C { #19; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/C -class compiler/valhalla/inlinetypes/I1 { +} // end class compiler/valhalla/valuetypes/C +class compiler/valhalla/valuetypes/I1 { 0xCAFEBABE; 0; // minor version 72; // version [] { // Constant Pool ; // first element is empty class #2; // #1 - Utf8 "compiler/valhalla/inlinetypes/I1"; // #2 + Utf8 "compiler/valhalla/valuetypes/I1"; // #2 class #4; // #3 Utf8 "java/lang/Object"; // #4 Utf8 "method"; // #5 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;"; // #6 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue2Mismatch;)Lcompiler/valhalla/valuetypes/MyValue2Mismatch;"; // #6 Utf8 "SourceFile"; // #7 Utf8 "TestMismatchHandlingGenerator.java"; // #8 } // Constant Pool @@ -2829,21 +2829,21 @@ class compiler/valhalla/inlinetypes/I1 { #8; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/I1 -class compiler/valhalla/inlinetypes/I2 { +} // end class compiler/valhalla/valuetypes/I1 +class compiler/valhalla/valuetypes/I2 { 0xCAFEBABE; 0; // minor version 72; // version [] { // Constant Pool ; // first element is empty class #2; // #1 - Utf8 "compiler/valhalla/inlinetypes/I2"; // #2 + Utf8 "compiler/valhalla/valuetypes/I2"; // #2 class #4; // #3 Utf8 "java/lang/Object"; // #4 class #6; // #5 - Utf8 "compiler/valhalla/inlinetypes/I1"; // #6 + Utf8 "compiler/valhalla/valuetypes/I1"; // #6 Utf8 "method"; // #7 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;"; // #8 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue2Mismatch;)Lcompiler/valhalla/valuetypes/MyValue2Mismatch;"; // #8 Utf8 "SourceFile"; // #9 Utf8 "TestMismatchHandlingGenerator.java"; // #10 } // Constant Pool @@ -2874,8 +2874,8 @@ class compiler/valhalla/inlinetypes/I2 { #10; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/I2 -class compiler/valhalla/inlinetypes/D { +} // end class compiler/valhalla/valuetypes/I2 +class compiler/valhalla/valuetypes/D { 0xCAFEBABE; 0; // minor version 72; // version @@ -2890,16 +2890,16 @@ class compiler/valhalla/inlinetypes/D { Method #8 #9; // #7 class #10; // #8 NameAndType #11 #6; // #9 - Utf8 "compiler/valhalla/inlinetypes/MyValue2Mismatch"; // #10 + Utf8 "compiler/valhalla/valuetypes/MyValue2Mismatch"; // #10 Utf8 "verify"; // #11 class #13; // #12 - Utf8 "compiler/valhalla/inlinetypes/D"; // #13 + Utf8 "compiler/valhalla/valuetypes/D"; // #13 class #15; // #14 - Utf8 "compiler/valhalla/inlinetypes/I2"; // #15 + Utf8 "compiler/valhalla/valuetypes/I2"; // #15 Utf8 "Code"; // #16 Utf8 "LineNumberTable"; // #17 Utf8 "method"; // #18 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;"; // #19 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue2Mismatch;)Lcompiler/valhalla/valuetypes/MyValue2Mismatch;"; // #19 Utf8 "SourceFile"; // #20 Utf8 "TestMismatchHandlingGenerator.java"; // #21 } // Constant Pool @@ -2971,8 +2971,8 @@ class compiler/valhalla/inlinetypes/D { #21; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/D -class compiler/valhalla/inlinetypes/F { +} // end class compiler/valhalla/valuetypes/D +class compiler/valhalla/valuetypes/F { 0xCAFEBABE; 0; // minor version 72; // version @@ -2987,18 +2987,18 @@ class compiler/valhalla/inlinetypes/F { Method #8 #9; // #7 class #10; // #8 NameAndType #11 #6; // #9 - Utf8 "compiler/valhalla/inlinetypes/MyValue2Mismatch"; // #10 + Utf8 "compiler/valhalla/valuetypes/MyValue2Mismatch"; // #10 Utf8 "verify"; // #11 class #13; // #12 - Utf8 "compiler/valhalla/inlinetypes/F"; // #13 + Utf8 "compiler/valhalla/valuetypes/F"; // #13 class #15; // #14 - Utf8 "compiler/valhalla/inlinetypes/I2"; // #15 + Utf8 "compiler/valhalla/valuetypes/I2"; // #15 class #17; // #16 - Utf8 "compiler/valhalla/inlinetypes/I4"; // #17 + Utf8 "compiler/valhalla/valuetypes/I4"; // #17 Utf8 "Code"; // #18 Utf8 "LineNumberTable"; // #19 Utf8 "method"; // #20 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue2Mismatch;"; // #21 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue2Mismatch;)Lcompiler/valhalla/valuetypes/MyValue2Mismatch;"; // #21 Utf8 "SourceFile"; // #22 Utf8 "TestMismatchHandlingGenerator.java"; // #23 } // Constant Pool @@ -3071,8 +3071,8 @@ class compiler/valhalla/inlinetypes/F { #23; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/F -class compiler/valhalla/inlinetypes/H { +} // end class compiler/valhalla/valuetypes/F +class compiler/valhalla/valuetypes/H { 0xCAFEBABE; 0; // minor version 72; // version @@ -3087,16 +3087,16 @@ class compiler/valhalla/inlinetypes/H { Method #8 #9; // #7 class #10; // #8 NameAndType #11 #6; // #9 - Utf8 "compiler/valhalla/inlinetypes/MyValue3Mismatch"; // #10 + Utf8 "compiler/valhalla/valuetypes/MyValue3Mismatch"; // #10 Utf8 "verify"; // #11 class #13; // #12 - Utf8 "compiler/valhalla/inlinetypes/H"; // #13 + Utf8 "compiler/valhalla/valuetypes/H"; // #13 class #15; // #14 - Utf8 "compiler/valhalla/inlinetypes/I5"; // #15 + Utf8 "compiler/valhalla/valuetypes/I5"; // #15 Utf8 "Code"; // #16 Utf8 "LineNumberTable"; // #17 Utf8 "method"; // #18 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue3Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue3Mismatch;"; // #19 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue3Mismatch;)Lcompiler/valhalla/valuetypes/MyValue3Mismatch;"; // #19 Utf8 "SourceFile"; // #20 Utf8 "TestMismatchHandlingGenerator.java"; // #21 } // Constant Pool @@ -3168,19 +3168,19 @@ class compiler/valhalla/inlinetypes/H { #21; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/H -class compiler/valhalla/inlinetypes/I5 { +} // end class compiler/valhalla/valuetypes/H +class compiler/valhalla/valuetypes/I5 { 0xCAFEBABE; 0; // minor version 72; // version [] { // Constant Pool ; // first element is empty class #2; // #1 - Utf8 "compiler/valhalla/inlinetypes/I5"; // #2 + Utf8 "compiler/valhalla/valuetypes/I5"; // #2 class #4; // #3 Utf8 "java/lang/Object"; // #4 Utf8 "method"; // #5 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue3Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue3Mismatch;"; // #6 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue3Mismatch;)Lcompiler/valhalla/valuetypes/MyValue3Mismatch;"; // #6 Utf8 "SourceFile"; // #7 Utf8 "TestMismatchHandlingGenerator.java"; // #8 } // Constant Pool @@ -3210,8 +3210,8 @@ class compiler/valhalla/inlinetypes/I5 { #8; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/I5 -class compiler/valhalla/inlinetypes/M { +} // end class compiler/valhalla/valuetypes/I5 +class compiler/valhalla/valuetypes/M { 0xCAFEBABE; 0; // minor version 72; // version @@ -3226,19 +3226,19 @@ class compiler/valhalla/inlinetypes/M { Field #8 #9; // #7 class #10; // #8 NameAndType #11 #12; // #9 - Utf8 "compiler/valhalla/inlinetypes/M"; // #10 + Utf8 "compiler/valhalla/valuetypes/M"; // #10 Utf8 "val"; // #11 Utf8 "I"; // #12 Method #14 #15; // #13 class #16; // #14 NameAndType #17 #18; // #15 - Utf8 "compiler/valhalla/inlinetypes/MyValue4Mismatch"; // #16 + Utf8 "compiler/valhalla/valuetypes/MyValue4Mismatch"; // #16 Utf8 "make"; // #17 - Utf8 "()Lcompiler/valhalla/inlinetypes/MyValue4Mismatch;"; // #18 + Utf8 "()Lcompiler/valhalla/valuetypes/MyValue4Mismatch;"; // #18 Utf8 "Code"; // #19 Utf8 "LineNumberTable"; // #20 Utf8 "method"; // #21 - Utf8 "(Z)Lcompiler/valhalla/inlinetypes/MyValue4Mismatch;"; // #22 + Utf8 "(Z)Lcompiler/valhalla/valuetypes/MyValue4Mismatch;"; // #22 Utf8 "StackMapTable"; // #23 Utf8 "SourceFile"; // #24 Utf8 "TestMismatchHandlingGenerator.java"; // #25 @@ -3319,7 +3319,7 @@ class compiler/valhalla/inlinetypes/M { } // end LineNumberTable ; Attr(#23) { // StackMapTable - [] { // + [] { // 6b; // same_frame 253b, 5, []z{O,14; I}; // append_frame 2 250b, 21; // chop_frame 1 @@ -3336,8 +3336,8 @@ class compiler/valhalla/inlinetypes/M { #25; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/M -class compiler/valhalla/inlinetypes/N { +} // end class compiler/valhalla/valuetypes/M +class compiler/valhalla/valuetypes/N { 0xCAFEBABE; 0; // minor version 72; // version @@ -3352,15 +3352,15 @@ class compiler/valhalla/inlinetypes/N { Method #8 #9; // #7 class #10; // #8 NameAndType #11 #12; // #9 - Utf8 "compiler/valhalla/inlinetypes/MyValue5Mismatch"; // #10 + Utf8 "compiler/valhalla/valuetypes/MyValue5Mismatch"; // #10 Utf8 "make"; // #11 - Utf8 "()Lcompiler/valhalla/inlinetypes/MyValue5Mismatch;"; // #12 + Utf8 "()Lcompiler/valhalla/valuetypes/MyValue5Mismatch;"; // #12 class #14; // #13 - Utf8 "compiler/valhalla/inlinetypes/N"; // #14 + Utf8 "compiler/valhalla/valuetypes/N"; // #14 Utf8 "Code"; // #15 Utf8 "LineNumberTable"; // #16 Utf8 "method"; // #17 - Utf8 "(Z)Lcompiler/valhalla/inlinetypes/MyValue5Mismatch;"; // #18 + Utf8 "(Z)Lcompiler/valhalla/valuetypes/MyValue5Mismatch;"; // #18 Utf8 "StackMapTable"; // #19 Utf8 "SourceFile"; // #20 Utf8 "TestMismatchHandlingGenerator.java"; // #21 @@ -3425,7 +3425,7 @@ class compiler/valhalla/inlinetypes/N { } // end LineNumberTable ; Attr(#19) { // StackMapTable - [] { // + [] { // 6b; // same_frame } } // end StackMapTable @@ -3440,8 +3440,8 @@ class compiler/valhalla/inlinetypes/N { #21; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/N -class compiler/valhalla/inlinetypes/O { +} // end class compiler/valhalla/valuetypes/N +class compiler/valhalla/valuetypes/O { 0xCAFEBABE; 0; // minor version 72; // version @@ -3456,15 +3456,15 @@ class compiler/valhalla/inlinetypes/O { Method #8 #9; // #7 class #10; // #8 NameAndType #11 #12; // #9 - Utf8 "compiler/valhalla/inlinetypes/MyValue6Mismatch"; // #10 + Utf8 "compiler/valhalla/valuetypes/MyValue6Mismatch"; // #10 Utf8 "make"; // #11 - Utf8 "()Lcompiler/valhalla/inlinetypes/MyValue6Mismatch;"; // #12 + Utf8 "()Lcompiler/valhalla/valuetypes/MyValue6Mismatch;"; // #12 class #14; // #13 - Utf8 "compiler/valhalla/inlinetypes/O"; // #14 + Utf8 "compiler/valhalla/valuetypes/O"; // #14 Utf8 "Code"; // #15 Utf8 "LineNumberTable"; // #16 Utf8 "method"; // #17 - Utf8 "(Z)Lcompiler/valhalla/inlinetypes/MyValue6Mismatch;"; // #18 + Utf8 "(Z)Lcompiler/valhalla/valuetypes/MyValue6Mismatch;"; // #18 Utf8 "StackMapTable"; // #19 Utf8 "SourceFile"; // #20 Utf8 "TestMismatchHandlingGenerator.java"; // #21 @@ -3529,7 +3529,7 @@ class compiler/valhalla/inlinetypes/O { } // end LineNumberTable ; Attr(#19) { // StackMapTable - [] { // + [] { // 6b; // same_frame } } // end StackMapTable @@ -3544,19 +3544,19 @@ class compiler/valhalla/inlinetypes/O { #21; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/O -class compiler/valhalla/inlinetypes/I6 { +} // end class compiler/valhalla/valuetypes/O +class compiler/valhalla/valuetypes/I6 { 0xCAFEBABE; 0; // minor version 72; // version [] { // Constant Pool ; // first element is empty class #2; // #1 - Utf8 "compiler/valhalla/inlinetypes/I6"; // #2 + Utf8 "compiler/valhalla/valuetypes/I6"; // #2 class #4; // #3 Utf8 "java/lang/Object"; // #4 Utf8 "method"; // #5 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue7Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue7Mismatch;"; // #6 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue7Mismatch;)Lcompiler/valhalla/valuetypes/MyValue7Mismatch;"; // #6 Utf8 "Code"; // #7 Utf8 "LineNumberTable"; // #8 Utf8 "SourceFile"; // #9 @@ -3604,8 +3604,8 @@ class compiler/valhalla/inlinetypes/I6 { #10; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/I6 -class compiler/valhalla/inlinetypes/P { +} // end class compiler/valhalla/valuetypes/I6 +class compiler/valhalla/valuetypes/P { 0xCAFEBABE; 0; // minor version 72; // version @@ -3620,16 +3620,16 @@ class compiler/valhalla/inlinetypes/P { Method #8 #9; // #7 class #10; // #8 NameAndType #11 #6; // #9 - Utf8 "compiler/valhalla/inlinetypes/MyValue7Mismatch"; // #10 + Utf8 "compiler/valhalla/valuetypes/MyValue7Mismatch"; // #10 Utf8 "verify"; // #11 class #13; // #12 - Utf8 "compiler/valhalla/inlinetypes/P"; // #13 + Utf8 "compiler/valhalla/valuetypes/P"; // #13 class #15; // #14 - Utf8 "compiler/valhalla/inlinetypes/I6"; // #15 + Utf8 "compiler/valhalla/valuetypes/I6"; // #15 Utf8 "Code"; // #16 Utf8 "LineNumberTable"; // #17 Utf8 "method"; // #18 - Utf8 "(Lcompiler/valhalla/inlinetypes/MyValue7Mismatch;)Lcompiler/valhalla/inlinetypes/MyValue7Mismatch;"; // #19 + Utf8 "(Lcompiler/valhalla/valuetypes/MyValue7Mismatch;)Lcompiler/valhalla/valuetypes/MyValue7Mismatch;"; // #19 Utf8 "SourceFile"; // #20 Utf8 "TestMismatchHandlingGenerator.java"; // #21 } // Constant Pool @@ -3701,4 +3701,4 @@ class compiler/valhalla/inlinetypes/P { #21; } // end SourceFile } // Attributes -} // end class compiler/valhalla/inlinetypes/P +} // end class compiler/valhalla/valuetypes/P diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMismatchHandlingGenerator.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMismatchHandlingGenerator.java similarity index 99% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMismatchHandlingGenerator.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMismatchHandlingGenerator.java index d80f5aaa206d..da1a2c879665 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMismatchHandlingGenerator.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMismatchHandlingGenerator.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; value class MyValue1Mismatch { int x = 42; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMissingOptAcmp.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMissingOptAcmp.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMissingOptAcmp.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMissingOptAcmp.java index 8751f920267d..6786631b0bd1 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMissingOptAcmp.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMissingOptAcmp.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; /* * @test diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMissingOptCastSpeculative.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMissingOptCastSpeculative.java similarity index 94% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMissingOptCastSpeculative.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMissingOptCastSpeculative.java index 4882f16ad60f..cf2cfacd2d26 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMissingOptCastSpeculative.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMissingOptCastSpeculative.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import test.java.lang.invoke.lib.InstructionHelper; @@ -31,12 +31,12 @@ import jdk.internal.value.ValueClass; -import static compiler.valhalla.inlinetypes.InlineTypes.*; +import static compiler.valhalla.valuetypes.ValueTypes.*; /* * @test * @bug 8367624 - * @summary Writing a null value to an inline type array casts the array to + * @summary Writing a null value to a value type array casts the array to * 'not null free'. If there is a speculative type before the cast, * we have to make sure to cast it as well, otherwise we get a * missed value optimization. diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMissingOptUseBaseOop.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMissingOptUseBaseOop.java similarity index 87% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMissingOptUseBaseOop.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMissingOptUseBaseOop.java index a1f7138da75b..11b777cf9d54 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMissingOptUseBaseOop.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMissingOptUseBaseOop.java @@ -21,15 +21,15 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; /* * @test * @bug 8367623 - * @summary When an InlineType has a larval oop and its method is + * @summary When an ValueType has a larval oop and its method is * not inlined, it prevents the Allocate node of the larval oop * to be eliminated. This ends up causing the report of a missed - * optimization (InlineTypeNode::Ideal) after macro expansion. + * optimization (ValueTypeNode::Ideal) after macro expansion. * That optimization should not be carried out, which is what this * test ensures. * @enablePreview @@ -39,8 +39,8 @@ * -Xcomp -XX:-TieredCompilation * -XX:CompileCommand=compileonly,*TestMissingOptUseBaseOop::test* * -XX:VerifyIterativeGVN=1110 - * compiler.valhalla.inlinetypes.TestMissingOptUseBaseOop - * @run main compiler.valhalla.inlinetypes.TestMissingOptUseBaseOop + * compiler.valhalla.valuetypes.TestMissingOptUseBaseOop + * @run main compiler.valhalla.valuetypes.TestMissingOptUseBaseOop */ public class TestMissingOptUseBaseOop { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMissingOptUseBaseOopNested.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMissingOptUseBaseOopNested.java similarity index 92% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMissingOptUseBaseOopNested.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMissingOptUseBaseOopNested.java index 8cc4daa0c8a9..ccd35acbc9bb 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMissingOptUseBaseOopNested.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMissingOptUseBaseOopNested.java @@ -21,18 +21,18 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.vm.annotation.NullRestricted; -import static compiler.valhalla.inlinetypes.InlineTypes.*; +import static compiler.valhalla.valuetypes.ValueTypes.*; /* * @test * @key randomness - * @summary For InlineType nodes, we want to set the base oop if fields are loaded from memory. + * @summary For ValueType nodes, we want to set the base oop if fields are loaded from memory. * This test ensures that this optimization is not missed when we have nested - * inline types and InlineTypeNode::is_loaded suddenly returns something for one of + * value types and ValueTypeNode::is_loaded suddenly returns something for one of * the nested types after another optimization. * @library /test/lib / * @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true") diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMissingOptUseBaseOopParsing.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMissingOptUseBaseOopParsing.java similarity index 89% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMissingOptUseBaseOopParsing.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMissingOptUseBaseOopParsing.java index 14a8b4169350..b30341143ad6 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMissingOptUseBaseOopParsing.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMissingOptUseBaseOopParsing.java @@ -21,20 +21,20 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; import jdk.internal.value.ValueClass; import jdk.internal.vm.annotation.NullRestricted; -import static compiler.valhalla.inlinetypes.InlineTypes.*; +import static compiler.valhalla.valuetypes.ValueTypes.*; /* * @test * @key randomness - * @summary For InlineType nodes, we want to set the base oop if fields are loaded from memory. - * This test ensures that this optimization is not missed when we create an InlineType - * node in parsing with InlineTypeNode::buffer. + * @summary For ValueType nodes, we want to set the base oop if fields are loaded from memory. + * This test ensures that this optimization is not missed when we create an ValueType + * node in parsing with ValueTypeNode::buffer. * @library /test/lib / * @enablePreview * @modules java.base/jdk.internal.value diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMultidimArrays.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMultidimArrays.java similarity index 84% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMultidimArrays.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMultidimArrays.java index 327d2b382773..2e66fdd68df2 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestMultidimArrays.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMultidimArrays.java @@ -26,23 +26,23 @@ * @library /test/lib * @summary Test correct handling of multidimensional arrays. * @enablePreview - * @run main compiler.valhalla.inlinetypes.TestMultidimArrays + * @run main compiler.valhalla.valuetypes.TestMultidimArrays * @run main/othervm -Xbatch -XX:-TieredCompilation - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestMultidimArrays::test* - * compiler.valhalla.inlinetypes.TestMultidimArrays + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestMultidimArrays::test* + * compiler.valhalla.valuetypes.TestMultidimArrays * @run main/othervm -Xbatch -XX:-TieredCompilation -XX:MultiArrayExpandLimit=0 - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestMultidimArrays::test* - * compiler.valhalla.inlinetypes.TestMultidimArrays + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestMultidimArrays::test* + * compiler.valhalla.valuetypes.TestMultidimArrays * @run main/othervm -Xbatch -XX:-TieredCompilation * -XX:+IgnoreUnrecognizedVMOptions -XX:+StressReflectiveCode - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestMultidimArrays::test* - * compiler.valhalla.inlinetypes.TestMultidimArrays + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestMultidimArrays::test* + * compiler.valhalla.valuetypes.TestMultidimArrays * @run main/othervm -Xbatch -XX:-TieredCompilation -XX:-DoEscapeAnalysis - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestMultidimArrays::test* - * compiler.valhalla.inlinetypes.TestMultidimArrays + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestMultidimArrays::test* + * compiler.valhalla.valuetypes.TestMultidimArrays */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNativeClone.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNativeClone.java similarity index 93% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNativeClone.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNativeClone.java index 293ea66c1cc0..02e945e4857c 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNativeClone.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNativeClone.java @@ -29,14 +29,14 @@ * @modules java.base/java.lang:+open * @enablePreview * @run main/othervm -Xbatch -XX:-UseTypeProfile - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.MyValue::* - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestNativeClone::test* + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue::* + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestNativeClone::test* * -XX:CompileCommand=compileonly,jdk.internal.reflect.GeneratedMethodAccessor1::invoke * -XX:CompileCommand=dontinline,jdk.internal.reflect.GeneratedMethodAccessor1::invoke - * compiler.valhalla.inlinetypes.TestNativeClone + * compiler.valhalla.valuetypes.TestNativeClone */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNestedLoopUnswitchingWithManyFlatArrayChecks.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNestedLoopUnswitchingWithManyFlatArrayChecks.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNestedLoopUnswitchingWithManyFlatArrayChecks.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNestedLoopUnswitchingWithManyFlatArrayChecks.java index b0a6e0d9ea8d..edd5e902d673 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNestedLoopUnswitchingWithManyFlatArrayChecks.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNestedLoopUnswitchingWithManyFlatArrayChecks.java @@ -31,7 +31,7 @@ * @run main/othervm -XX:-BackgroundCompilation -XX:+UnlockDiagnosticVMOptions -XX:-UseArrayLoadStoreProfile ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.value.ValueClass; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNestmateAccess.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNestmateAccess.java similarity index 95% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNestmateAccess.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNestmateAccess.java index 33d2b3cef072..8b77a00a8ca7 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNestmateAccess.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNestmateAccess.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; @@ -38,12 +38,12 @@ * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @run main/othervm -Xcomp - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.Test*:: - * compiler.valhalla.inlinetypes.TestNestmateAccess + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.Test*:: + * compiler.valhalla.valuetypes.TestNestmateAccess * @run main/othervm -Xcomp -XX:TieredStopAtLevel=1 - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.Test*:: - * compiler.valhalla.inlinetypes.TestNestmateAccess - * @run main/othervm compiler.valhalla.inlinetypes.TestNestmateAccess + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.Test*:: + * compiler.valhalla.valuetypes.TestNestmateAccess + * @run main/othervm compiler.valhalla.valuetypes.TestNestmateAccess */ interface MyInterfaceNestmateAccess { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNewAcmp.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNewAcmp.java similarity index 99% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNewAcmp.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNewAcmp.java index be860a2c69d6..dad60af136df 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNewAcmp.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNewAcmp.java @@ -29,10 +29,10 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * compiler.valhalla.inlinetypes.TestNewAcmp + * compiler.valhalla.valuetypes.TestNewAcmp */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.CompLevel; import compiler.lib.ir_framework.TestFramework; @@ -1862,8 +1862,8 @@ private static void enumerateVMOptions() throws Exception { "-Xbatch", "-XX:TypeProfileLevel=222", "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED", - "-XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestNewAcmp::test*", - "-XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestNewAcmp::cmp*"}; + "-XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestNewAcmp::test*", + "-XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestNewAcmp::cmp*"}; String SCENARIOS = System.getProperty("Scenarios", ""); List scenarios = null; @@ -1881,7 +1881,7 @@ private static void enumerateVMOptions() throws Exception { cmds = addOptions(cmds, "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+AlwaysIncrementalInline"); } - cmds = addOptions(cmds, "compiler.valhalla.inlinetypes.TestNewAcmp"); + cmds = addOptions(cmds, "compiler.valhalla.valuetypes.TestNewAcmp"); cmds = addOptions(cmds, Integer.toString(nullMode)); if (scenarios != null && !scenarios.contains(Integer.toString(scenario))) { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableArrays.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableArrays.java similarity index 99% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableArrays.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableArrays.java index db0eb31fe491..f7580f9c69bb 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableArrays.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableArrays.java @@ -21,24 +21,24 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; import compiler.lib.ir_framework.*; -import static compiler.valhalla.inlinetypes.InlineTypes.rI; -import static compiler.valhalla.inlinetypes.InlineTypes.rL; -import static compiler.valhalla.inlinetypes.InlineTypes.rD; +import static compiler.valhalla.valuetypes.ValueTypes.rI; +import static compiler.valhalla.valuetypes.ValueTypes.rL; +import static compiler.valhalla.valuetypes.ValueTypes.rD; import static compiler.lib.ir_framework.IRNode.ALLOC; import static compiler.lib.ir_framework.IRNode.ALLOC_ARRAY_OF_MYVALUE_KLASS; import static compiler.lib.ir_framework.IRNode.ALLOC_OF_MYVALUE_KLASS; import static compiler.lib.ir_framework.IRNode.LOAD_OF_ANY_KLASS; -import static compiler.lib.ir_framework.IRNode.LOAD_UNKNOWN_INLINE; +import static compiler.lib.ir_framework.IRNode.LOAD_UNKNOWN_VALUE; import static compiler.lib.ir_framework.IRNode.LOOP; import static compiler.lib.ir_framework.IRNode.PREDICATE_TRAP; import static compiler.lib.ir_framework.IRNode.STORE_OF_ANY_KLASS; -import static compiler.lib.ir_framework.IRNode.STORE_UNKNOWN_INLINE; +import static compiler.lib.ir_framework.IRNode.STORE_UNKNOWN_VALUE; import static compiler.lib.ir_framework.IRNode.UNSTABLE_IF_TRAP; import jdk.internal.value.ValueClass; @@ -135,13 +135,13 @@ public class TestNullableArrays { public static void main(String[] args) { - Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; + Scenario[] scenarios = ValueTypes.DEFAULT_SCENARIOS; scenarios[2].addFlags("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast", "-XX:+StressArrayCopyMacroNode"); scenarios[3].addFlags("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast"); scenarios[4].addFlags("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast"); scenarios[5].addFlags("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck", "-XX:-UncommonNullCast", "-XX:+StressArrayCopyMacroNode"); - InlineTypes.getFramework() + ValueTypes.getFramework() .addScenarios(scenarios[Integer.parseInt(args[0])]) .addHelperClasses(MyValue1.class, MyValue2.class, @@ -980,8 +980,8 @@ public void test28_verifier() { @Test @IR(failOn = {LOOP, UNSTABLE_IF_TRAP, PREDICATE_TRAP}) - @IR(failOn = LOAD_OF_ANY_KLASS, applyIf = {"InlineTypeReturnedAsFields", "false"}) - @IR(counts = {LOAD_OF_ANY_KLASS, "4"}, applyIf = {"InlineTypeReturnedAsFields", "true"}) + @IR(failOn = LOAD_OF_ANY_KLASS, applyIf = {"ValueTypeReturnedAsFields", "false"}) + @IR(counts = {LOAD_OF_ANY_KLASS, "4"}, applyIf = {"ValueTypeReturnedAsFields", "true"}) public MyValue2 test29(MyValue2[] src) { MyValue2[] dst = new MyValue2[10]; System.arraycopy(src, 0, dst, 0, 10); @@ -2573,7 +2573,7 @@ public static void test94_verifier() { Asserts.assertEquals(result, MyValue1.createDefaultInline().hash()); } - // Test meeting constant TypeInstPtr with InlineTypeNode + // Test meeting constant TypeInstPtr with ValueTypeNode @ForceInline public long test95_callee() { MyValue1[] va = new MyValue1[1]; @@ -2656,7 +2656,7 @@ public void test96_verifier() { // Test loads from vararg arrays @Test - @IR(failOn = {LOAD_UNKNOWN_INLINE}) + @IR(failOn = {LOAD_UNKNOWN_VALUE}) public static Object test97(Object... args) { return args[0]; } @@ -2750,7 +2750,7 @@ public static void test100_verifier(RunInfo info) { // Test stores to varag arrays @Test - @IR(failOn = STORE_UNKNOWN_INLINE) + @IR(failOn = STORE_UNKNOWN_VALUE) public static void test101(Object val, Object... args) { args[0] = val; } diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableInlineTypes.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableValueTypes.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableInlineTypes.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableValueTypes.java index a4a68b5f9ea3..81140f8eee56 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestNullableInlineTypes.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullableValueTypes.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.*; import jdk.test.lib.Asserts; @@ -38,7 +38,7 @@ import jdk.internal.vm.annotation.LooselyConsistentValue; import jdk.internal.vm.annotation.NullRestricted; -import static compiler.valhalla.inlinetypes.InlineTypes.*; +import static compiler.valhalla.valuetypes.ValueTypes.*; import static compiler.lib.ir_framework.IRNode.ALLOC; import static compiler.lib.ir_framework.IRNode.ALLOC_OF_MYVALUE_KLASS; @@ -148,9 +148,9 @@ */ @ForceCompileClassInitializer -public class TestNullableInlineTypes { +public class TestNullableValueTypes { - public TestNullableInlineTypes() { + public TestNullableValueTypes() { valueField1 = testValue1; flatField = MyValue1.DEFAULT; wrapperField = new MyValue1Wrapper(testValue1); @@ -163,25 +163,25 @@ public TestNullableInlineTypes() { public static void main(String[] args) { - Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; + Scenario[] scenarios = ValueTypes.DEFAULT_SCENARIOS; scenarios[3].addFlags("-XX:+UnlockDiagnosticVMOptions", "-XX:+UseArrayFlattening", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck"); scenarios[4].addFlags("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck"); - InlineTypes.getFramework() - .addScenarios(scenarios[Integer.parseInt(args[0])]) - .addHelperClasses(MyValue1.class, - MyValue2.class, - MyValue2Inline.class, - MyValue3.class, - MyValue3Inline.class) - .start(); + ValueTypes.getFramework() + .addScenarios(scenarios[Integer.parseInt(args[0])]) + .addHelperClasses(MyValue1.class, + MyValue2.class, + MyValue2Inline.class, + MyValue3.class, + MyValue3Inline.class) + .start(); } static { // Make sure RuntimeException is loaded to prevent uncommon traps in IR verified tests RuntimeException tmp = new RuntimeException("42"); try { - Class clazz = TestNullableInlineTypes.class; + Class clazz = TestNullableValueTypes.class; MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodType test18_mt = MethodType.methodType(void.class, MyValue1.class); @@ -786,9 +786,9 @@ public void test22_verifier() { } @Test - @IR(applyIfAnd = {"UseArrayFlattening", "true", "InlineTypePassFieldsAsArgs", "true"}, + @IR(applyIfAnd = {"UseArrayFlattening", "true", "ValueTypePassFieldsAsArgs", "true"}, failOn = {ALLOC_OF_MYVALUE_KLASS}) - @IR(applyIfAnd = {"UseArrayFlattening", "false", "InlineTypePassFieldsAsArgs", "false"}, + @IR(applyIfAnd = {"UseArrayFlattening", "false", "ValueTypePassFieldsAsArgs", "false"}, failOn = {ALLOC_OF_MYVALUE_KLASS}) public void test23(MyValue1 val) { MyValue1[] arr = (MyValue1[])ValueClass.newNullRestrictedNonAtomicArray(MyValue1.class, 2, MyValue1.DEFAULT); @@ -1020,7 +1020,7 @@ public void test33_verifier() { Asserts.assertEquals(result, test33Val); } - // Verify that static nullable inline-type fields are not + // Verify that static nullable value-type fields are not // treated as never-null by C2 when initialized at compile time. private static MyValue1 test34Val; @@ -2528,10 +2528,10 @@ public ObjectWrapper(Object obj) { // Test scalarization with phi referencing itself @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, failOn = {ALLOC_OF_MYVALUE_KLASS, STORE_OF_ANY_KLASS}, counts = {LOAD_OF_ANY_KLASS, " = 4"}) // 4 loads from the non-flattened MyValue1.v4 fields - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "false"}, failOn = {ALLOC_OF_MYVALUE_KLASS, STORE_OF_ANY_KLASS}) public long test86(MyValue1 vt) { ObjectWrapper val = new ObjectWrapper(vt); @@ -2660,7 +2660,7 @@ public void test90_verifier() throws Exception { // Test that scalarization does not introduce redundant/unused checks @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "false"}, failOn = {ALLOC_OF_MYVALUE_KLASS, CMP_N, CMP_P}) public Object test91(MyValue1 vt) { return vt; @@ -2687,7 +2687,7 @@ public void test92_verifier() { private static final MethodHandle refCheckCast = InstructionHelper.buildMethodHandle(MethodHandles.lookup(), "refCheckCast", - MethodType.methodType(MyValue2.class, TestNullableInlineTypes.class, MyValue1.class), + MethodType.methodType(MyValue2.class, TestNullableValueTypes.class, MyValue1.class), CODE -> { CODE. aload(1). @@ -2724,9 +2724,9 @@ public MyValue1 test94_helper3(Object vt) { // Test that calling convention optimization prevents buffering of arguments @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, counts = {ALLOC, " <= 2"}) // 1 MyValue2 allocation + 1 Integer allocation (if not the all-zero value) - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "false"}, counts = {ALLOC, " <= 3"}) // 1 MyValue1 allocation + 1 MyValue2 allocation + 1 Integer allocation (if not the all-zero value) public MyValue1 test94(MyValue1 vt) { MyValue1 res = test94_helper1(vt); @@ -2760,9 +2760,9 @@ public static MyValue1 test95_helper3(Object vt) { // Same as test94 but with static methods to trigger simple adapter logic @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, counts = {ALLOC, " <= 2"}) // 1 MyValue2 allocation + 1 Integer allocation (if not the all-zero value) - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "false"}, counts = {ALLOC, " <= 3"}) // 1 MyValue1 allocation + 1 MyValue2 allocation + 1 Integer allocation (if not the all-zero value) public static MyValue1 test95(MyValue1 vt) { MyValue1 res = test95_helper1(vt); @@ -2796,9 +2796,9 @@ public MyValue2 test96_helper3(boolean b) { // Test that calling convention optimization prevents buffering of return values @Test - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, failOn = {ALLOC}) - @IR(applyIf = {"InlineTypeReturnedAsFields", "false"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "false"}, counts = {ALLOC, " <= 1"}) // No allocation required if the MyValue2 return is the all-zero value public MyValue2 test96(int c, boolean b) { MyValue2 res = null; @@ -2845,9 +2845,9 @@ public MyValue3 test97_helper3(boolean b) { // Same as test96 but with MyValue3 return @Test - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, failOn = {ALLOC}) - @IR(applyIf = {"InlineTypeReturnedAsFields", "false"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "false"}, counts = {ALLOC, " <= 1"}) // No allocation required if the MyValue3 return is the all-zero value public MyValue3 test97(int c, boolean b) { MyValue3 res = null; @@ -3125,7 +3125,7 @@ public void test107_verifier() { } @Test - void test108(TestNullableInlineTypes t, MyValue104 arg) { + void test108(TestNullableValueTypes t, MyValue104 arg) { t.field2 = arg; } @@ -3141,7 +3141,7 @@ public void test108_verifier() { @Test void test109() { - TestNullableInlineTypes t = null; + TestNullableValueTypes t = null; t.field2 = null; } @@ -3216,7 +3216,7 @@ public void test113_verifier() { } @Test - void test114(TestNullableInlineTypes t, MyValueEmpty arg) { + void test114(TestNullableValueTypes t, MyValueEmpty arg) { t.field4 = arg; } @@ -3232,7 +3232,7 @@ public void test114_verifier() { @Test void test115(MyValueEmpty arg) { - TestNullableInlineTypes t = null; + TestNullableValueTypes t = null; t.field4 = arg; } diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestOnStackReplacement.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestOnStackReplacement.java similarity index 97% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestOnStackReplacement.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestOnStackReplacement.java index cdc1bc09e54f..c02a3d4c9c9e 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestOnStackReplacement.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestOnStackReplacement.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.*; import jdk.test.lib.Asserts; @@ -34,8 +34,8 @@ import static compiler.lib.ir_framework.IRNode.LOAD_OF_ANY_KLASS; import static compiler.lib.ir_framework.IRNode.STORE_OF_ANY_KLASS; -import static compiler.valhalla.inlinetypes.InlineTypes.rI; -import static compiler.valhalla.inlinetypes.InlineTypes.rL; +import static compiler.valhalla.valuetypes.ValueTypes.rI; +import static compiler.valhalla.valuetypes.ValueTypes.rL; /* * @test @@ -124,10 +124,10 @@ public class TestOnStackReplacement { public static void main(String[] args) throws Throwable { - Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; + Scenario[] scenarios = ValueTypes.DEFAULT_SCENARIOS; scenarios[3].addFlags("-XX:+UnlockDiagnosticVMOptions", "-XX:-UseArrayFlattening"); - InlineTypes.getFramework() + ValueTypes.getFramework() .addScenarios(scenarios[Integer.parseInt(args[0])]) .addHelperClasses(MyValue1.class, MyValue2.class, diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestOopsInReturnConvention.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestOopsInReturnConvention.java similarity index 83% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestOopsInReturnConvention.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestOopsInReturnConvention.java index 685ac396b408..934166f366d8 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestOopsInReturnConvention.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestOopsInReturnConvention.java @@ -31,9 +31,9 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xbatch -XX:-TieredCompilation - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestOopsInReturnConvention::callee - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestOopsInReturnConvention*::verify - * compiler.valhalla.inlinetypes.TestOopsInReturnConvention Interpreted + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestOopsInReturnConvention::callee + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestOopsInReturnConvention*::verify + * compiler.valhalla.valuetypes.TestOopsInReturnConvention Interpreted */ /* @@ -46,9 +46,9 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xbatch - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestOopsInReturnConvention::callee - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestOopsInReturnConvention*::verify - * compiler.valhalla.inlinetypes.TestOopsInReturnConvention C1 + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestOopsInReturnConvention::callee + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestOopsInReturnConvention*::verify + * compiler.valhalla.valuetypes.TestOopsInReturnConvention C1 */ /* @@ -61,9 +61,9 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xbatch - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestOopsInReturnConvention::callee - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestOopsInReturnConvention*::verify - * compiler.valhalla.inlinetypes.TestOopsInReturnConvention C2 + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestOopsInReturnConvention::callee + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestOopsInReturnConvention*::verify + * compiler.valhalla.valuetypes.TestOopsInReturnConvention C2 */ /* @@ -77,9 +77,9 @@ * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xbatch -XX:-TieredCompilation * -XX:+IgnoreUnrecognizedVMOptions -XX:+StressCallingConvention - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestOopsInReturnConvention::callee - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestOopsInReturnConvention*::verify - * compiler.valhalla.inlinetypes.TestOopsInReturnConvention Interpreted + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestOopsInReturnConvention::callee + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestOopsInReturnConvention*::verify + * compiler.valhalla.valuetypes.TestOopsInReturnConvention Interpreted */ /* @@ -92,9 +92,9 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+StressCallingConvention - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestOopsInReturnConvention::callee - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestOopsInReturnConvention*::verify - * compiler.valhalla.inlinetypes.TestOopsInReturnConvention C1 + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestOopsInReturnConvention::callee + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestOopsInReturnConvention*::verify + * compiler.valhalla.valuetypes.TestOopsInReturnConvention C1 */ /* @@ -107,9 +107,9 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xbatch -XX:-TieredCompilation -XX:+IgnoreUnrecognizedVMOptions -XX:+StressCallingConvention - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestOopsInReturnConvention::callee - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestOopsInReturnConvention*::verify - * compiler.valhalla.inlinetypes.TestOopsInReturnConvention C2 + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestOopsInReturnConvention::callee + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestOopsInReturnConvention*::verify + * compiler.valhalla.valuetypes.TestOopsInReturnConvention C2 */ /* @@ -123,9 +123,9 @@ * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xbatch -XX:-TieredCompilation * -XX:+IgnoreUnrecognizedVMOptions -XX:-PreloadClasses - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestOopsInReturnConvention::callee - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestOopsInReturnConvention*::verify - * compiler.valhalla.inlinetypes.TestOopsInReturnConvention Interpreted + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestOopsInReturnConvention::callee + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestOopsInReturnConvention*::verify + * compiler.valhalla.valuetypes.TestOopsInReturnConvention Interpreted */ /* @@ -139,9 +139,9 @@ * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xbatch * -XX:+IgnoreUnrecognizedVMOptions -XX:-PreloadClasses - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestOopsInReturnConvention::callee - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestOopsInReturnConvention*::verify - * compiler.valhalla.inlinetypes.TestOopsInReturnConvention C1 + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestOopsInReturnConvention::callee + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestOopsInReturnConvention*::verify + * compiler.valhalla.valuetypes.TestOopsInReturnConvention C1 */ /* @@ -155,13 +155,13 @@ * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xbatch -XX:-TieredCompilation * -XX:+IgnoreUnrecognizedVMOptions -XX:-PreloadClasses - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestOopsInReturnConvention::callee - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestOopsInReturnConvention*::verify - * compiler.valhalla.inlinetypes.TestOopsInReturnConvention C2 + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestOopsInReturnConvention::callee + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestOopsInReturnConvention*::verify + * compiler.valhalla.valuetypes.TestOopsInReturnConvention C2 */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.lang.reflect.Method; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestOptimizeKlassCmp.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestOptimizeKlassCmp.java similarity index 95% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestOptimizeKlassCmp.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestOptimizeKlassCmp.java index e9f98ccbad90..3c333b7a184f 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestOptimizeKlassCmp.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestOptimizeKlassCmp.java @@ -27,10 +27,10 @@ * @summary Verify that Parse::optimize_cmp_with_klass() works with value classes. * @library /test/lib * @enablePreview - * @run main/othervm -Xbatch compiler.valhalla.inlinetypes.TestOptimizeKlassCmp + * @run main/othervm -Xbatch compiler.valhalla.valuetypes.TestOptimizeKlassCmp */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestOptimizePtrCompare.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestOptimizePtrCompare.java similarity index 55% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestOptimizePtrCompare.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestOptimizePtrCompare.java index df4b3d91f0b1..b4d71ded8e9e 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestOptimizePtrCompare.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestOptimizePtrCompare.java @@ -31,15 +31,15 @@ * @run driver ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.*; public class TestOptimizePtrCompare { public static void main(String[] args) { - TestFramework.runWithFlags("--enable-preview", "-XX:+InlineTypePassFieldsAsArgs", "-XX:+InlineTypeReturnedAsFields"); - TestFramework.runWithFlags("--enable-preview", "-XX:-InlineTypePassFieldsAsArgs", "-XX:+InlineTypeReturnedAsFields"); - TestFramework.runWithFlags("--enable-preview", "-XX:+InlineTypePassFieldsAsArgs", "-XX:-InlineTypeReturnedAsFields"); - TestFramework.runWithFlags("--enable-preview", "-XX:-InlineTypePassFieldsAsArgs", "-XX:-InlineTypeReturnedAsFields"); + TestFramework.runWithFlags("--enable-preview", "-XX:+ValueTypePassFieldsAsArgs", "-XX:+ValueTypeReturnedAsFields"); + TestFramework.runWithFlags("--enable-preview", "-XX:-ValueTypePassFieldsAsArgs", "-XX:+ValueTypeReturnedAsFields"); + TestFramework.runWithFlags("--enable-preview", "-XX:+ValueTypePassFieldsAsArgs", "-XX:-ValueTypeReturnedAsFields"); + TestFramework.runWithFlags("--enable-preview", "-XX:-ValueTypePassFieldsAsArgs", "-XX:-ValueTypeReturnedAsFields"); } @Test @@ -67,10 +67,10 @@ static value class MyValue { } @Test - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "true", "InlineTypeReturnedAsFields", "true"}, failOn = {IRNode.CMP_P_OR_N}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "false", "InlineTypeReturnedAsFields", "true"}, counts = {IRNode.CMP_P_OR_N, "2", IRNode.CMP_I, "1"}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "true", "InlineTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "2"}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "false", "InlineTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "3"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "true", "ValueTypeReturnedAsFields", "true"}, failOn = {IRNode.CMP_P_OR_N}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "false", "ValueTypeReturnedAsFields", "true"}, counts = {IRNode.CMP_P_OR_N, "2", IRNode.CMP_I, "1"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "true", "ValueTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "2"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "false", "ValueTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "3"}) public static void test2() { Object notUsed = new Object(); // make sure EA runs MyValue arg = new MyValue(null); @@ -108,10 +108,10 @@ static value class MyValue3 { static Object fieldO = new Object(); @Test - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "true", "InlineTypeReturnedAsFields", "true"}, failOn = {IRNode.CMP_P_OR_N}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "false", "InlineTypeReturnedAsFields", "true"}, counts = {IRNode.CMP_P_OR_N, "2", IRNode.CMP_I, "1"}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "true", "InlineTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "2"}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "false", "InlineTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "3"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "true", "ValueTypeReturnedAsFields", "true"}, failOn = {IRNode.CMP_P_OR_N}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "false", "ValueTypeReturnedAsFields", "true"}, counts = {IRNode.CMP_P_OR_N, "2", IRNode.CMP_I, "1"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "true", "ValueTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "2"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "false", "ValueTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "3"}) public static void test3() { Object notUsed = new Object(); // make sure EA runs MyValue2 arg = new MyValue2(null, fieldO); @@ -127,10 +127,10 @@ static MyValue2 notInlined3(MyValue2 v) { } @Test - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "true", "InlineTypeReturnedAsFields", "true"}, counts = {IRNode.CMP_P_OR_N, "1"}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "false", "InlineTypeReturnedAsFields", "true"}, counts = {IRNode.CMP_P_OR_N, "2"}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "true", "InlineTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "1"}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "false", "InlineTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "2"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "true", "ValueTypeReturnedAsFields", "true"}, counts = {IRNode.CMP_P_OR_N, "1"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "false", "ValueTypeReturnedAsFields", "true"}, counts = {IRNode.CMP_P_OR_N, "2"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "true", "ValueTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "1"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "false", "ValueTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "2"}) public static void test4() { Object notUsed = new Object(); // make sure EA runs MyValue arg = new MyValue(null); @@ -146,10 +146,10 @@ static Object notInlined4(MyValue v) { } @Test - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "true", "InlineTypeReturnedAsFields", "true"}, failOn = {IRNode.CMP_P_OR_N}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "false", "InlineTypeReturnedAsFields", "true"}, counts = {IRNode.CMP_P_OR_N, "2", IRNode.CMP_I, "1"}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "true", "InlineTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "2"}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "false", "InlineTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "3"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "true", "ValueTypeReturnedAsFields", "true"}, failOn = {IRNode.CMP_P_OR_N}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "false", "ValueTypeReturnedAsFields", "true"}, counts = {IRNode.CMP_P_OR_N, "2", IRNode.CMP_I, "1"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "true", "ValueTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "2"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "false", "ValueTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "3"}) public static void test5() { Object notUsed = new Object(); // make sure EA runs MyValue2 arg = new MyValue2(fieldO, null); @@ -166,10 +166,10 @@ static MyValue2 notInlined5(MyValue2 v) { // TODO 8376254: C1 bails out if the type of the nullable flat field is uninitialized @Test(allowNotCompilable = true) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "true", "InlineTypeReturnedAsFields", "true"}, failOn = {IRNode.CMP_P_OR_N}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "false", "InlineTypeReturnedAsFields", "true"}, counts = {IRNode.CMP_P_OR_N, "4", IRNode.CMP_I, "2"}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "true", "InlineTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "2"}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "false", "InlineTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "5"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "true", "ValueTypeReturnedAsFields", "true"}, failOn = {IRNode.CMP_P_OR_N}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "false", "ValueTypeReturnedAsFields", "true"}, counts = {IRNode.CMP_P_OR_N, "4", IRNode.CMP_I, "2"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "true", "ValueTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "2"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "false", "ValueTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "5"}) public static void test6() { Object notUsed = new Object(); // make sure EA runs MyValue v1 = new MyValue(fieldO); @@ -187,10 +187,10 @@ static MyValue3 notInlined6(MyValue v1, MyValue2 v2, MyValue3 v3) { } @Test - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "true", "InlineTypeReturnedAsFields", "true"}, counts = {IRNode.CMP_P_OR_N, "1"}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "false", "InlineTypeReturnedAsFields", "true"}, counts = {IRNode.CMP_P_OR_N, "2", IRNode.CMP_I, "1"}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "true", "InlineTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "2"}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "false", "InlineTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "3"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "true", "ValueTypeReturnedAsFields", "true"}, counts = {IRNode.CMP_P_OR_N, "1"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "false", "ValueTypeReturnedAsFields", "true"}, counts = {IRNode.CMP_P_OR_N, "2", IRNode.CMP_I, "1"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "true", "ValueTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "2"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "false", "ValueTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "3"}) public static void test7() { Object notUsed = new Object(); // make sure EA runs MyValue2 arg = new MyValue2(fieldO, null); @@ -209,10 +209,10 @@ static MyValue2 notInlined7(MyValue2 v, boolean flag) { } @Test - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "true", "InlineTypeReturnedAsFields", "true"}, counts = {IRNode.CMP_P_OR_N, "1"}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "false", "InlineTypeReturnedAsFields", "true"}, counts = {IRNode.CMP_P_OR_N, "2", IRNode.CMP_I, "1"}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "true", "InlineTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "2"}) - @IR(applyIfAnd = {"InlineTypePassFieldsAsArgs", "false", "InlineTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "3"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "true", "ValueTypeReturnedAsFields", "true"}, counts = {IRNode.CMP_P_OR_N, "1"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "false", "ValueTypeReturnedAsFields", "true"}, counts = {IRNode.CMP_P_OR_N, "2", IRNode.CMP_I, "1"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "true", "ValueTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "2"}) + @IR(applyIfAnd = {"ValueTypePassFieldsAsArgs", "false", "ValueTypeReturnedAsFields", "false"}, counts = {IRNode.CMP_P_OR_N, "3"}) public static void test8() { Object notUsed = new Object(); // make sure EA runs MyValue2 arg = new MyValue2(fieldO, null); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestPollutedCallsiteProfileInlineType.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestPollutedCallsiteProfileValueType.java similarity index 93% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestPollutedCallsiteProfileInlineType.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestPollutedCallsiteProfileValueType.java index 5bd2bf5eabb6..6f7eb31a1f65 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestPollutedCallsiteProfileInlineType.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestPollutedCallsiteProfileValueType.java @@ -21,12 +21,12 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; /* * @test * @bug 8380927 - * @summary Polluted callsite profiling must not break the idempotence of InlineTypeNode::Value + * @summary Polluted callsite profiling must not break the idempotence of ValueTypeNode::Value * @library /test/lib / * @enablePreview * @modules java.base/jdk.internal.value @@ -36,12 +36,12 @@ * -XX:-TieredCompilation -XX:VerifyIterativeGVN=1110 * -XX:CompileCommand=compileonly,${test.main.class}::test * -XX:CompileCommand=dontinline,${test.main.class}::call - * -XX:+AlwaysIncrementalInline -XX:-InlineTypeReturnedAsFields + * -XX:+AlwaysIncrementalInline -XX:-ValueTypeReturnedAsFields * -XX:TypeProfileLevel=222 ${test.main.class} * @run main ${test.main.class} */ -public class TestPollutedCallsiteProfileInlineType { +public class TestPollutedCallsiteProfileValueType { static value class MyValue {} static MyValue call(boolean throwRE) { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestPushThroughPhiNotification.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestPushThroughPhiNotification.java similarity index 91% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestPushThroughPhiNotification.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestPushThroughPhiNotification.java index b8c51b5ad3f8..622801ef6d22 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestPushThroughPhiNotification.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestPushThroughPhiNotification.java @@ -21,11 +21,11 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; /* * @test - * @summary Test that Phi users are revisited when InlineTypeNode is pushed through. + * @summary Test that Phi users are revisited when ValueTypeNode is pushed through. * @bug 8386067 * @enablePreview * @run main ${test.main.class} @@ -50,7 +50,7 @@ static boolean test() { } } // Phi with (deep) CmpL user from acmp implementation that needs to - // be re-visited by IGVN when InlineTypeNode is pushed through. + // be re-visited by IGVN when ValueTypeNode is pushed through. return lhs == rhs; } diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestPushInlineTypeDownDeadBranch.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestPushValueTypeDownDeadBranch.java similarity index 70% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestPushInlineTypeDownDeadBranch.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestPushValueTypeDownDeadBranch.java index f9570e5995e3..b6fcd8b674d2 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestPushInlineTypeDownDeadBranch.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestPushValueTypeDownDeadBranch.java @@ -24,7 +24,7 @@ /* * @test * @bug 8389088 - * @summary Test that PushInlineTypeDown correctly handles dying branches in do_transform(). + * @summary Test that PushValueTypeDown correctly handles dying branches in do_transform(). * @library /test/lib * @enablePreview * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions @@ -36,11 +36,11 @@ * @run main ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; -public class TestPushInlineTypeDownDeadBranch { +public class TestPushValueTypeDownDeadBranch { public static void main(String[] args) { for (int i = 0; i < 10000; i++) { Asserts.assertEQ(test(), null); @@ -51,14 +51,14 @@ static V test() { // null // | // v - // Before Incremental Inlining: CallStaticJava -> OpaqueParse -> CastPP -> CheckCastPP -> Phi -> InlineType -> Return - // After Incremental Inlining: InlineType(null) -> OpaqueParse -> CastPP -> CheckCastPP -> Phi -> InlineType -> Return - // During IGVN: InlineType(null) -> CastPP -> CheckCastPP -> Phi -> InlineType -> Return - // InlineType(null) -> CastPP -> CheckCastPP -> Phi -> InlineType -> Return - // InlineType(null) -> InlineType -> Return - // Before Patch: InlineType(TOP /* wrong! */) -> InlineType -> Return + // Before Incremental Inlining: CallStaticJava -> OpaqueParse -> CastPP -> CheckCastPP -> Phi -> ValueType -> Return + // After Incremental Inlining: ValueType(null) -> OpaqueParse -> CastPP -> CheckCastPP -> Phi -> ValueType -> Return + // During IGVN: ValueType(null) -> CastPP -> CheckCastPP -> Phi -> ValueType -> Return + // ValueType(null) -> CastPP -> CheckCastPP -> Phi -> ValueType -> Return + // ValueType(null) -> ValueType -> Return + // Before Patch: ValueType(TOP /* wrong! */) -> ValueType -> Return // - // After Patch: InlineType(null) -> InlineType -> Return + // After Patch: ValueType(null) -> ValueType -> Return Object obj = foo(null); return (V)obj; } diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestReallocWithoutEA.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestReallocWithoutEA.java similarity index 94% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestReallocWithoutEA.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestReallocWithoutEA.java index bb316a73fc23..977fb46bc4d0 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestReallocWithoutEA.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestReallocWithoutEA.java @@ -21,9 +21,9 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; -import static compiler.valhalla.inlinetypes.InlineTypes.*; +import static compiler.valhalla.valuetypes.ValueTypes.*; /* * @test diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestReferenceArrayClone.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestReferenceArrayClone.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestReferenceArrayClone.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestReferenceArrayClone.java index df5f4878090d..90ed13215c93 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestReferenceArrayClone.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestReferenceArrayClone.java @@ -38,7 +38,7 @@ * ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.value.ValueClass; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestReturnBufferClassInitialization.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestReturnBufferClassInitialization.java similarity index 99% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestReturnBufferClassInitialization.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestReturnBufferClassInitialization.java index e276230a8c71..c05e863f16a5 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestReturnBufferClassInitialization.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestReturnBufferClassInitialization.java @@ -36,7 +36,7 @@ * ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestSafepointAtPollReturn.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSafepointAtPollReturn.java similarity index 92% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestSafepointAtPollReturn.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSafepointAtPollReturn.java index 68414d71916a..ed4a19877fec 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestSafepointAtPollReturn.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSafepointAtPollReturn.java @@ -25,11 +25,11 @@ * @test * @summary Test that oop fields of value classes are preserved over safepoints at returns. * @enablePreview - * @run main/othervm -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestSafepointAtPollReturn::test* -XX:+UnlockDiagnosticVMOptions - * -XX:+SafepointALot -XX:-TieredCompilation -XX:+UseTLAB compiler.valhalla.inlinetypes.TestSafepointAtPollReturn + * @run main/othervm -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestSafepointAtPollReturn::test* -XX:+UnlockDiagnosticVMOptions + * -XX:+SafepointALot -XX:-TieredCompilation -XX:+UseTLAB compiler.valhalla.valuetypes.TestSafepointAtPollReturn */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; public class TestSafepointAtPollReturn { static Integer INT_VAL = 0; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestSafepointScalarizationNodeGrowth.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSafepointScalarizationNodeGrowth.java similarity index 99% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestSafepointScalarizationNodeGrowth.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSafepointScalarizationNodeGrowth.java index 3ab61da78d69..164a9d30ea2a 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestSafepointScalarizationNodeGrowth.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSafepointScalarizationNodeGrowth.java @@ -33,7 +33,7 @@ * ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; public class TestSafepointScalarizationNodeGrowth { static int counter; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestSafepointScalarizationNodeLimit.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSafepointScalarizationNodeLimit.java similarity index 99% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestSafepointScalarizationNodeLimit.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSafepointScalarizationNodeLimit.java index f3eb37856d04..171bf542d8c2 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestSafepointScalarizationNodeLimit.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSafepointScalarizationNodeLimit.java @@ -36,7 +36,7 @@ * ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestScalarizeVboxWithScalarizedValues.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestScalarizeVboxWithScalarizedValues.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestScalarizeVboxWithScalarizedValues.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestScalarizeVboxWithScalarizedValues.java index 723028b1eeab..155aa3eca8af 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestScalarizeVboxWithScalarizedValues.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestScalarizeVboxWithScalarizedValues.java @@ -42,7 +42,7 @@ * @run main ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.incubator.vector.*; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestScalarizeVboxWithScalarizedValuesAndHalf.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestScalarizeVboxWithScalarizedValuesAndHalf.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestScalarizeVboxWithScalarizedValuesAndHalf.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestScalarizeVboxWithScalarizedValuesAndHalf.java index 05e018c09844..4fd87edfdbb1 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestScalarizeVboxWithScalarizedValuesAndHalf.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestScalarizeVboxWithScalarizedValuesAndHalf.java @@ -42,7 +42,7 @@ * @run main ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.incubator.vector.*; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestScalarizedCCReceiverOnlyEntryAllocBuffer.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestScalarizedCCReceiverOnlyEntryAllocBuffer.java similarity index 90% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestScalarizedCCReceiverOnlyEntryAllocBuffer.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestScalarizedCCReceiverOnlyEntryAllocBuffer.java index c241905fe786..a535f8c5ad21 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestScalarizedCCReceiverOnlyEntryAllocBuffer.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestScalarizedCCReceiverOnlyEntryAllocBuffer.java @@ -24,15 +24,15 @@ /** * @test * @bug 8381563 - * @summary [lworld] SharedRuntime::allocate_inline_types hits "buffer not of expected class" assert + * @summary [lworld] SharedRuntime::allocate_value_types hits "buffer not of expected class" assert * @enablePreview * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64") * @run main/othervm -XX:-BackgroundCompilation - * -XX:CompileOnly=compiler.valhalla.inlinetypes.TestScalarizedCCReceiverOnlyEntryAllocBuffer::test1 + * -XX:CompileOnly=compiler.valhalla.valuetypes.TestScalarizedCCReceiverOnlyEntryAllocBuffer::test1 * ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; public class TestScalarizedCCReceiverOnlyEntryAllocBuffer { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestScalarizedCallingConventionLimits.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestScalarizedCallingConventionLimits.java similarity index 99% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestScalarizedCallingConventionLimits.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestScalarizedCallingConventionLimits.java index 0287e6b4b333..55462ffede4d 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestScalarizedCallingConventionLimits.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestScalarizedCallingConventionLimits.java @@ -40,7 +40,7 @@ * ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.util.function.IntFunction; import java.util.List; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestSpeculateArrayAccess.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSpeculateArrayAccess.java similarity index 93% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestSpeculateArrayAccess.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSpeculateArrayAccess.java index d0c2dd6a7e0c..0fb7627e04e4 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestSpeculateArrayAccess.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSpeculateArrayAccess.java @@ -28,13 +28,13 @@ * @summary Test that speculative array access checks do not cause a load to be wrongly hoisted before its range check. * @run main/othervm -XX:CompileCommand=dontinline,*::* -XX:CompileCommand=compileonly,*TestSpeculateArrayAccess::test * -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:StressSeed=1202682944 - * compiler.valhalla.inlinetypes.TestSpeculateArrayAccess + * compiler.valhalla.valuetypes.TestSpeculateArrayAccess * @run main/othervm -XX:CompileCommand=dontinline,*::* -XX:CompileCommand=compileonly,*TestSpeculateArrayAccess::test * -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM - * compiler.valhalla.inlinetypes.TestSpeculateArrayAccess + * compiler.valhalla.valuetypes.TestSpeculateArrayAccess */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; public class TestSpeculateArrayAccess { static Object[] oArr = new Object[100]; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestStaleArrayTypeInArrayStore.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestStaleArrayTypeInArrayStore.java similarity index 97% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestStaleArrayTypeInArrayStore.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestStaleArrayTypeInArrayStore.java index 4d728dfe98d0..2433c90ee0b2 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestStaleArrayTypeInArrayStore.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestStaleArrayTypeInArrayStore.java @@ -29,7 +29,7 @@ * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,${test.main.class}::test ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; public class TestStaleArrayTypeInArrayStore { static Object[] array = new Object[1]; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestStressReturnBuffering.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestStressReturnBuffering.java similarity index 92% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestStressReturnBuffering.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestStressReturnBuffering.java index 25fec2d495e4..e08af3b5963d 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestStressReturnBuffering.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestStressReturnBuffering.java @@ -27,11 +27,11 @@ * @summary Verify that TLAB allocated buffer initialization when returning a value object works properly with oops. * @library /test/lib * @enablePreview - * @run main/othervm -XX:CompileCommand=exclude,compiler.valhalla.inlinetypes.TestStressReturnBuffering::caller -Xmx10m - * compiler.valhalla.inlinetypes.TestStressReturnBuffering + * @run main/othervm -XX:CompileCommand=exclude,compiler.valhalla.valuetypes.TestStressReturnBuffering::caller -Xmx10m + * compiler.valhalla.valuetypes.TestStressReturnBuffering */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestStrictFieldBarriers.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestStrictFieldBarriers.java similarity index 84% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestStrictFieldBarriers.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestStrictFieldBarriers.java index 9d0015e2a215..41571ad52450 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestStrictFieldBarriers.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestStrictFieldBarriers.java @@ -29,30 +29,30 @@ * @enablePreview * @compile TestStrictFieldBarriers.java * @run driver jdk.test.lib.helpers.StrictProcessor - * compiler.valhalla.inlinetypes.TestStrictFieldBarriers$A1 - * compiler.valhalla.inlinetypes.TestStrictFieldBarriers$B1 - * compiler.valhalla.inlinetypes.TestStrictFieldBarriers$C1 - * compiler.valhalla.inlinetypes.TestStrictFieldBarriers$A2 - * compiler.valhalla.inlinetypes.TestStrictFieldBarriers$B2 - * compiler.valhalla.inlinetypes.TestStrictFieldBarriers$C2 - * @run main/othervm compiler.valhalla.inlinetypes.TestStrictFieldBarriers + * compiler.valhalla.valuetypes.TestStrictFieldBarriers$A1 + * compiler.valhalla.valuetypes.TestStrictFieldBarriers$B1 + * compiler.valhalla.valuetypes.TestStrictFieldBarriers$C1 + * compiler.valhalla.valuetypes.TestStrictFieldBarriers$A2 + * compiler.valhalla.valuetypes.TestStrictFieldBarriers$B2 + * compiler.valhalla.valuetypes.TestStrictFieldBarriers$C2 + * @run main/othervm compiler.valhalla.valuetypes.TestStrictFieldBarriers * @run main/othervm -Xbatch - * compiler.valhalla.inlinetypes.TestStrictFieldBarriers + * compiler.valhalla.valuetypes.TestStrictFieldBarriers * @run main/othervm -Xbatch -XX:TieredStopAtLevel=1 - * compiler.valhalla.inlinetypes.TestStrictFieldBarriers + * compiler.valhalla.valuetypes.TestStrictFieldBarriers * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,java.lang.Object::*init* - * compiler.valhalla.inlinetypes.TestStrictFieldBarriers + * compiler.valhalla.valuetypes.TestStrictFieldBarriers * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,StrictInitTest$A::*init* - * compiler.valhalla.inlinetypes.TestStrictFieldBarriers + * compiler.valhalla.valuetypes.TestStrictFieldBarriers * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,StrictInitTest$B::*init* - * compiler.valhalla.inlinetypes.TestStrictFieldBarriers + * compiler.valhalla.valuetypes.TestStrictFieldBarriers * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,StrictInitTest$C::*init* - * compiler.valhalla.inlinetypes.TestStrictFieldBarriers + * compiler.valhalla.valuetypes.TestStrictFieldBarriers * @run main/othervm -Xbatch -XX:CompileCommand=dontinline,*::*init* - * compiler.valhalla.inlinetypes.TestStrictFieldBarriers + * compiler.valhalla.valuetypes.TestStrictFieldBarriers */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.helpers.StrictInit; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestStrictFinalExitMemBar.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestStrictFinalExitMemBar.java similarity index 95% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestStrictFinalExitMemBar.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestStrictFinalExitMemBar.java index 2078f3d65f16..61b79f0cc842 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestStrictFinalExitMemBar.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestStrictFinalExitMemBar.java @@ -30,12 +30,12 @@ * @enablePreview * @compile TestStrictFinalExitMemBar.java * @run driver jdk.test.lib.helpers.StrictProcessor - * compiler.valhalla.inlinetypes.TestStrictFinalExitMemBar$StrictFinalHolder - * compiler.valhalla.inlinetypes.TestStrictFinalExitMemBar$StrictNonFinalHolder + * compiler.valhalla.valuetypes.TestStrictFinalExitMemBar$StrictFinalHolder + * compiler.valhalla.valuetypes.TestStrictFinalExitMemBar$StrictNonFinalHolder * @run driver ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.*; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestSubstitutabilityExpansionAfterMacro.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSubstitutabilityExpansionAfterMacro.java similarity index 82% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestSubstitutabilityExpansionAfterMacro.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSubstitutabilityExpansionAfterMacro.java index 462d69477e61..b08f44ea3b7b 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestSubstitutabilityExpansionAfterMacro.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSubstitutabilityExpansionAfterMacro.java @@ -40,12 +40,12 @@ static boolean equals(Object a, Object b) { return a == b; } - // Below tests trigger InlineTypeNode::can_emit_substitutability_check only + // Below tests trigger ValueTypeNode::can_emit_substitutability_check only // after macro expansion. - // EA leaves the right operand as Phi(InlineType, LoadN). - // The cast creates a buffered InlineTypeNode whose oop is a cast of that phi. - // After InlineTypeNode removal after macro expansion, both operands are equivalent. + // EA leaves the right operand as Phi(ValueType, LoadN). + // The cast creates a buffered ValueTypeNode whose oop is a cast of that phi. + // After ValueTypeNode removal after macro expansion, both operands are equivalent. static boolean test1(boolean b) { Box box = b ? new Box(new MyValue(null)) : new Box(null); if (box.value == null) { @@ -54,14 +54,14 @@ static boolean test1(boolean b) { return equals((MyValue) box.value, box.value); } - // InlineTypeNode removal changes Phi(InlineType(oop=null), exact Object) + // ValueTypeNode removal changes Phi(ValueType(oop=null), exact Object) // to Phi(null, exact Object) as the right operand. The phi then becomes an exact - // nullable Object and can_be_inline_type() changes to false after macro expansion. + // nullable Object and can_be_value_type() changes to false after macro expansion. static boolean test2(Object obj, boolean b) { return equals(obj, b ? (Integer) null : new Object()); } - // Both operands are phis of an InlineTypeNode and its oop. After InlineTypeNode + // Both operands are phis of an ValueTypeNode and its oop. After ValueTypeNode // removal, both phis collapse to the same oop and the operands become equivalent // after macro expansion. static boolean test3(Object obj, boolean b) { @@ -86,4 +86,3 @@ public static void main(String[] args) { } } } - diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestSubstitutabilityWithCOH.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSubstitutabilityWithCOH.java similarity index 100% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestSubstitutabilityWithCOH.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestSubstitutabilityWithCOH.java diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestTearing.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestTearing.java similarity index 97% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestTearing.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestTearing.java index 712bdc9e0d05..da8ec541405e 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestTearing.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestTearing.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.lang.invoke.*; import java.lang.reflect.Field; @@ -49,7 +49,7 @@ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI -XX:-UseFieldFlattening -XX:-UseArrayFlattening * -XX:+StressGCM -XX:+StressLCM - * compiler.valhalla.inlinetypes.TestTearing + * compiler.valhalla.valuetypes.TestTearing */ /* @@ -68,7 +68,7 @@ * -XX:+WhiteBoxAPI -XX:-UseFieldFlattening -XX:-UseArrayFlattening * -XX:+StressGCM -XX:+StressLCM * -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline - * compiler.valhalla.inlinetypes.TestTearing + * compiler.valhalla.valuetypes.TestTearing */ /* @@ -87,7 +87,7 @@ * -XX:+WhiteBoxAPI -XX:-UseFieldFlattening -XX:-UseArrayFlattening * -XX:CompileCommand=dontinline,*::incrementAndCheck* * -XX:+StressGCM -XX:+StressLCM - * compiler.valhalla.inlinetypes.TestTearing + * compiler.valhalla.valuetypes.TestTearing */ /* @@ -107,7 +107,7 @@ * -XX:CompileCommand=dontinline,*::incrementAndCheck* * -XX:+StressGCM -XX:+StressLCM * -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline - * compiler.valhalla.inlinetypes.TestTearing + * compiler.valhalla.valuetypes.TestTearing */ /* @@ -125,7 +125,7 @@ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions * -XX:+WhiteBoxAPI -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseArrayFlattening * -Xcomp -XX:-TieredCompilation - * compiler.valhalla.inlinetypes.TestTearing + * compiler.valhalla.valuetypes.TestTearing */ /* @@ -143,7 +143,7 @@ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions * -XX:+WhiteBoxAPI -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseArrayFlattening * -XX:+StressGCM -XX:+StressLCM - * compiler.valhalla.inlinetypes.TestTearing + * compiler.valhalla.valuetypes.TestTearing */ /* @@ -162,7 +162,7 @@ * -XX:+WhiteBoxAPI -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseArrayFlattening * -XX:+StressGCM -XX:+StressLCM * -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline - * compiler.valhalla.inlinetypes.TestTearing + * compiler.valhalla.valuetypes.TestTearing */ /* @@ -181,7 +181,7 @@ * -XX:+WhiteBoxAPI -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseArrayFlattening * -XX:CompileCommand=dontinline,*::incrementAndCheck* * -XX:+StressGCM -XX:+StressLCM - * compiler.valhalla.inlinetypes.TestTearing + * compiler.valhalla.valuetypes.TestTearing */ /* @@ -201,7 +201,7 @@ * -XX:CompileCommand=dontinline,*::incrementAndCheck* * -XX:+StressGCM -XX:+StressLCM * -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline - * compiler.valhalla.inlinetypes.TestTearing + * compiler.valhalla.valuetypes.TestTearing */ @LooselyConsistentValue diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestTrivialMethods.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestTrivialMethods.java similarity index 96% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestTrivialMethods.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestTrivialMethods.java index befcfc228f35..7b7ce657529e 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestTrivialMethods.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestTrivialMethods.java @@ -24,7 +24,7 @@ /** * @test * @bug 8275825 8289686 - * @summary Verify that trivial accessor methods operating on an inline type + * @summary Verify that trivial accessor methods operating on a value type * field are C2 compiled to enable scalarization of the arg/return value. * @requires vm.compiler2.enabled * @library /test/lib /compiler/whitebox / @@ -36,14 +36,14 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch - * -XX:+InlineTypePassFieldsAsArgs -XX:+InlineTypeReturnedAsFields + * -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields * -XX:+IgnoreUnrecognizedVMOptions -XX:-StressCallingConvention * -XX:CompileCommand=dontinline,*::getter* -XX:CompileCommand=dontinline,*::setter* * -XX:CompileCommand=dontinline,*::constantGetter* -XX:+PreloadClasses - * compiler.valhalla.inlinetypes.TestTrivialMethods + * compiler.valhalla.valuetypes.TestTrivialMethods */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.whitebox.CompilerWhiteBoxTest; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnexpectedMemBar.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnexpectedMemBar.java similarity index 94% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnexpectedMemBar.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnexpectedMemBar.java index d86e50796570..48455e6ad46d 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnexpectedMemBar.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnexpectedMemBar.java @@ -31,7 +31,7 @@ * -XX:-TieredCompilation -XX:-ReduceInitialCardMarks * -XX:+AlwaysIncrementalInline -Xbatch -XX:CompileCommand=compileonly,*TestUnexpectedMemBar::test* * -XX:+StressIGVN -XX:+StressGCM -XX:+StressLCM -XX:StressSeed=851121348 - * compiler.valhalla.inlinetypes.TestUnexpectedMemBar + * compiler.valhalla.valuetypes.TestUnexpectedMemBar */ /* @@ -44,7 +44,7 @@ * -XX:-TieredCompilation -XX:-ReduceInitialCardMarks -XX:+AlwaysIncrementalInline * -Xbatch -XX:CompileCommand=compileonly,*TestUnexpectedMemBar::test* * -XX:+StressIGVN -XX:+StressGCM -XX:+StressLCM - * compiler.valhalla.inlinetypes.TestUnexpectedMemBar + * compiler.valhalla.valuetypes.TestUnexpectedMemBar */ /* @@ -56,10 +56,10 @@ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions * -Xbatch -XX:CompileCommand=compileonly,*TestUnexpectedMemBar::test* * -XX:+StressIGVN -XX:+StressGCM -XX:+StressLCM - * compiler.valhalla.inlinetypes.TestUnexpectedMemBar + * compiler.valhalla.valuetypes.TestUnexpectedMemBar */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUninitializedFlatAccess.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUninitializedFlatAccess.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUninitializedFlatAccess.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUninitializedFlatAccess.java index 04aa43ed21ff..376f93f4a4ad 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUninitializedFlatAccess.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUninitializedFlatAccess.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUninitializedValueClass.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUninitializedValueClass.java similarity index 93% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUninitializedValueClass.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUninitializedValueClass.java index 455c517e3e0e..9f2f502fbf5d 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUninitializedValueClass.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUninitializedValueClass.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; /** * @test @@ -29,7 +29,7 @@ * @summary Test that uninitialized value class is properly handled by C2. * @enablePreview * @run main/othervm -XX:CompileCommand=compileonly,*:: -Xcomp -XX:-TieredCompilation - * compiler.valhalla.inlinetypes.TestUninitializedValueClass + * compiler.valhalla.valuetypes.TestUninitializedValueClass */ value class MyValueUninitValueClass { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnloadedCastType.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnloadedCastType.java similarity index 91% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnloadedCastType.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnloadedCastType.java index de01ca4de249..e56d4c8ec253 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnloadedCastType.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnloadedCastType.java @@ -26,11 +26,11 @@ * @summary Test casting of value objects to an unloaded type. * @enablePreview * @library /test/lib - * @run main/othervm -Xbatch -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestUnloadedCastType::test* - * compiler.valhalla.inlinetypes.TestUnloadedCastType + * @run main/othervm -Xbatch -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestUnloadedCastType::test* + * compiler.valhalla.valuetypes.TestUnloadedCastType */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnloadedReturnTypes.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnloadedReturnTypes.java similarity index 96% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnloadedReturnTypes.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnloadedReturnTypes.java index 6044fa53675a..f0ccad31ae86 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnloadedReturnTypes.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnloadedReturnTypes.java @@ -30,17 +30,17 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xbatch -XX:CompileCommand=dontinline,*::test* - * compiler.valhalla.inlinetypes.TestUnloadedReturnTypes + * compiler.valhalla.valuetypes.TestUnloadedReturnTypes * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+IgnoreUnrecognizedVMOptions -XX:-PreloadClasses * -Xbatch -XX:CompileCommand=dontinline,*::test* - * compiler.valhalla.inlinetypes.TestUnloadedReturnTypes + * compiler.valhalla.valuetypes.TestUnloadedReturnTypes * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+IgnoreUnrecognizedVMOptions -XX:-PreloadClasses -XX:+AlwaysIncrementalInline - * compiler.valhalla.inlinetypes.TestUnloadedReturnTypes + * compiler.valhalla.valuetypes.TestUnloadedReturnTypes */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.lang.reflect.Method; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnloadedInlineTypeArray.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnloadedValueTypeArray.java similarity index 62% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnloadedInlineTypeArray.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnloadedValueTypeArray.java index 724b53dfe126..11e06527d4b9 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnloadedInlineTypeArray.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnloadedValueTypeArray.java @@ -31,8 +31,8 @@ * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @run main/othervm -Xcomp - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestUnloadedInlineTypeArray::test* - * compiler.valhalla.inlinetypes.TestUnloadedInlineTypeArray + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestUnloadedValueTypeArray::test* + * compiler.valhalla.valuetypes.TestUnloadedValueTypeArray */ /* @@ -44,8 +44,8 @@ * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:-UseArrayFlattening - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestUnloadedInlineTypeArray::test* - * compiler.valhalla.inlinetypes.TestUnloadedInlineTypeArray + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestUnloadedValueTypeArray::test* + * compiler.valhalla.valuetypes.TestUnloadedValueTypeArray */ /* @@ -56,7 +56,7 @@ * @enablePreview * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation - * @run main/othervm -Xcomp compiler.valhalla.inlinetypes.TestUnloadedInlineTypeArray + * @run main/othervm -Xcomp compiler.valhalla.valuetypes.TestUnloadedValueTypeArray */ /* @@ -68,7 +68,7 @@ * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:-UseArrayFlattening - * compiler.valhalla.inlinetypes.TestUnloadedInlineTypeArray + * compiler.valhalla.valuetypes.TestUnloadedValueTypeArray */ /* @@ -80,8 +80,8 @@ * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @run main/othervm -Xcomp -XX:-TieredCompilation - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestUnloadedInlineTypeArray::test* - * compiler.valhalla.inlinetypes.TestUnloadedInlineTypeArray + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestUnloadedValueTypeArray::test* + * compiler.valhalla.valuetypes.TestUnloadedValueTypeArray */ /* @@ -93,8 +93,8 @@ * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:-TieredCompilation -XX:-UseArrayFlattening - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestUnloadedInlineTypeArray::test* - * compiler.valhalla.inlinetypes.TestUnloadedInlineTypeArray + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestUnloadedValueTypeArray::test* + * compiler.valhalla.valuetypes.TestUnloadedValueTypeArray */ /* @@ -106,7 +106,7 @@ * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @run main/othervm -Xcomp -XX:-TieredCompilation - * compiler.valhalla.inlinetypes.TestUnloadedInlineTypeArray + * compiler.valhalla.valuetypes.TestUnloadedValueTypeArray */ /* @@ -118,10 +118,10 @@ * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:-TieredCompilation -XX:-UseArrayFlattening - * compiler.valhalla.inlinetypes.TestUnloadedInlineTypeArray + * compiler.valhalla.valuetypes.TestUnloadedValueTypeArray */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; @@ -129,119 +129,119 @@ import jdk.internal.vm.annotation.LooselyConsistentValue; @LooselyConsistentValue -value class MyValue1UnloadedInlineTypeArray { +value class MyValue1UnloadedValueTypeArray { int foo; - private MyValue1UnloadedInlineTypeArray() { + private MyValue1UnloadedValueTypeArray() { foo = 0x42; } } @LooselyConsistentValue -value class MyValue2UnloadedInlineTypeArray { +value class MyValue2UnloadedValueTypeArray { int foo; - public MyValue2UnloadedInlineTypeArray(int n) { + public MyValue2UnloadedValueTypeArray(int n) { foo = n; } } @LooselyConsistentValue -value class MyValue3UnloadedInlineTypeArray { +value class MyValue3UnloadedValueTypeArray { int foo; - public MyValue3UnloadedInlineTypeArray(int n) { + public MyValue3UnloadedValueTypeArray(int n) { foo = n; } } @LooselyConsistentValue -value class MyValue4UnloadedInlineTypeArray { +value class MyValue4UnloadedValueTypeArray { int foo; - public MyValue4UnloadedInlineTypeArray(int n) { + public MyValue4UnloadedValueTypeArray(int n) { foo = n; } } @LooselyConsistentValue -value class MyValue5UnloadedInlineTypeArray { +value class MyValue5UnloadedValueTypeArray { int foo; - public MyValue5UnloadedInlineTypeArray(int n) { + public MyValue5UnloadedValueTypeArray(int n) { foo = n; } } @LooselyConsistentValue -value class MyValue6UnloadedInlineTypeArray { +value class MyValue6UnloadedValueTypeArray { int foo; - public MyValue6UnloadedInlineTypeArray(int n) { + public MyValue6UnloadedValueTypeArray(int n) { foo = n; } - public MyValue6UnloadedInlineTypeArray(MyValue6UnloadedInlineTypeArray v, MyValue6UnloadedInlineTypeArray[] dummy) { + public MyValue6UnloadedValueTypeArray(MyValue6UnloadedValueTypeArray v, MyValue6UnloadedValueTypeArray[] dummy) { foo = v.foo + 1; } } @LooselyConsistentValue -value class MyValue7UnloadedInlineTypeArray { +value class MyValue7UnloadedValueTypeArray { int foo; - public MyValue7UnloadedInlineTypeArray(int n) { + public MyValue7UnloadedValueTypeArray(int n) { foo = n; } } @LooselyConsistentValue -value class MyValue8UnloadedInlineTypeArray { +value class MyValue8UnloadedValueTypeArray { int foo = 123; static { - compiler.valhalla.inlinetypes.TestUnloadedInlineTypeArray.MyValue8_inited = true; + compiler.valhalla.valuetypes.TestUnloadedValueTypeArray.MyValue8_inited = true; } } @LooselyConsistentValue -value class MyValue9UnloadedInlineTypeArray { +value class MyValue9UnloadedValueTypeArray { int foo = 123; static { - compiler.valhalla.inlinetypes.TestUnloadedInlineTypeArray.MyValue9_inited = true; + compiler.valhalla.valuetypes.TestUnloadedValueTypeArray.MyValue9_inited = true; } } @LooselyConsistentValue -value class MyValue10UnloadedInlineTypeArray { +value class MyValue10UnloadedValueTypeArray { int foo = 42; } @LooselyConsistentValue -value class MyValue11UnloadedInlineTypeArray { +value class MyValue11UnloadedValueTypeArray { int foo = 42; } -public class TestUnloadedInlineTypeArray { +public class TestUnloadedValueTypeArray { static boolean MyValue8_inited = false; static boolean MyValue9_inited = false; - static MyValue1UnloadedInlineTypeArray[] target1() { - return (MyValue1UnloadedInlineTypeArray[])ValueClass.newNullableAtomicArray(MyValue1UnloadedInlineTypeArray.class, 10); + static MyValue1UnloadedValueTypeArray[] target1() { + return (MyValue1UnloadedValueTypeArray[])ValueClass.newNullableAtomicArray(MyValue1UnloadedValueTypeArray.class, 10); } static void test1() { target1(); } - static MyValue1UnloadedInlineTypeArray[] target1Nullable() { - return new MyValue1UnloadedInlineTypeArray[10]; + static MyValue1UnloadedValueTypeArray[] target1Nullable() { + return new MyValue1UnloadedValueTypeArray[10]; } static void test1Nullable() { target1Nullable(); } - static int test2(MyValue2UnloadedInlineTypeArray[] arr) { + static int test2(MyValue2UnloadedValueTypeArray[] arr) { if (arr != null) { return arr[1].foo; } else { @@ -258,8 +258,8 @@ static void verifyTest2() { } Asserts.assertEQ(m, 1234); - MyValue2UnloadedInlineTypeArray[] arr = (MyValue2UnloadedInlineTypeArray[])ValueClass.newNullableAtomicArray(MyValue2UnloadedInlineTypeArray.class, 2); - arr[1] = new MyValue2UnloadedInlineTypeArray(5678); + MyValue2UnloadedValueTypeArray[] arr = (MyValue2UnloadedValueTypeArray[])ValueClass.newNullableAtomicArray(MyValue2UnloadedValueTypeArray.class, 2); + arr[1] = new MyValue2UnloadedValueTypeArray(5678); m = 9999; for (int i = 0; i < n; i++) { m = test2(arr); @@ -267,7 +267,7 @@ static void verifyTest2() { Asserts.assertEQ(m, 5678); } - static int test2Nullable(MyValue2UnloadedInlineTypeArray[] arr) { + static int test2Nullable(MyValue2UnloadedValueTypeArray[] arr) { if (arr != null) { return arr[1].foo; } else { @@ -284,8 +284,8 @@ static void verifyTest2Nullable() { } Asserts.assertEQ(m, 1234); - MyValue2UnloadedInlineTypeArray[] arr = new MyValue2UnloadedInlineTypeArray[2]; - arr[1] = new MyValue2UnloadedInlineTypeArray(5678); + MyValue2UnloadedValueTypeArray[] arr = new MyValue2UnloadedValueTypeArray[2]; + arr[1] = new MyValue2UnloadedValueTypeArray(5678); m = 9999; for (int i = 0; i < n; i++) { m = test2Nullable(arr); @@ -293,9 +293,9 @@ static void verifyTest2Nullable() { Asserts.assertEQ(m, 5678); } - static void test3(MyValue3UnloadedInlineTypeArray[] arr) { + static void test3(MyValue3UnloadedValueTypeArray[] arr) { if (arr != null) { - arr[1] = new MyValue3UnloadedInlineTypeArray(2345); + arr[1] = new MyValue3UnloadedValueTypeArray(2345); } } @@ -306,17 +306,17 @@ static void verifyTest3() { test3(null); } - MyValue3UnloadedInlineTypeArray[] arr = (MyValue3UnloadedInlineTypeArray[])ValueClass.newNullableAtomicArray(MyValue3UnloadedInlineTypeArray.class, 2); + MyValue3UnloadedValueTypeArray[] arr = (MyValue3UnloadedValueTypeArray[])ValueClass.newNullableAtomicArray(MyValue3UnloadedValueTypeArray.class, 2); for (int i = 0; i < n; i++) { test3(arr); } Asserts.assertEQ(arr[1].foo, 2345); } - static void test3Nullable(MyValue3UnloadedInlineTypeArray[] arr) { + static void test3Nullable(MyValue3UnloadedValueTypeArray[] arr) { if (arr != null) { arr[0] = null; - arr[1] = new MyValue3UnloadedInlineTypeArray(2345); + arr[1] = new MyValue3UnloadedValueTypeArray(2345); } } @@ -327,7 +327,7 @@ static void verifyTest3Nullable() { test3Nullable(null); } - MyValue3UnloadedInlineTypeArray[] arr = new MyValue3UnloadedInlineTypeArray[2]; + MyValue3UnloadedValueTypeArray[] arr = new MyValue3UnloadedValueTypeArray[2]; for (int i = 0; i < n; i++) { test3Nullable(arr); } @@ -335,11 +335,11 @@ static void verifyTest3Nullable() { Asserts.assertEQ(arr[1].foo, 2345); } - static MyValue4UnloadedInlineTypeArray[] test4(boolean b) { + static MyValue4UnloadedValueTypeArray[] test4(boolean b) { // range check elimination if (b) { - MyValue4UnloadedInlineTypeArray[] arr = (MyValue4UnloadedInlineTypeArray[])ValueClass.newNullableAtomicArray(MyValue4UnloadedInlineTypeArray.class, 10); - arr[1] = new MyValue4UnloadedInlineTypeArray(2345); + MyValue4UnloadedValueTypeArray[] arr = (MyValue4UnloadedValueTypeArray[])ValueClass.newNullableAtomicArray(MyValue4UnloadedValueTypeArray.class, 10); + arr[1] = new MyValue4UnloadedValueTypeArray(2345); return arr; } else { return null; @@ -353,19 +353,19 @@ static void verifyTest4() { test4(false); } - MyValue4UnloadedInlineTypeArray[] arr = null; + MyValue4UnloadedValueTypeArray[] arr = null; for (int i = 0; i < n; i++) { arr = test4(true); } Asserts.assertEQ(arr[1].foo, 2345); } - static MyValue4UnloadedInlineTypeArray[] test4Nullable(boolean b) { + static MyValue4UnloadedValueTypeArray[] test4Nullable(boolean b) { // range check elimination if (b) { - MyValue4UnloadedInlineTypeArray[] arr = new MyValue4UnloadedInlineTypeArray[10]; + MyValue4UnloadedValueTypeArray[] arr = new MyValue4UnloadedValueTypeArray[10]; arr[0] = null; - arr[1] = new MyValue4UnloadedInlineTypeArray(2345); + arr[1] = new MyValue4UnloadedValueTypeArray(2345); return arr; } else { return null; @@ -379,7 +379,7 @@ static void verifyTest4Nullable() { test4Nullable(false); } - MyValue4UnloadedInlineTypeArray[] arr = null; + MyValue4UnloadedValueTypeArray[] arr = null; for (int i = 0; i < n; i++) { arr = test4Nullable(true); } @@ -392,12 +392,12 @@ static Object[] test5(int n) { if (n == 0) { return null; } else if (n == 1) { - MyValue5UnloadedInlineTypeArray[] arr = (MyValue5UnloadedInlineTypeArray[])ValueClass.newNullableAtomicArray(MyValue5UnloadedInlineTypeArray.class, 10); - arr[1] = new MyValue5UnloadedInlineTypeArray(12345); + MyValue5UnloadedValueTypeArray[] arr = (MyValue5UnloadedValueTypeArray[])ValueClass.newNullableAtomicArray(MyValue5UnloadedValueTypeArray.class, 10); + arr[1] = new MyValue5UnloadedValueTypeArray(12345); return arr; } else { - MyValue5UnloadedInlineTypeArray[] arr = new MyValue5UnloadedInlineTypeArray[10]; - arr[1] = new MyValue5UnloadedInlineTypeArray(22345); + MyValue5UnloadedValueTypeArray[] arr = new MyValue5UnloadedValueTypeArray[10]; + arr[1] = new MyValue5UnloadedValueTypeArray(22345); return arr; } } @@ -410,31 +410,31 @@ static void verifyTest5() { } { - MyValue5UnloadedInlineTypeArray[] arr = null; + MyValue5UnloadedValueTypeArray[] arr = null; for (int i = 0; i < n; i++) { - arr = (MyValue5UnloadedInlineTypeArray[])test5(1); + arr = (MyValue5UnloadedValueTypeArray[])test5(1); } Asserts.assertEQ(arr[1].foo, 12345); } { - MyValue5UnloadedInlineTypeArray[] arr = null; + MyValue5UnloadedValueTypeArray[] arr = null; for (int i = 0; i < n; i++) { - arr = (MyValue5UnloadedInlineTypeArray[])test5(2); + arr = (MyValue5UnloadedValueTypeArray[])test5(2); } Asserts.assertEQ(arr[1].foo, 22345); } } static Object test6() { - return new MyValue6UnloadedInlineTypeArray(new MyValue6UnloadedInlineTypeArray(123), null); + return new MyValue6UnloadedValueTypeArray(new MyValue6UnloadedValueTypeArray(123), null); } static void verifyTest6() { Object n = test6(); - Asserts.assertEQ(n.toString(), "compiler.valhalla.inlinetypes.MyValue6UnloadedInlineTypeArray@" + Integer.toHexString(n.hashCode())); + Asserts.assertEQ(n.toString(), "compiler.valhalla.valuetypes.MyValue6UnloadedValueTypeArray@" + Integer.toHexString(n.hashCode())); } - static int test7(MyValue7UnloadedInlineTypeArray[][] arr) { + static int test7(MyValue7UnloadedValueTypeArray[][] arr) { if (arr != null) { return arr[0][1].foo; } else { @@ -451,12 +451,12 @@ static void verifyTest7() { } Asserts.assertEQ(m, 1234); - MyValue7UnloadedInlineTypeArray[][] arr = { (MyValue7UnloadedInlineTypeArray[])ValueClass.newNullableAtomicArray(MyValue7UnloadedInlineTypeArray.class, 2), - (MyValue7UnloadedInlineTypeArray[])ValueClass.newNullableAtomicArray(MyValue7UnloadedInlineTypeArray.class, 2) }; + MyValue7UnloadedValueTypeArray[][] arr = { (MyValue7UnloadedValueTypeArray[])ValueClass.newNullableAtomicArray(MyValue7UnloadedValueTypeArray.class, 2), + (MyValue7UnloadedValueTypeArray[])ValueClass.newNullableAtomicArray(MyValue7UnloadedValueTypeArray.class, 2) }; Object[] oa = arr[1]; Asserts.assertEQ(oa[0], null); - arr[0][1] = new MyValue7UnloadedInlineTypeArray(5678); + arr[0][1] = new MyValue7UnloadedValueTypeArray(5678); m = 9999; for (int i = 0; i < n; i++) { m = test7(arr); @@ -464,7 +464,7 @@ static void verifyTest7() { Asserts.assertEQ(m, 5678); } - static int test7Nullable(MyValue7UnloadedInlineTypeArray[][] arr) { + static int test7Nullable(MyValue7UnloadedValueTypeArray[][] arr) { if (arr != null) { arr[0][0] = null; return arr[0][1].foo; @@ -482,11 +482,11 @@ static void verifyTest7Nullable() { } Asserts.assertEQ(m, 1234); - MyValue7UnloadedInlineTypeArray[][] arr = new MyValue7UnloadedInlineTypeArray[2][2]; + MyValue7UnloadedValueTypeArray[][] arr = new MyValue7UnloadedValueTypeArray[2][2]; Object[] oa = arr[1]; Asserts.assertEQ(oa[0], null); - arr[0][1] = new MyValue7UnloadedInlineTypeArray(5678); + arr[0][1] = new MyValue7UnloadedValueTypeArray(5678); m = 9999; for (int i = 0; i < n; i++) { m = test7Nullable(arr); @@ -496,31 +496,31 @@ static void verifyTest7Nullable() { } static void test8() { - MyValue8UnloadedInlineTypeArray a[] = new MyValue8UnloadedInlineTypeArray[0]; + MyValue8UnloadedValueTypeArray a[] = new MyValue8UnloadedValueTypeArray[0]; Asserts.assertEQ(MyValue8_inited, false); - MyValue8UnloadedInlineTypeArray b[] = (MyValue8UnloadedInlineTypeArray[])ValueClass.newNullableAtomicArray(MyValue8UnloadedInlineTypeArray.class, 0); + MyValue8UnloadedValueTypeArray b[] = (MyValue8UnloadedValueTypeArray[])ValueClass.newNullableAtomicArray(MyValue8UnloadedValueTypeArray.class, 0); Asserts.assertEQ(MyValue8_inited, false); // creation of a nullable array doesn't trigger the initialization // of the element's class (same behavior as anewarray and Array.newInstance()) } static void test9() { - MyValue9UnloadedInlineTypeArray a[][] = new MyValue9UnloadedInlineTypeArray[10][0]; + MyValue9UnloadedValueTypeArray a[][] = new MyValue9UnloadedValueTypeArray[10][0]; Asserts.assertEQ(MyValue9_inited, false); - a[0] = (MyValue9UnloadedInlineTypeArray[])ValueClass.newNullableAtomicArray(MyValue9UnloadedInlineTypeArray.class, 0); + a[0] = (MyValue9UnloadedValueTypeArray[])ValueClass.newNullableAtomicArray(MyValue9UnloadedValueTypeArray.class, 0); Asserts.assertEQ(MyValue9_inited, false); // creation of a nullable array doesn't trigger the initialization // of the element's class (same behavior as anewarray and Array.newInstance()) } - static void test10(MyValue10UnloadedInlineTypeArray dummy) { - MyValue10UnloadedInlineTypeArray[][] a = { (MyValue10UnloadedInlineTypeArray[])ValueClass.newNullRestrictedNonAtomicArray(MyValue10UnloadedInlineTypeArray.class, 1, new MyValue10UnloadedInlineTypeArray()) }; + static void test10(MyValue10UnloadedValueTypeArray dummy) { + MyValue10UnloadedValueTypeArray[][] a = { (MyValue10UnloadedValueTypeArray[])ValueClass.newNullRestrictedNonAtomicArray(MyValue10UnloadedValueTypeArray.class, 1, new MyValue10UnloadedValueTypeArray()) }; if (a[0][0].equals(null)) throw new RuntimeException("test10 failed"); Asserts.assertNE(a[0][0], null); } - static void test11(MyValue10UnloadedInlineTypeArray dummy) { - MyValue11UnloadedInlineTypeArray[][] a = new MyValue11UnloadedInlineTypeArray[1][1]; + static void test11(MyValue10UnloadedValueTypeArray dummy) { + MyValue11UnloadedValueTypeArray[][] a = new MyValue11UnloadedValueTypeArray[1][1]; Asserts.assertEQ(a[0][0], null); } diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnloadedInlineTypeField.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnloadedValueTypeField.java similarity index 95% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnloadedInlineTypeField.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnloadedValueTypeField.java index f7fc75791d8e..7522dd208cd0 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnloadedInlineTypeField.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnloadedValueTypeField.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.*; import jdk.test.lib.Asserts; @@ -29,7 +29,7 @@ import jdk.internal.vm.annotation.LooselyConsistentValue; import jdk.internal.vm.annotation.NullRestricted; -import static compiler.valhalla.inlinetypes.InlineTypes.rI; +import static compiler.valhalla.valuetypes.ValueTypes.rI; /* * @test @@ -40,12 +40,12 @@ * @enablePreview * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation - * @compile hack/GetUnresolvedInlineFieldWrongSignature.java - * @compile TestUnloadedInlineTypeField.java + * @compile hack/GetUnresolvedValueFieldWrongSignature.java + * @compile TestUnloadedValueTypeField.java * @run driver/timeout=300 ${test.main.class} */ -public class TestUnloadedInlineTypeField { +public class TestUnloadedValueTypeField { // Only prevent loading of classes when testing with C1. Load classes // early when executing with C2 to prevent uncommon traps. It's still // beneficial to execute this test with C2 because it also checks handling @@ -59,15 +59,15 @@ public static void main(String[] args) { new Scenario(3, "-XX:-UseFieldFlattening", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+PatchALot") }; - InlineTypes.getFramework() - .addScenarios(scenarios) - .addFlags("--enable-preview", - "-XX:+UnlockDiagnosticVMOptions", - // Prevent IR Test Framework from loading classes - "-DIgnoreCompilerControls=true", - // Some tests trigger frequent re-compilation. Don't mark them as non-compilable. - "-XX:PerMethodRecompilationCutoff=-1", "-XX:PerBytecodeRecompilationCutoff=-1") - .start(); + ValueTypes.getFramework() + .addScenarios(scenarios) + .addFlags("--enable-preview", + "-XX:+UnlockDiagnosticVMOptions", + // Prevent IR Test Framework from loading classes + "-DIgnoreCompilerControls=true", + // Some tests trigger frequent re-compilation. Don't mark them as non-compilable. + "-XX:PerMethodRecompilationCutoff=-1", "-XX:PerBytecodeRecompilationCutoff=-1") + .start(); } // Test case 1: @@ -78,7 +78,7 @@ public static void main(String[] args) { // ^ not loaded ^ already loaded // // MyValue1 has already been loaded, because it's in the preload attribute of - // TestUnloadedInlineTypeField, due to TestUnloadedInlineTypeField.test1_precondition(). + // TestUnloadedValueTypeField, due to TestUnloadedValueTypeField.test1_precondition(). @LooselyConsistentValue static value class MyValue1 { int foo; @@ -130,7 +130,7 @@ public void test1_verifier(RunInfo info) { // ^ not loaded ^ not loaded // // MyValue2 has not been loaded, because it is not explicitly referenced by - // TestUnloadedInlineTypeField. + // TestUnloadedValueTypeField. @LooselyConsistentValue static value class MyValue2 { int foo; @@ -265,7 +265,7 @@ public void test5_verifier(RunInfo info) { // ^ not loaded ^ already loaded // // MyValue6 has already been loaded, because it's in the preload attribute of - // TestUnloadedInlineTypeField, due to TestUnloadedInlineTypeField.test1_precondition(). + // TestUnloadedValueTypeField, due to TestUnloadedValueTypeField.test1_precondition(). @LooselyConsistentValue static value class MyValue6 { int foo; @@ -310,7 +310,7 @@ public void test6_verifier(RunInfo info) { // ^ not loaded ^ not loaded // // MyValue7 has not been loaded, because it is not explicitly referenced by - // TestUnloadedInlineTypeField. + // TestUnloadedValueTypeField. @LooselyConsistentValue static value class MyValue7 { int foo; @@ -542,7 +542,7 @@ static MyValue13 test13_precondition() { @Test public void test13(Object holder) { // Don't use MyValue13Holder in the signature, it might trigger class loading - GetUnresolvedInlineFieldWrongSignature.test13(holder); + GetUnresolvedValueFieldWrongSignature.test13(holder); } @Run(test = "test13") @@ -581,7 +581,7 @@ public MyValue15Holder() { @Test public void test15(Object holder) { // Don't use MyValue15Holder in the signature, it might trigger class loading - GetUnresolvedInlineFieldWrongSignature.test15(holder); + GetUnresolvedValueFieldWrongSignature.test15(holder); } @Run(test = "test15") @@ -612,7 +612,7 @@ static MyValue16 test16_precondition() { @Test public Object test16(boolean warmup) { - return GetUnresolvedInlineFieldWrongSignature.test16(warmup); + return GetUnresolvedValueFieldWrongSignature.test16(warmup); } @Run(test = "test16") @@ -639,7 +639,7 @@ public MyValue17() { @Test public Object test17(boolean warmup) { - return GetUnresolvedInlineFieldWrongSignature.test17(warmup); + return GetUnresolvedValueFieldWrongSignature.test17(warmup); } @Run(test = "test17") diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnresolvedInlineClass.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnresolvedValueClass.java similarity index 74% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnresolvedInlineClass.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnresolvedValueClass.java index 4dce286e41fa..5db451cc7d48 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestUnresolvedInlineClass.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnresolvedValueClass.java @@ -24,43 +24,43 @@ /** * @test * @bug 8187679 - * @summary The VM should exit gracefully when unable to preload an inline type argument + * @summary The VM should exit gracefully when unable to preload a value type argument * @enablePreview * @requires vm.flagless * @library /test/lib - * @compile SimpleInlineType.java TestUnresolvedInlineClass.java - * @run main compiler.valhalla.inlinetypes.TestUnresolvedInlineClass + * @compile SimpleValueType.java TestUnresolvedValueClass.java + * @run main compiler.valhalla.valuetypes.TestUnresolvedValueClass */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.io.File; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; -public class TestUnresolvedInlineClass { +public class TestUnresolvedValueClass { final static String TEST_CLASSES = System.getProperty("test.classes") + File.separator; - // Method with unresolved inline type argument - static void test1(SimpleInlineType vt) { + // Method with unresolved value type argument + static void test1(SimpleValueType vt) { } static public void main(String[] args) throws Exception { if (args.length == 0) { - // Delete SimpleInlineType.class - File unresolved = new File(TEST_CLASSES, "compiler/valhalla/inlinetypes/SimpleInlineType.class"); + // Delete SimpleValueType.class + File unresolved = new File(TEST_CLASSES, "compiler/valhalla/valuetypes/SimpleValueType.class"); if (!unresolved.exists() || !unresolved.delete()) { throw new RuntimeException("Could not delete: " + unresolved); } // Run test in new VM instance - String[] arg = {"--enable-preview", "-XX:+UnlockDiagnosticVMOptions", "-Xlog:class+preload=info", "-XX:+InlineTypePassFieldsAsArgs", "compiler.valhalla.inlinetypes.TestUnresolvedInlineClass", "run"}; + String[] arg = {"--enable-preview", "-XX:+UnlockDiagnosticVMOptions", "-Xlog:class+preload=info", "-XX:+ValueTypePassFieldsAsArgs", "compiler.valhalla.valuetypes.TestUnresolvedValueClass", "run"}; OutputAnalyzer oa = ProcessTools.executeTestJava(arg); // Verify that a warning is printed String output = oa.getOutput(); - oa.shouldContain("Preloading of class compiler/valhalla/inlinetypes/SimpleInlineType during linking of class compiler/valhalla/inlinetypes/TestUnresolvedInlineClass (cause: LoadableDescriptors attribute) failed"); + oa.shouldContain("Preloading of class compiler/valhalla/valuetypes/SimpleValueType during linking of class compiler/valhalla/valuetypes/TestUnresolvedValueClass (cause: LoadableDescriptors attribute) failed"); } } } diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestValueClassCodeCacheLeak.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueClassCodeCacheLeak.java similarity index 92% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestValueClassCodeCacheLeak.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueClassCodeCacheLeak.java index 6286fbdc414c..b5ea31c4863e 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestValueClassCodeCacheLeak.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueClassCodeCacheLeak.java @@ -30,7 +30,7 @@ * @run main/othervm -XX:ReservedCodeCacheSize=32m ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.io.InputStream; @@ -39,7 +39,7 @@ public static value class TemporaryValue { } static final class Loader extends ClassLoader { Class define(byte[] bytes) { - return defineClass("compiler.valhalla.inlinetypes.TestValueClassCodeCacheLeak$TemporaryValue", bytes, 0, bytes.length); + return defineClass("compiler.valhalla.valuetypes.TestValueClassCodeCacheLeak$TemporaryValue", bytes, 0, bytes.length); } } diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestValueClasses.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueClasses.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestValueClasses.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueClasses.java index 947082760288..db75cac2322d 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestValueClasses.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueClasses.java @@ -21,14 +21,14 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.*; import jdk.test.lib.Asserts; import java.lang.reflect.Method; -import static compiler.valhalla.inlinetypes.InlineTypes.*; +import static compiler.valhalla.valuetypes.ValueTypes.*; import static compiler.lib.ir_framework.IRNode.ALLOC; import static compiler.lib.ir_framework.IRNode.ALLOC_OF_MYVALUE_KLASS; @@ -125,14 +125,14 @@ public class TestValueClasses { public static void main(String[] args) { - Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; + Scenario[] scenarios = ValueTypes.DEFAULT_SCENARIOS; // Don't generate bytecodes but call through runtime for reflective calls scenarios[0].addFlags("-Dsun.reflect.inflationThreshold=10000"); scenarios[1].addFlags("-Dsun.reflect.inflationThreshold=10000"); scenarios[3].addFlags("-XX:+UnlockDiagnosticVMOptions", "-XX:+UseArrayFlattening", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck"); scenarios[4].addFlags("-XX:-UseTLAB", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-MonomorphicArrayCheck"); - InlineTypes.getFramework() + ValueTypes.getFramework() .addScenarios(scenarios[Integer.parseInt(args[0])]) .addHelperClasses(MyValueClass1.class, MyValueClass2.class, @@ -600,9 +600,9 @@ public MyValueClass1 test15_helper3(Object vt) { // Test that calling convention optimization prevents buffering of arguments @Test - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "true"}, counts = {ALLOC, " <= 7"}) // 6 MyValueClass2/MyValueClass2Inline allocations + 1 Integer allocation (if not the all-zero value) - @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, + @IR(applyIf = {"ValueTypePassFieldsAsArgs", "false"}, counts = {ALLOC, " <= 8"}) // 1 MyValueClass1 allocation + 6 MyValueClass2/MyValueClass2Inline allocations + 1 Integer allocation (if not the all-zero value) public MyValueClass1 test15(MyValueClass1 vt) { MyValueClass1 res = test15_helper1(vt); @@ -637,9 +637,9 @@ public MyValueClass2 test16_helper3(boolean b) { // Test that calling convention optimization prevents buffering of return values @Test - @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "true"}, counts = {ALLOC, " <= 1"}) // 1 MyValueClass2Inline allocation (if not the all-zero value) - @IR(applyIf = {"InlineTypeReturnedAsFields", "false"}, + @IR(applyIf = {"ValueTypeReturnedAsFields", "false"}, counts = {ALLOC, " <= 2"}) // 1 MyValueClass2 + 1 MyValueClass2Inline allocation (if not the all-zero value) public MyValueClass2 test16(int c, boolean b) { MyValueClass2 res = null; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestValueConstruction.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueConstruction.java similarity index 98% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestValueConstruction.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueConstruction.java index ad40c09a5585..d89b933efc27 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestValueConstruction.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueConstruction.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.lang.classfile.Label; import java.lang.invoke.MethodHandle; @@ -45,7 +45,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch * -XX:CompileCommand=inline,TestValueConstruction::checkDeopt - * compiler.valhalla.inlinetypes.TestValueConstruction + * compiler.valhalla.valuetypes.TestValueConstruction */ /* @@ -57,7 +57,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+DeoptimizeALot * -XX:CompileCommand=inline,TestValueConstruction::checkDeopt - * compiler.valhalla.inlinetypes.TestValueConstruction + * compiler.valhalla.valuetypes.TestValueConstruction */ /* @@ -70,7 +70,7 @@ * @run main/othervm/timeout=400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:CompileCommand=compileonly,*TestValueConstruction::test* -Xbatch * -XX:CompileCommand=inline,TestValueConstruction::checkDeopt - * compiler.valhalla.inlinetypes.TestValueConstruction + * compiler.valhalla.valuetypes.TestValueConstruction */ /** @@ -84,7 +84,7 @@ * @run main/othervm/timeout=400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbatch * -XX:CompileCommand=dontinline,compiler*::helper* * -XX:CompileCommand=inline,TestValueConstruction::checkDeopt - * compiler.valhalla.inlinetypes.TestValueConstruction + * compiler.valhalla.valuetypes.TestValueConstruction */ /* @@ -97,7 +97,7 @@ * @run main/othervm/timeout=400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:CompileCommand=dontinline,*MyValue*:: -Xbatch * -XX:CompileCommand=inline,TestValueConstruction::checkDeopt - * compiler.valhalla.inlinetypes.TestValueConstruction + * compiler.valhalla.valuetypes.TestValueConstruction */ /* @@ -110,7 +110,7 @@ * @run main/othervm/timeout=400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:CompileCommand=dontinline,*Object:: -Xbatch * -XX:CompileCommand=inline,TestValueConstruction::checkDeopt - * compiler.valhalla.inlinetypes.TestValueConstruction + * compiler.valhalla.valuetypes.TestValueConstruction */ /* @@ -123,7 +123,7 @@ * @run main/othervm/timeout=400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+IgnoreUnrecognizedVMOptions * -XX:+DeoptimizeALot -XX:CompileCommand=dontinline,*Object:: -Xbatch * -XX:CompileCommand=inline,TestValueConstruction::checkDeopt - * compiler.valhalla.inlinetypes.TestValueConstruction + * compiler.valhalla.valuetypes.TestValueConstruction */ /* @@ -136,7 +136,7 @@ * @run main/othervm/timeout=400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:CompileCommand=dontinline,*MyAbstract:: -Xbatch * -XX:CompileCommand=inline,TestValueConstruction::checkDeopt - * compiler.valhalla.inlinetypes.TestValueConstruction + * compiler.valhalla.valuetypes.TestValueConstruction */ /* @@ -150,7 +150,7 @@ * -XX:-TieredCompilation -XX:+StressIncrementalInlining * -XX:CompileCommand=inline,TestValueConstruction::checkDeopt * -XX:CompileCommand=MemLimit,*.*,2G~crash - * compiler.valhalla.inlinetypes.TestValueConstruction + * compiler.valhalla.valuetypes.TestValueConstruction */ /* @@ -164,7 +164,7 @@ * -XX:-TieredCompilation -XX:+StressIncrementalInlining * -XX:CompileCommand=inline,TestValueConstruction::checkDeopt * -XX:CompileCommand=compileonly,*TestValueConstruction::test* -Xbatch - * compiler.valhalla.inlinetypes.TestValueConstruction + * compiler.valhalla.valuetypes.TestValueConstruction */ /* @test id=StressIncrementalInliningDontInlineMyValueInit @@ -177,7 +177,7 @@ * -XX:-TieredCompilation -XX:+StressIncrementalInlining * -XX:CompileCommand=inline,TestValueConstruction::checkDeopt * -XX:CompileCommand=dontinline,*MyValue*:: -Xbatch - * compiler.valhalla.inlinetypes.TestValueConstruction + * compiler.valhalla.valuetypes.TestValueConstruction */ /* @@ -191,7 +191,7 @@ * -XX:-TieredCompilation -XX:+StressIncrementalInlining * -XX:CompileCommand=inline,TestValueConstruction::checkDeopt * -XX:CompileCommand=dontinline,*Object:: -Xbatch - * compiler.valhalla.inlinetypes.TestValueConstruction + * compiler.valhalla.valuetypes.TestValueConstruction */ /* @@ -206,7 +206,7 @@ * -XX:CompileCommand=inline,TestValueConstruction::checkDeopt * -XX:CompileCommand=dontinline,*MyAbstract:: -Xbatch * -XX:CompileCommand=MemLimit,*.*,2G~crash - * compiler.valhalla.inlinetypes.TestValueConstruction + * compiler.valhalla.valuetypes.TestValueConstruction */ /* @@ -221,7 +221,7 @@ * -XX:Tier0BackedgeNotifyFreqLog=0 -XX:Tier2BackedgeNotifyFreqLog=0 -XX:Tier3BackedgeNotifyFreqLog=0 * -XX:Tier2BackEdgeThreshold=1 -XX:Tier3BackEdgeThreshold=1 -XX:Tier4BackEdgeThreshold=1 -Xbatch * -XX:CompileCommand=MemLimit,*.*,2G~crash - * compiler.valhalla.inlinetypes.TestValueConstruction + * compiler.valhalla.valuetypes.TestValueConstruction */ public class TestValueConstruction { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestInlineFieldNonFlattened.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueFieldNonFlattened.java similarity index 97% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestInlineFieldNonFlattened.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueFieldNonFlattened.java index 7749e0df9499..ab426dab275d 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestInlineFieldNonFlattened.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueFieldNonFlattened.java @@ -22,7 +22,7 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import compiler.lib.ir_framework.*; import java.util.Random; @@ -43,7 +43,7 @@ * @run driver ${test.main.class} */ -public class TestInlineFieldNonFlattened { +public class TestValueFieldNonFlattened { static class MyClass { @NullRestricted public final MyValue v1; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestValueInvokeStaticDuringClinit.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueInvokeStaticDuringClinit.java similarity index 91% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestValueInvokeStaticDuringClinit.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueInvokeStaticDuringClinit.java index 329ceade5900..0b93f0bcabc6 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestValueInvokeStaticDuringClinit.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueInvokeStaticDuringClinit.java @@ -26,11 +26,11 @@ * @bug 8385469 * @summary Test static call resolution of a value class method with inline arguments while the class is being initialized * @enablePreview - * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestValueInvokeStaticDuringClinit::test - * compiler.valhalla.inlinetypes.TestValueInvokeStaticDuringClinit + * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestValueInvokeStaticDuringClinit::test + * compiler.valhalla.valuetypes.TestValueInvokeStaticDuringClinit */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; public class TestValueInvokeStaticDuringClinit { static value class MyValueClass { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestValueRematDuringTypeSharpening.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueRematDuringTypeSharpening.java similarity index 92% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestValueRematDuringTypeSharpening.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueRematDuringTypeSharpening.java index 1664baaa5cfc..d860cd2bb3a5 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestValueRematDuringTypeSharpening.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueRematDuringTypeSharpening.java @@ -21,14 +21,14 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.misc.Unsafe; import compiler.lib.ir_framework.*; /* * @test - * @summary Missing InlineTypeNode re-materialization during type sharpening. + * @summary Missing ValueTypeNode re-materialization during type sharpening. * @library /test/lib / * @enablePreview * @modules java.base/jdk.internal.misc @@ -62,7 +62,7 @@ public static int getUnsafeFieldValue(topValue obj, int incr) { } @Test - @IR(phase = {CompilePhase.AFTER_PARSING}, counts = {IRNode.INLINE_TYPE, " > 0 "}) + @IR(phase = {CompilePhase.AFTER_PARSING}, counts = {IRNode.VALUE_TYPE, " > 0 "}) public static int test(topValue obj) { int val = 0; if (obj.getClass() != dummyValue1.class) { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestInlineTypeInfinitePushThruPhi.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueTypeInfinitePushThruPhi.java similarity index 93% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestInlineTypeInfinitePushThruPhi.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueTypeInfinitePushThruPhi.java index 9bb53506271d..5f7a986e0ae6 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestInlineTypeInfinitePushThruPhi.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestValueTypeInfinitePushThruPhi.java @@ -24,7 +24,7 @@ /** * @test * @bug 8386676 - * @summary [lworld] Infinite loop when pushing inline types down though phis during IGVN + * @summary [lworld] Infinite loop when pushing value types down though phis during IGVN * @enablePreview * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation @@ -36,12 +36,12 @@ * -XX:-UseOnStackReplacement -XX:CompileTaskTimeout=8000 ${test.main.class} */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.internal.vm.annotation.LooselyConsistentValue; import jdk.internal.vm.annotation.NullRestricted; -public class TestInlineTypeInfinitePushThruPhi { +public class TestValueTypeInfinitePushThruPhi { static V2 v2 = new V2(3); public static void main(String[] args) { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestVirtualThreadExtendedFrame.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestVirtualThreadExtendedFrame.java similarity index 100% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestVirtualThreadExtendedFrame.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestVirtualThreadExtendedFrame.java diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestVirtualThreadMethodHandle.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestVirtualThreadMethodHandle.java similarity index 100% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestVirtualThreadMethodHandle.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestVirtualThreadMethodHandle.java diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestVirtualThreads.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestVirtualThreads.java similarity index 94% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestVirtualThreads.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestVirtualThreads.java index f66ab190a27a..a38eef79b79b 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestVirtualThreads.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestVirtualThreads.java @@ -31,7 +31,7 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * compiler.valhalla.inlinetypes.TestVirtualThreads + * compiler.valhalla.valuetypes.TestVirtualThreads */ /* @@ -43,8 +43,8 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -Xbatch -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestVirtualThreads*::* - * compiler.valhalla.inlinetypes.TestVirtualThreads + * -Xbatch -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::* + * compiler.valhalla.valuetypes.TestVirtualThreads */ /* @@ -56,8 +56,8 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -Xbatch -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestVirtualThreads*::test* - * compiler.valhalla.inlinetypes.TestVirtualThreads + * -Xbatch -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::test* + * compiler.valhalla.valuetypes.TestVirtualThreads */ /* @@ -70,9 +70,9 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xbatch -XX:CompileCommand=dontinline,*::dontinline - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestVirtualThreads*::test* + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::test* * -XX:CompileCommand=dontinline,*::test* - * compiler.valhalla.inlinetypes.TestVirtualThreads + * compiler.valhalla.valuetypes.TestVirtualThreads */ /* @@ -85,9 +85,9 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xbatch -XX:CompileCommand=dontinline,*::dontinline - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestVirtualThreads*::test* + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::test* * -XX:CompileCommand=dontinline,*::*Helper - * compiler.valhalla.inlinetypes.TestVirtualThreads + * compiler.valhalla.valuetypes.TestVirtualThreads */ /* @@ -100,9 +100,9 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xbatch -XX:CompileCommand=dontinline,*::dontinline - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestVirtualThreads*::test* + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::test* * -XX:CompileCommand=exclude,*::*Helper - * compiler.valhalla.inlinetypes.TestVirtualThreads + * compiler.valhalla.valuetypes.TestVirtualThreads */ /* @@ -114,8 +114,8 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -Xcomp -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestVirtualThreads*::* - * compiler.valhalla.inlinetypes.TestVirtualThreads 50000 + * -Xcomp -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::* + * compiler.valhalla.valuetypes.TestVirtualThreads 50000 */ /* @@ -127,8 +127,8 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -Xcomp -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestVirtualThreads*::test* - * compiler.valhalla.inlinetypes.TestVirtualThreads 50000 + * -Xcomp -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::test* + * compiler.valhalla.valuetypes.TestVirtualThreads 50000 */ /* @@ -141,9 +141,9 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xcomp -XX:CompileCommand=dontinline,*::dontinline - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestVirtualThreads*::test* + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::test* * -XX:CompileCommand=dontinline,*::test* - * compiler.valhalla.inlinetypes.TestVirtualThreads 50000 + * compiler.valhalla.valuetypes.TestVirtualThreads 50000 */ /* @@ -156,9 +156,9 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xcomp -XX:CompileCommand=dontinline,*::dontinline - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestVirtualThreads*::test* + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::test* * -XX:CompileCommand=dontinline,*::*Helper - * compiler.valhalla.inlinetypes.TestVirtualThreads 50000 + * compiler.valhalla.valuetypes.TestVirtualThreads 50000 */ /* @@ -171,9 +171,9 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xcomp -XX:CompileCommand=dontinline,*::dontinline - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestVirtualThreads*::test* + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::test* * -XX:CompileCommand=exclude,*::*Helper - * compiler.valhalla.inlinetypes.TestVirtualThreads 50000 + * compiler.valhalla.valuetypes.TestVirtualThreads 50000 */ /* @@ -186,8 +186,8 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xbatch -XX:CompileCommand=dontinline,*::* - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestVirtualThreads*::* - * compiler.valhalla.inlinetypes.TestVirtualThreads 50000 + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::* + * compiler.valhalla.valuetypes.TestVirtualThreads 50000 */ /* @@ -200,8 +200,8 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -Xcomp -XX:CompileCommand=dontinline,*::* - * -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.TestVirtualThreads*::* - * compiler.valhalla.inlinetypes.TestVirtualThreads 50000 + * -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.TestVirtualThreads*::* + * compiler.valhalla.valuetypes.TestVirtualThreads 50000 */ /* @@ -215,10 +215,10 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+VerifyContinuations - * compiler.valhalla.inlinetypes.TestVirtualThreads + * compiler.valhalla.valuetypes.TestVirtualThreads */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import java.lang.reflect.Method; @@ -798,7 +798,7 @@ public static void main(String[] args) throws Exception { Collections.addAll(methods, LargeValue2.class.getDeclaredMethods()); Collections.addAll(methods, LargeValueWithOops.class.getDeclaredMethods()); Collections.addAll(methods, DoubleValue.class.getDeclaredMethods()); - Collections.addAll(methods, compiler.valhalla.inlinetypes.TestVirtualThreads.class.getDeclaredMethods()); + Collections.addAll(methods, compiler.valhalla.valuetypes.TestVirtualThreads.class.getDeclaredMethods()); System.out.println("Excluding methods from C1 compilation:"); for (Method m : methods) { if (Utils.getRandomInstance().nextBoolean()) { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestWithSpeculativeTypes.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestWithSpeculativeTypes.java similarity index 92% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestWithSpeculativeTypes.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestWithSpeculativeTypes.java index d5ca24df6654..dff6f84a12cd 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestWithSpeculativeTypes.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestWithSpeculativeTypes.java @@ -27,12 +27,12 @@ * @summary Test that speculative types are properly handled by scalarization. * @library /test/lib * @enablePreview - * @run main/othervm -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestWithSpeculativeTypes::* + * @run main/othervm -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestWithSpeculativeTypes::* * -XX:TypeProfileLevel=222 -XX:-TieredCompilation -Xbatch - * compiler.valhalla.inlinetypes.TestWithSpeculativeTypes + * compiler.valhalla.valuetypes.TestWithSpeculativeTypes */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestWrongFlatArrayCopyStubWithShenandoah.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestWrongFlatArrayCopyStubWithShenandoah.java similarity index 92% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestWrongFlatArrayCopyStubWithShenandoah.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestWrongFlatArrayCopyStubWithShenandoah.java index 360a556577a1..70c805a0e215 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestWrongFlatArrayCopyStubWithShenandoah.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestWrongFlatArrayCopyStubWithShenandoah.java @@ -30,12 +30,12 @@ * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @run main/othervm -Xbatch -XX:+UseShenandoahGC - * -XX:CompileCommand=exclude,compiler.valhalla.inlinetypes.TestWrongFlatArrayCopyStubWithShenandoah::check - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestWrongFlatArrayCopyStubWithShenandoah::test* - * compiler.valhalla.inlinetypes.TestWrongFlatArrayCopyStubWithShenandoah + * -XX:CompileCommand=exclude,compiler.valhalla.valuetypes.TestWrongFlatArrayCopyStubWithShenandoah::check + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestWrongFlatArrayCopyStubWithShenandoah::test* + * compiler.valhalla.valuetypes.TestWrongFlatArrayCopyStubWithShenandoah */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; import jdk.test.lib.Utils; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestWrongFlatArrayCopyStubWithZGC.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestWrongFlatArrayCopyStubWithZGC.java similarity index 93% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestWrongFlatArrayCopyStubWithZGC.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/TestWrongFlatArrayCopyStubWithZGC.java index eefa1e2220c9..3dbfc85b6662 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestWrongFlatArrayCopyStubWithZGC.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestWrongFlatArrayCopyStubWithZGC.java @@ -31,12 +31,12 @@ * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @run main/othervm -Xbatch -XX:+UseZGC - * -XX:CompileCommand=exclude,compiler.valhalla.inlinetypes.TestWrongFlatArrayCopyStubWithZGC::check - * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestWrongFlatArrayCopyStubWithZGC::test* - * compiler.valhalla.inlinetypes.TestWrongFlatArrayCopyStubWithZGC + * -XX:CompileCommand=exclude,compiler.valhalla.valuetypes.TestWrongFlatArrayCopyStubWithZGC::check + * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.TestWrongFlatArrayCopyStubWithZGC::test* + * compiler.valhalla.valuetypes.TestWrongFlatArrayCopyStubWithZGC */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Asserts; import jdk.test.lib.Utils; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/InlineTypes.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypes.java similarity index 86% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/InlineTypes.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypes.java index 7a13e56d3bf8..9f12d71eeaa9 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/InlineTypes.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/ValueTypes.java @@ -21,13 +21,13 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; import jdk.test.lib.Utils; import compiler.lib.ir_framework.Scenario; import compiler.lib.ir_framework.TestFramework; -public class InlineTypes { +public class ValueTypes { public static final int rI = Utils.getRandomInstance().nextInt() % 1000; public static final long rL = Utils.getRandomInstance().nextLong() % 1000; public static final double rD = Utils.getRandomInstance().nextDouble() % 1000; @@ -39,8 +39,8 @@ public class InlineTypes { "-XX:+UseArrayFlattening", "-XX:-UseArrayLoadStoreProfile", "-XX:+UseFieldFlattening", - "-XX:+InlineTypePassFieldsAsArgs", - "-XX:+InlineTypeReturnedAsFields", + "-XX:+ValueTypePassFieldsAsArgs", + "-XX:+ValueTypeReturnedAsFields", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+AlwaysIncrementalInline" ), @@ -51,8 +51,8 @@ public class InlineTypes { "-XX:+UseArrayFlattening", "-XX:-UseArrayLoadStoreProfile", "-XX:+UseFieldFlattening", - "-XX:-InlineTypePassFieldsAsArgs", - "-XX:-InlineTypeReturnedAsFields" + "-XX:-ValueTypePassFieldsAsArgs", + "-XX:-ValueTypeReturnedAsFields" ), new Scenario(2, "-XX:-UseACmpProfile", @@ -61,16 +61,16 @@ public class InlineTypes { "-XX:-UseArrayFlattening", "-XX:-UseArrayLoadStoreProfile", "-XX:+UseFieldFlattening", - "-XX:+InlineTypePassFieldsAsArgs", - "-XX:+InlineTypeReturnedAsFields" + "-XX:+ValueTypePassFieldsAsArgs", + "-XX:+ValueTypeReturnedAsFields" ), new Scenario(3, "-DVerifyIR=false", "-XX:FlatArrayElementMaxOops=0", "-XX:-UseArrayFlattening", "-XX:-UseFieldFlattening", - "-XX:+InlineTypePassFieldsAsArgs", - "-XX:+InlineTypeReturnedAsFields", + "-XX:+ValueTypePassFieldsAsArgs", + "-XX:+ValueTypeReturnedAsFields", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+AlwaysIncrementalInline" ), @@ -79,8 +79,8 @@ public class InlineTypes { "-XX:FlatArrayElementMaxOops=-1", "-XX:+UseArrayFlattening", "-XX:-UseFieldFlattening", - "-XX:+InlineTypePassFieldsAsArgs", - "-XX:-InlineTypeReturnedAsFields", + "-XX:+ValueTypePassFieldsAsArgs", + "-XX:-ValueTypeReturnedAsFields", "-XX:-ReduceInitialCardMarks" ), new Scenario(5, @@ -89,8 +89,8 @@ public class InlineTypes { "-XX:+UseArrayFlattening", "-XX:-UseArrayLoadStoreProfile", "-XX:+UseFieldFlattening", - "-XX:-InlineTypePassFieldsAsArgs", - "-XX:-InlineTypeReturnedAsFields", + "-XX:-ValueTypePassFieldsAsArgs", + "-XX:-ValueTypeReturnedAsFields", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+AlwaysIncrementalInline" ), @@ -103,8 +103,8 @@ public class InlineTypes { "-XX:+UseNullableAtomicValueFlattening", "-XX:+UseNullFreeAtomicValueFlattening", "-XX:+UseNullFreeNonAtomicValueFlattening", - "-XX:+InlineTypePassFieldsAsArgs", - "-XX:+InlineTypeReturnedAsFields", + "-XX:+ValueTypePassFieldsAsArgs", + "-XX:+ValueTypeReturnedAsFields", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+AlwaysIncrementalInline" ), diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/bootstrap/InstallBootstrapClasses.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/bootstrap/InstallBootstrapClasses.java similarity index 95% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/bootstrap/InstallBootstrapClasses.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/bootstrap/InstallBootstrapClasses.java index 38d2734fedd0..6e7bdeae1fe0 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/bootstrap/InstallBootstrapClasses.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/bootstrap/InstallBootstrapClasses.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes.bootstrap; +package compiler.valhalla.valuetypes.bootstrap; import java.io.IOException; import java.nio.file.Files; @@ -34,7 +34,7 @@ public class InstallBootstrapClasses { private static void copyClass(String name) throws IOException { - Path source = Path.of(Utils.TEST_CLASSES).resolve("compiler/valhalla/inlinetypes/bootstrap/" + name); + Path source = Path.of(Utils.TEST_CLASSES).resolve("compiler/valhalla/valuetypes/bootstrap/" + name); Path dest = Path.of("boot"); Path target = dest.resolve(name); Files.createDirectories(dest); diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/bootstrap/TestBootClassloader.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/bootstrap/TestBootClassloader.java similarity index 93% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/bootstrap/TestBootClassloader.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/bootstrap/TestBootClassloader.java index f5ab0e588444..c07737288ed0 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/bootstrap/TestBootClassloader.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/bootstrap/TestBootClassloader.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes.bootstrap; +package compiler.valhalla.valuetypes.bootstrap; import java.lang.reflect.Method; import jdk.test.lib.Asserts; @@ -44,10 +44,10 @@ * @compile ValueOnBootclasspath.java InstallBootstrapClasses.java TestBootClassloader.java * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm compiler.valhalla.inlinetypes.bootstrap.InstallBootstrapClasses + * @run main/othervm compiler.valhalla.valuetypes.bootstrap.InstallBootstrapClasses * @run main/othervm -Xbootclasspath/a:boot -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -Xbatch -XX:-TieredCompilation -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.bootstrap.TestBootClassloader::test* - * -XX:CompileCommand=inline,*::get* compiler.valhalla.inlinetypes.bootstrap.TestBootClassloader + * -Xbatch -XX:-TieredCompilation -XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.bootstrap.TestBootClassloader::test* + * -XX:CompileCommand=inline,*::get* compiler.valhalla.valuetypes.bootstrap.TestBootClassloader */ public class TestBootClassloader { diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/bootstrap/ValueOnBootclasspath.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/bootstrap/ValueOnBootclasspath.java similarity index 96% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/bootstrap/ValueOnBootclasspath.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/bootstrap/ValueOnBootclasspath.java index 9c3108b3834c..a4bd783d423c 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/bootstrap/ValueOnBootclasspath.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/bootstrap/ValueOnBootclasspath.java @@ -21,7 +21,7 @@ * questions. */ -package compiler.valhalla.inlinetypes.bootstrap; +package compiler.valhalla.valuetypes.bootstrap; import jdk.internal.vm.annotation.LooselyConsistentValue; diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/hack/GetUnresolvedInlineFieldWrongSignature.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/hack/GetUnresolvedValueFieldWrongSignature.java similarity index 83% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/hack/GetUnresolvedInlineFieldWrongSignature.java rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/hack/GetUnresolvedValueFieldWrongSignature.java index c95f05830959..74a7723d4201 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/hack/GetUnresolvedInlineFieldWrongSignature.java +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/hack/GetUnresolvedValueFieldWrongSignature.java @@ -21,9 +21,9 @@ * questions. */ -package compiler.valhalla.inlinetypes; +package compiler.valhalla.valuetypes; -class TestUnloadedInlineTypeField { +class TestUnloadedValueTypeField { static class MyValue3 { int foo; } @@ -74,25 +74,25 @@ static value class MyValue17 { } } -public class GetUnresolvedInlineFieldWrongSignature { +public class GetUnresolvedValueFieldWrongSignature { public static void test13(Object holder) { if (holder != null) { // Don't use MyValue13Holder in the signature, it might trigger class loading - ((TestUnloadedInlineTypeField.MyValue13Holder)holder).v = new TestUnloadedInlineTypeField.MyValue13(); + ((TestUnloadedValueTypeField.MyValue13Holder)holder).v = new TestUnloadedValueTypeField.MyValue13(); } } public static void test15(Object holder) { if (holder != null) { // Don't use MyValue15Holder in the signature, it might trigger class loading - ((TestUnloadedInlineTypeField.MyValue15Holder)holder).v = new TestUnloadedInlineTypeField.MyValue15(); + ((TestUnloadedValueTypeField.MyValue15Holder)holder).v = new TestUnloadedValueTypeField.MyValue15(); } } public static Object test16(boolean warmup) { if (!warmup) { - return new TestUnloadedInlineTypeField.MyValue16(); + return new TestUnloadedValueTypeField.MyValue16(); } else { return null; } @@ -100,7 +100,7 @@ public static Object test16(boolean warmup) { public static Object test17(boolean warmup) { if (!warmup) { - return new TestUnloadedInlineTypeField.MyValue17(); + return new TestUnloadedValueTypeField.MyValue17(); } else { return null; } diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/libTestJNICalls.c b/test/hotspot/jtreg/compiler/valhalla/valuetypes/libTestJNICalls.c similarity index 80% rename from test/hotspot/jtreg/compiler/valhalla/inlinetypes/libTestJNICalls.c rename to test/hotspot/jtreg/compiler/valhalla/valuetypes/libTestJNICalls.c index 87d1468042dc..b0114c6be031 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/libTestJNICalls.c +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/libTestJNICalls.c @@ -24,21 +24,21 @@ #include JNIEXPORT jobject JNICALL -Java_compiler_valhalla_inlinetypes_TestJNICalls_testMethod1(JNIEnv *env, jobject receiver, jobject vt) { +Java_compiler_valhalla_valuetypes_TestJNICalls_testMethod1(JNIEnv *env, jobject receiver, jobject vt) { jclass cls = (*env)->GetObjectClass(env, receiver); - jmethodID mid = (*env)->GetMethodID(env, cls, "test1", "(Lcompiler/valhalla/inlinetypes/MyValue1;Z)Lcompiler/valhalla/inlinetypes/MyValue1;"); + jmethodID mid = (*env)->GetMethodID(env, cls, "test1", "(Lcompiler/valhalla/valuetypes/MyValue1;Z)Lcompiler/valhalla/valuetypes/MyValue1;"); return (*env)->CallObjectMethod(env, receiver, mid, vt, JNI_TRUE); } JNIEXPORT jlong JNICALL -Java_compiler_valhalla_inlinetypes_TestJNICalls_testMethod2(JNIEnv *env, jobject receiver, jobject vt) { +Java_compiler_valhalla_valuetypes_TestJNICalls_testMethod2(JNIEnv *env, jobject receiver, jobject vt) { jclass cls = (*env)->GetObjectClass(env, vt); jmethodID mid = (*env)->GetMethodID(env, cls, "hash", "()J"); return (*env)->CallLongMethod(env, vt, mid); } JNIEXPORT jint JNICALL -Java_compiler_valhalla_inlinetypes_TestJNICalls_00024MyValueWithNative_testMethod3(JNIEnv *env, jobject receiver) { +Java_compiler_valhalla_valuetypes_TestJNICalls_00024MyValueWithNative_testMethod3(JNIEnv *env, jobject receiver) { jclass cls = (*env)->GetObjectClass(env, receiver); jfieldID fid = (*env)->GetFieldID(env, cls, "x", "I"); return (*env)->GetIntField(env, receiver, fid); diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestFloat16VectorFMAAccumSpill.java b/test/hotspot/jtreg/compiler/vectorapi/TestFloat16VectorFMAAccumSpill.java index 63aad3341e2b..6728741cb3db 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestFloat16VectorFMAAccumSpill.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestFloat16VectorFMAAccumSpill.java @@ -23,7 +23,7 @@ /** * @test -* @bug 8387213 +* @bug 8387213 8391717 * @summary Float16Vector.fma must accumulate in-place (231-form) so a register * blocked FMA reduction does not spill accumulators to the stack. * @modules jdk.incubator.vector @@ -81,9 +81,11 @@ public TestFloat16VectorFMAAccumSpill() { // reintroduces the accumulator-preserving copies/spills and fails this test. @Test @IR(counts = {IRNode.FMA_VHF, ">0"}, + applyIf = {"UseFMA", "true"}, applyIfCPUFeature = {"avx512_fp16", "true"}) @IR(failOn = {IRNode.MEM_TO_REG_SPILL_COPY_TYPE, "vector[xyz]"}, phase = {CompilePhase.FINAL_CODE}, + applyIf = {"UseFMA", "true"}, applyIfCPUFeature = {"avx512_fp16", "true"}) void fmaAccum() { Float16Vector c00 = (Float16Vector) SPECIES.zero(); diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestFloat16VectorOperations.java b/test/hotspot/jtreg/compiler/vectorapi/TestFloat16VectorOperations.java index 30d066d1b152..f627f2fbf626 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestFloat16VectorOperations.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestFloat16VectorOperations.java @@ -23,7 +23,7 @@ /** * @test -* @bug 8370691 +* @bug 8370691 8391717 * @summary Test intrinsification of Float16Vector operations * @modules jdk.incubator.vector * @library /test/lib / @@ -61,6 +61,9 @@ public static void main(String args[]) { TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", "-XX:MaxVectorSize=16"); TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", "-XX:MaxVectorSize=32"); TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", "-XX:MaxVectorSize=64"); + + // Test with FMA instructions disabled + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", "-XX:-UseFMA"); } static void assertResults(int arity, short ... values) { @@ -299,8 +302,10 @@ void checkResultSqrt() { @Test @IR(counts = {IRNode.FMA_VHF, " >0 "}, + applyIf = {"UseFMA", "true"}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true", "sve", "true"}) @IR(counts = {IRNode.FMA_VHF, " >0 "}, + applyIf = {"UseFMA", "true"}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) void vectorFmaFloat16() { int i = 0; @@ -332,8 +337,10 @@ void checkResultFma() { @Test @IR(counts = {IRNode.FMA_VHF, " >0 "}, + applyIf = {"UseFMA", "true"}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true", "sve", "true"}) @IR(counts = {IRNode.FMA_VHF, " >0 "}, + applyIf = {"UseFMA", "true"}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) void vectorFmaFloat16ScalarMixedConstants() { int i = 0; @@ -366,8 +373,10 @@ void checkResultFmaScalarMixedConstants() { @Test @IR(counts = {IRNode.FMA_VHF, " >0 "}, + applyIf = {"UseFMA", "true"}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true", "sve", "true"}) @IR(counts = {IRNode.FMA_VHF, " >0 "}, + applyIf = {"UseFMA", "true"}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) void vectorFmaFloat16MixedConstants() { short input3 = floatToFloat16(3.0f); @@ -401,8 +410,10 @@ void checkResultFmaMixedConstants() { @Test @IR(counts = {IRNode.FMA_VHF, " >0 "}, + applyIf = {"UseFMA", "true"}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true", "sve", "true"}) @IR(counts = {IRNode.FMA_VHF, " >0 "}, + applyIf = {"UseFMA", "true"}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) void vectorFmaFloat16AllConstants() { short input1 = floatToFloat16(1.0f); diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorBitwiseBlendTopInput.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorBitwiseBlendTopInput.java new file mode 100644 index 000000000000..d7dc3cd17a2e --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorBitwiseBlendTopInput.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2026, NVIDIA CORPORATION & 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 8389670 + * @library /test/lib / + * @summary Test that all the inputs of VectorBitwiseBlendNode are vectors + * @modules jdk.incubator.vector + * + * @run driver ${test.main.class} -DShuffleTests=false -DTest=bm,f --add-modules=jdk.incubator.vector + */ + +// The test is a reduced version of the one generated by VectorExpressionFuzzer.java + +package compiler.vectorapi; + +import compiler.lib.ir_framework.*; +import jdk.incubator.vector.*; + +public class TestVectorBitwiseBlendTopInput { + public static void main(String[] args) { + TestFramework framework = new TestFramework(); + framework.addFlags(args); + framework.start(); + } + + Object g = test_17(); + + @Test + Object test_17() { + return ShortVector.broadcast(ShortVector.SPECIES_128, 0); + } + + Object g(VectorShuffle a) { + return a; + } + + @Test + Object f() { + try { + return ((LongVector) + DoubleVector.broadcast(DoubleVector.SPECIES_256, 0) + .convertShape( + VectorOperators.Conversion.ofReinterpret(double.class, long.class), + LongVector.SPECIES_128, + 1)) + .bitwiseBlend( + VectorMask.fromArray(LongVector.SPECIES_256, + new boolean[] {true, true, true, true}, + 0).toLong(), + ((LongVector) DoubleVector.broadcast(DoubleVector.SPECIES_512, 0) + .convert(VectorOperators.Conversion.ofReinterpret(double.class, long.class), -1)) + .convertShape( + VectorOperators.Conversion.ofCast(long.class, long.class), + LongVector.SPECIES_128, + ShortVector.broadcast(ShortVector.SPECIES_128, 0).toShuffle().checkIndex(0))); + } catch (IndexOutOfBoundsException a) { + return a; + } + } + + @Test + Object bm() { + return DoubleVector.broadcast(DoubleVector.SPECIES_256, 0) + .lanewise( + VectorOperators.ADD, + ((DoubleVector) + LongVector.broadcast(LongVector.SPECIES_512, 0) + .reinterpretShape(DoubleVector.SPECIES_64, 1)) + .lane(0)); + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorFallbackInlining.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorFallbackInlining.java new file mode 100644 index 000000000000..dc332d56970e --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorFallbackInlining.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2026, 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 compiler.lib.verify.Verify; +import jdk.incubator.vector.FloatVector; +import jdk.incubator.vector.VectorSpecies; + +/* + * @test + * @bug 8382713 + * @summary Verify that the fallback implementation of a failed vector intrinsic is + * inlined (rather than left as a static call) when IncrementalInlineVector + * is enabled. + * @modules jdk.incubator.vector + * @library /test/lib / + * @requires vm.compiler2.enabled + * @run driver ${test.main.class} + */ + +/** + * Vector.withLane with a non-constant lane index cannot be intrinsified: the + * insert inline expander bails out because the index is not a compile-time constant. + * This is a species- and platform-agnostic limitation of the expander -- it is independent + * of the element type, vector shape and the available CPU features -- so the vector + * intrinsic reliably fails to expand and the fallback implementation + * is exercised on every configuration. + * + * With IncrementalInlineVector enabled (the default) the fallback is late-inlined into the + * caller, so no static call to intrinsic entry point survives; with the flag disabled, the + * static call to the fallback remains. + */ +public class TestVectorFallbackInlining { + private static final VectorSpecies SPECIES = FloatVector.SPECIES_MAX; + private static final int LENGTH = 1024; + + // Non-final so the JIT cannot treat the lane index as a compile-time constant, which + // is what forces the insert intrinsic to bail out to its fallback implementation. + private static int INDEX = SPECIES.length() - 1; + + private static final float[] a = new float[LENGTH]; + private static final float[] c = new float[LENGTH]; + + static { + for (int i = 0; i < LENGTH; i++) { + a[i] = i; + } + } + + // The fallback is only late-inlined if it also passes the regular inlining heuristics. + // During warmup VectorSupport::insert is called from the interpreter often enough to be + // compiled on its own, and with assertions enabled its nmethod grows beyond + // InlineSmallCode, so C2 rejects it as "already compiled into a big method". Keep it + // inlinable so that the rules below only depend on the late inlining machinery. + private static final String FORCE_INLINE_FALLBACK = + "-XX:CompileCommand=inline,jdk.internal.vm.vector.VectorSupport::insert"; + + public static void main(String[] args) { + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", + FORCE_INLINE_FALLBACK, + "-XX:+IncrementalInlineVector"); + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", + FORCE_INLINE_FALLBACK, + "-XX:-IncrementalInlineVector"); + } + + @Test + @IR(counts = {IRNode.VECTORAPI_INSERT_OP, ">= 1"}, + applyIf = {"IncrementalInlineVector", "false"}) + @IR(failOn = {IRNode.VECTORAPI_INSERT_OP}, + applyIf = {"IncrementalInlineVector", "true"}) + public static void testInsert() { + for (int i = 0; i < LENGTH; i += SPECIES.length()) { + FloatVector va = FloatVector.fromArray(SPECIES, a, i); + va.withLane(INDEX, 0.0f).intoArray(c, i); + } + } + + @Run(test = "testInsert") + @Warmup(10000) + public static void runInsert() { + testInsert(); + float[] expected = new float[LENGTH]; + for (int i = 0; i < LENGTH; i++) { + expected[i] = a[i]; + } + for (int i = 0; i < LENGTH; i += SPECIES.length()) { + expected[i + INDEX] = 0.0f; + } + Verify.checkEQ(expected, c); + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorTest.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorTest.java index c6329c70f659..ddc5d253462b 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestVectorTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, 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,17 +46,38 @@ public static void main(String[] args) { @DontInline public int call() { return 1; } + // The @IR rules below verify the VectorTest idealization that eliminates the + // scalar materialization (CmpI/CMoveI) of the mask query result. They are only + // valid when VectorMask.fromLong and the mask query are fully intrinsified. + // IncrementalInlineVector is enabled by default: when the intrinsic fails to + // apply on a given configuration (e.g. VectorMask.fromLong under -XX:UseAVX=0 + // or -XX:UseSVE=0/1 on AArch64), the fallback is inlined and materializes the + // result with the very scalar nodes these rules forbid. We therefore guard the + // rules to the configurations where full intrinsification is guaranteed: on x64 + // that requires UseAVX > 0 (and bmi2), on AArch64 that requires UseSVE > 1 + // (SVE2 mode, the default on SVE2-capable hardware), while on the remaining + // supported platforms the @requires clause above already guarantees it. @Test - @IR(failOn = {IRNode.CMP_I, IRNode.CMOVE_I}) - @IR(counts = {IRNode.VECTOR_TEST, "1"}) + @IR(failOn = {IRNode.CMP_I, IRNode.CMOVE_I}, counts = {IRNode.VECTOR_TEST, "1"}, + applyIfPlatform = {"x64", "true"}, applyIf = {"UseAVX", "> 0"}, + applyIfCPUFeature = {"bmi2", "true"}) + @IR(failOn = {IRNode.CMP_I, IRNode.CMOVE_I}, counts = {IRNode.VECTOR_TEST, "1"}, + applyIfPlatform = {"aarch64", "true"}, applyIf = {"UseSVE", "> 1"}) + @IR(failOn = {IRNode.CMP_I, IRNode.CMOVE_I}, counts = {IRNode.VECTOR_TEST, "1"}, + applyIfPlatformAnd = {"x64", "false", "aarch64", "false"}) public int branch(long maskLong) { var mask = VectorMask.fromLong(ByteVector.SPECIES_PREFERRED, maskLong); return mask.allTrue() ? call() : 0; } @Test - @IR(failOn = {IRNode.CMP_I}) - @IR(counts = {IRNode.VECTOR_TEST, "1", IRNode.CMOVE_I, "1"}) + @IR(failOn = {IRNode.CMP_I}, counts = {IRNode.VECTOR_TEST, "1", IRNode.CMOVE_I, "1"}, + applyIfPlatform = {"x64", "true"}, applyIf = {"UseAVX", "> 0"}, + applyIfCPUFeature = {"bmi2", "true"}) + @IR(failOn = {IRNode.CMP_I}, counts = {IRNode.VECTOR_TEST, "1", IRNode.CMOVE_I, "1"}, + applyIfPlatform = {"aarch64", "true"}, applyIf = {"UseSVE", "> 1"}) + @IR(failOn = {IRNode.CMP_I}, counts = {IRNode.VECTOR_TEST, "1", IRNode.CMOVE_I, "1"}, + applyIfPlatformAnd = {"x64", "false", "aarch64", "false"}) public int cmove(long maskLong) { var mask = VectorMask.fromLong(ByteVector.SPECIES_PREFERRED, maskLong); return mask.allTrue() ? 1 : 0; diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorCompareWithZeroTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorCompareWithZeroTest.java index 26e159fb768d..3d939ccdd224 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorCompareWithZeroTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorCompareWithZeroTest.java @@ -159,7 +159,8 @@ private static void assertArrayEquals(double[] a, boolean[] r, DoubleOp f) { } @Test - @IR(counts = { IRNode.VMASK_CMP_ZERO_I_NEON, ">= 1" }) + @IR(counts = { IRNode.VMASK_CMP_ZERO_I_NEON, ">= 1" }, + applyIf = { "TieredCompilation", "true" }) public static void testByteVectorEqualToZero() { ByteVector av = ByteVector.fromArray(B_SPECIES, ba, 0); av.compare(VectorOperators.EQ, 0).intoArray(br, 0); @@ -172,7 +173,8 @@ public static void testByteVectorEqualToZero_runner() { } @Test - @IR(counts = { IRNode.VMASK_CMP_ZERO_I_NEON, ">= 1" }) + @IR(counts = { IRNode.VMASK_CMP_ZERO_I_NEON, ">= 1" }, + applyIf = { "TieredCompilation", "true" }) public static void testShortVectorNotEqualToZero() { ShortVector av = ShortVector.fromArray(S_SPECIES, sa, 0); av.compare(VectorOperators.NE, 0).intoArray(sr, 0); @@ -185,7 +187,8 @@ public static void testShortVectorNotEqualToZero_runner() { } @Test - @IR(counts = { IRNode.VMASK_CMP_ZERO_I_NEON, ">= 1" }) + @IR(counts = { IRNode.VMASK_CMP_ZERO_I_NEON, ">= 1" }, + applyIf = { "TieredCompilation", "true" }) public static void testIntVectorGreaterEqualToZero() { IntVector av = IntVector.fromArray(I_SPECIES, ia, 0); av.compare(VectorOperators.GE, 0).intoArray(ir, 0); @@ -198,7 +201,8 @@ public static void testIntVectorGreaterEqualToZero_runner() { } @Test - @IR(counts = { IRNode.VMASK_CMP_ZERO_L_NEON, ">= 1" }) + @IR(counts = { IRNode.VMASK_CMP_ZERO_L_NEON, ">= 1" }, + applyIf = { "TieredCompilation", "true" }) public static void testLongVectorGreaterThanZero() { LongVector av = LongVector.fromArray(L_SPECIES, la, 0); av.compare(VectorOperators.GT, 0).intoArray(lr, 0); @@ -211,7 +215,8 @@ public static void testLongVectorGreaterThanZero_runner() { } @Test - @IR(counts = { IRNode.VMASK_CMP_ZERO_F_NEON, ">= 1" }) + @IR(counts = { IRNode.VMASK_CMP_ZERO_F_NEON, ">= 1" }, + applyIf = { "TieredCompilation", "true" }) public static void testFloatVectorLessEqualToZero() { FloatVector av = FloatVector.fromArray(F_SPECIES, fa, 0); av.compare(VectorOperators.LE, 0).intoArray(fr, 0); @@ -224,7 +229,8 @@ public static void testFloatVectorLessEqualToZero_runner() { } @Test - @IR(counts = { IRNode.VMASK_CMP_ZERO_D_NEON, ">= 1" }) + @IR(counts = { IRNode.VMASK_CMP_ZERO_D_NEON, ">= 1" }, + applyIf = { "TieredCompilation", "true" }) public static void testDoubleVectorLessThanZero() { DoubleVector av = DoubleVector.fromArray(D_SPECIES, da, 0); av.compare(VectorOperators.LT, 0).intoArray(dr, 0); @@ -237,20 +243,31 @@ public static void testDoubleVectorLessThanZero_runner() { } @Test - @IR(failOn = { IRNode.VMASK_CMP_ZERO_I_NEON }) + @IR(failOn = { IRNode.VMASK_CMP_ZERO_I_NEON }, + applyIf = { "TieredCompilation", "true" }) public static void testIntVectorUnsignedCondition() { IntVector av = IntVector.fromArray(I_SPECIES, ia, 0); av.compare(VectorOperators.UGT, 0).intoArray(ir, 0); } @Test - @IR(failOn = { IRNode.VMASK_CMP_ZERO_L_NEON }) + @IR(failOn = { IRNode.VMASK_CMP_ZERO_L_NEON }, + applyIf = { "TieredCompilation", "true" }) public static void testLongVectorUnsignedCondition() { LongVector av = LongVector.fromArray(L_SPECIES, la, 0); av.compare(VectorOperators.UGE, 0).intoArray(lr, 0); } public static void main(String[] args) { + // The @IR rules in this test verify that the optimized NEON compare-with-zero + // instructions (vmaskcmp_zero*_neon) are generated. IncrementalInlineVector is + // enabled by default; when a vector intrinsic fails to intrinsify, inlining its + // fallback implementation enlarges the compilation unit and, under unstable profiling, + // may prevent AbstractMask::intoArray() from being inlined. When intoArray() is not + // inlined, the mask is boxed before the call, which breaks the compare-with-zero + // match so the expected vmaskcmp_zero*_neon nodes are not produced. This only happens + // under unstable profiling (which makes the intoArray inlining decision + // non-deterministic); under the default profiling the match is stable. TestFramework testFramework = new TestFramework(); testFramework.setDefaultWarmup(10000) .addFlags("--add-modules=jdk.incubator.vector") diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java index 9a2f440ea822..a6128682ab11 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java @@ -276,7 +276,8 @@ public static void testCompareMaskNotDouble(VectorSpecies vs, VectorOper @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareEQMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.EQ, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.EQ); @@ -288,7 +289,8 @@ public static void testCompareEQMaskNotByte() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareNEMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.NE, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.NE); @@ -300,7 +302,8 @@ public static void testCompareNEMaskNotByte() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareLTMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.LT, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.LT); @@ -312,7 +315,8 @@ public static void testCompareLTMaskNotByte() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareGTMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.GT, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.GT); @@ -324,7 +328,8 @@ public static void testCompareGTMaskNotByte() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareLEMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.LE, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.LE); @@ -336,7 +341,8 @@ public static void testCompareLEMaskNotByte() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareGEMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.GE, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.GE); @@ -348,7 +354,8 @@ public static void testCompareGEMaskNotByte() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareULTMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.ULT, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.ULT); @@ -360,7 +367,8 @@ public static void testCompareULTMaskNotByte() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareUGTMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.UGT, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.UGT); @@ -372,7 +380,8 @@ public static void testCompareUGTMaskNotByte() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareULEMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.ULE, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.ULE); @@ -384,7 +393,8 @@ public static void testCompareULEMaskNotByte() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareUGEMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.UGE, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.UGE); @@ -397,7 +407,8 @@ public static void testCompareUGEMaskNotByte() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareEQMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.EQ, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.EQ); @@ -409,7 +420,8 @@ public static void testCompareEQMaskNotShort() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareNEMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.NE, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.NE); @@ -421,7 +433,8 @@ public static void testCompareNEMaskNotShort() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareLTMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.LT, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.LT); @@ -433,7 +446,8 @@ public static void testCompareLTMaskNotShort() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareGTMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.GT, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.GT); @@ -445,7 +459,8 @@ public static void testCompareGTMaskNotShort() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareLEMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.LE, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.LE); @@ -457,7 +472,8 @@ public static void testCompareLEMaskNotShort() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareGEMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.GE, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.GE); @@ -469,7 +485,8 @@ public static void testCompareGEMaskNotShort() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareULTMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.ULT, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.ULT); @@ -481,7 +498,8 @@ public static void testCompareULTMaskNotShort() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareUGTMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.UGT, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.UGT); @@ -493,7 +511,8 @@ public static void testCompareUGTMaskNotShort() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareULEMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.ULE, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.ULE); @@ -505,7 +524,8 @@ public static void testCompareULEMaskNotShort() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareUGEMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.UGE, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.UGE); @@ -518,7 +538,8 @@ public static void testCompareUGEMaskNotShort() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareEQMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.EQ, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.EQ); @@ -530,7 +551,8 @@ public static void testCompareEQMaskNotInt() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareNEMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.NE, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.NE); @@ -542,7 +564,8 @@ public static void testCompareNEMaskNotInt() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareLTMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.LT, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.LT); @@ -554,7 +577,8 @@ public static void testCompareLTMaskNotInt() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareGTMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.GT, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.GT); @@ -566,7 +590,8 @@ public static void testCompareGTMaskNotInt() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareLEMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.LE, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.LE); @@ -578,7 +603,8 @@ public static void testCompareLEMaskNotInt() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareGEMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.GE, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.GE); @@ -590,7 +616,8 @@ public static void testCompareGEMaskNotInt() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareULTMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.ULT, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.ULT); @@ -602,7 +629,8 @@ public static void testCompareULTMaskNotInt() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareUGTMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.UGT, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.UGT); @@ -614,7 +642,8 @@ public static void testCompareUGTMaskNotInt() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareULEMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.ULE, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.ULE); @@ -626,7 +655,8 @@ public static void testCompareULEMaskNotInt() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareUGEMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.UGE, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.UGE); @@ -640,7 +670,8 @@ public static void testCompareUGEMaskNotInt() { IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CAST, "= 1", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareEQMaskNotLong() { testCompareMaskNotLong(L_SPECIES, VectorOperators.EQ, (m) -> { return m.not(); }); verifyResultsLong(L_SPECIES, VectorOperators.EQ); @@ -656,7 +687,8 @@ public static void testCompareEQMaskNotLong() { IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CAST, "= 1", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareNEMaskNotLong() { testCompareMaskNotLong(L_SPECIES, VectorOperators.NE, (m) -> { return m.not(); }); verifyResultsLong(L_SPECIES, VectorOperators.NE); @@ -672,7 +704,8 @@ public static void testCompareNEMaskNotLong() { IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CAST, "= 1", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareLTMaskNotLong() { testCompareMaskNotLong(L_SPECIES, VectorOperators.LT, (m) -> { return m.not(); }); verifyResultsLong(L_SPECIES, VectorOperators.LT); @@ -688,7 +721,8 @@ public static void testCompareLTMaskNotLong() { IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CAST, "= 1", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareGTMaskNotLong() { testCompareMaskNotLong(L_SPECIES, VectorOperators.GT, (m) -> { return m.not(); }); verifyResultsLong(L_SPECIES, VectorOperators.GT); @@ -704,7 +738,8 @@ public static void testCompareGTMaskNotLong() { IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CAST, "= 1", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareLEMaskNotLong() { testCompareMaskNotLong(L_SPECIES, VectorOperators.LE, (m) -> { return m.not(); }); verifyResultsLong(L_SPECIES, VectorOperators.LE); @@ -720,7 +755,8 @@ public static void testCompareLEMaskNotLong() { IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CAST, "= 1", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareGEMaskNotLong() { testCompareMaskNotLong(L_SPECIES, VectorOperators.GE, (m) -> { return m.not(); }); verifyResultsLong(L_SPECIES, VectorOperators.GE); @@ -736,7 +772,8 @@ public static void testCompareGEMaskNotLong() { IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CAST, "= 1", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareULTMaskNotLong() { testCompareMaskNotLong(L_SPECIES, VectorOperators.ULT, (m) -> { return m.not(); }); verifyResultsLong(L_SPECIES, VectorOperators.ULT); @@ -752,7 +789,8 @@ public static void testCompareULTMaskNotLong() { IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CAST, "= 1", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareUGTMaskNotLong() { testCompareMaskNotLong(L_SPECIES, VectorOperators.UGT, (m) -> { return m.not(); }); verifyResultsLong(L_SPECIES, VectorOperators.UGT); @@ -768,7 +806,8 @@ public static void testCompareUGTMaskNotLong() { IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CAST, "= 1", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareULEMaskNotLong() { testCompareMaskNotLong(L_SPECIES, VectorOperators.ULE, (m) -> { return m.not(); }); verifyResultsLong(L_SPECIES, VectorOperators.ULE); @@ -784,7 +823,8 @@ public static void testCompareULEMaskNotLong() { IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CAST, "= 1", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareUGEMaskNotLong() { testCompareMaskNotLong(L_SPECIES, VectorOperators.UGE, (m) -> { return m.not(); }); verifyResultsLong(L_SPECIES, VectorOperators.UGE); @@ -799,7 +839,8 @@ public static void testCompareUGEMaskNotLong() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareEQMaskNotFloat() { testCompareMaskNotFloat(F_SPECIES, VectorOperators.EQ, fa, fb, (m) -> { return m.not(); }); verifyResultsFloat(F_SPECIES, VectorOperators.EQ, fa, fb); @@ -811,7 +852,8 @@ public static void testCompareEQMaskNotFloat() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareNEMaskNotFloat() { testCompareMaskNotFloat(F_SPECIES, VectorOperators.NE, fa, fb, (m) -> { return m.not(); }); verifyResultsFloat(F_SPECIES, VectorOperators.NE, fa, fb); @@ -823,7 +865,8 @@ public static void testCompareNEMaskNotFloat() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareEQMaskNotFloatNaN() { testCompareMaskNotFloat(F_SPECIES, VectorOperators.EQ, fa, fnan, (m) -> { return m.not(); }); verifyResultsFloat(F_SPECIES, VectorOperators.EQ, fa, fnan); @@ -835,7 +878,8 @@ public static void testCompareEQMaskNotFloatNaN() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareNEMaskNotFloatNaN() { testCompareMaskNotFloat(F_SPECIES, VectorOperators.NE, fa, fnan, (m) -> { return m.not(); }); verifyResultsFloat(F_SPECIES, VectorOperators.NE, fa, fnan); @@ -847,7 +891,8 @@ public static void testCompareNEMaskNotFloatNaN() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareEQMaskNotFloatPositiveInfinity() { testCompareMaskNotFloat(F_SPECIES, VectorOperators.EQ, fa, fpinf, (m) -> { return m.not(); }); verifyResultsFloat(F_SPECIES, VectorOperators.EQ, fa, fpinf); @@ -859,7 +904,8 @@ public static void testCompareEQMaskNotFloatPositiveInfinity() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareNEMaskNotFloatPositiveInfinity() { testCompareMaskNotFloat(F_SPECIES, VectorOperators.NE, fa, fpinf, (m) -> { return m.not(); }); verifyResultsFloat(F_SPECIES, VectorOperators.NE, fa, fpinf); @@ -871,7 +917,8 @@ public static void testCompareNEMaskNotFloatPositiveInfinity() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareEQMaskNotFloatNegativeInfinity() { testCompareMaskNotFloat(F_SPECIES, VectorOperators.EQ, fa, fninf, (m) -> { return m.not(); }); verifyResultsFloat(F_SPECIES, VectorOperators.EQ, fa, fninf); @@ -883,7 +930,8 @@ public static void testCompareEQMaskNotFloatNegativeInfinity() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareNEMaskNotFloatNegativeInfinity() { testCompareMaskNotFloat(F_SPECIES, VectorOperators.NE, fa, fninf, (m) -> { return m.not(); }); verifyResultsFloat(F_SPECIES, VectorOperators.NE, fa, fninf); @@ -895,7 +943,8 @@ public static void testCompareNEMaskNotFloatNegativeInfinity() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareEQMaskNotDouble() { testCompareMaskNotDouble(D_SPECIES, VectorOperators.EQ, da, db, (m) -> { return m.not(); }); verifyResultsDouble(D_SPECIES, VectorOperators.EQ, da, db); @@ -907,7 +956,8 @@ public static void testCompareEQMaskNotDouble() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareNEMaskNotDouble() { testCompareMaskNotDouble(D_SPECIES, VectorOperators.NE, da, db, (m) -> { return m.not(); }); verifyResultsDouble(D_SPECIES, VectorOperators.NE, da, db); @@ -919,7 +969,8 @@ public static void testCompareNEMaskNotDouble() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareEQMaskNotDoubleNaN() { testCompareMaskNotDouble(D_SPECIES, VectorOperators.EQ, da, dnan, (m) -> { return m.not(); }); verifyResultsDouble(D_SPECIES, VectorOperators.EQ, da, dnan); @@ -931,7 +982,8 @@ public static void testCompareEQMaskNotDoubleNaN() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareNEMaskNotDoubleNaN() { testCompareMaskNotDouble(D_SPECIES, VectorOperators.NE, da, dnan, (m) -> { return m.not(); }); verifyResultsDouble(D_SPECIES, VectorOperators.NE, da, dnan); @@ -943,7 +995,8 @@ public static void testCompareNEMaskNotDoubleNaN() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareEQMaskNotDoublePositiveInfinity() { testCompareMaskNotDouble(D_SPECIES, VectorOperators.EQ, da, dpinf, (m) -> { return m.not(); }); verifyResultsDouble(D_SPECIES, VectorOperators.EQ, da, dpinf); @@ -955,7 +1008,8 @@ public static void testCompareEQMaskNotDoublePositiveInfinity() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareNEMaskNotDoublePositiveInfinity() { testCompareMaskNotDouble(D_SPECIES, VectorOperators.NE, da, dpinf, (m) -> { return m.not(); }); verifyResultsDouble(D_SPECIES, VectorOperators.NE, da, dpinf); @@ -967,7 +1021,8 @@ public static void testCompareNEMaskNotDoublePositiveInfinity() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareEQMaskNotDoubleNegativeInfinity() { testCompareMaskNotDouble(D_SPECIES, VectorOperators.EQ, da, dninf, (m) -> { return m.not(); }); verifyResultsDouble(D_SPECIES, VectorOperators.EQ, da, dninf); @@ -979,7 +1034,8 @@ public static void testCompareEQMaskNotDoubleNegativeInfinity() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareNEMaskNotDoubleNegativeInfinity() { testCompareMaskNotDouble(D_SPECIES, VectorOperators.NE, da, dninf, (m) -> { return m.not(); }); verifyResultsDouble(D_SPECIES, VectorOperators.NE, da, dninf); @@ -992,13 +1048,16 @@ public static void testCompareNEMaskNotDoubleNegativeInfinity() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "avx2", "true" }) + applyIfCPUFeatureAnd = { "avx2", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareMaskNotByteNegative() { testCompareMaskNotByte(B_SPECIES, VectorOperators.EQ, (m) -> { // The vector mask is used multiple times. @@ -1015,13 +1074,16 @@ public static void testCompareMaskNotByteNegative() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "avx2", "true" }) + applyIfCPUFeatureAnd = { "avx2", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareMaskNotShortNegative() { testCompareMaskNotShort(S_SPECIES, VectorOperators.EQ, (m) -> { // The vector mask is used multiple times. @@ -1038,13 +1100,16 @@ public static void testCompareMaskNotShortNegative() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "avx2", "true" }) + applyIfCPUFeatureAnd = { "avx2", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareMaskNotIntNegative() { testCompareMaskNotInt(I_SPECIES, VectorOperators.EQ, (m) -> { // The vector mask is used multiple times. @@ -1061,13 +1126,16 @@ public static void testCompareMaskNotIntNegative() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "avx2", "true" }) + applyIfCPUFeatureAnd = { "avx2", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareMaskNotLongNegative() { testCompareMaskNotLong(L_SPECIES, VectorOperators.EQ, (m) -> { // The vector mask is used multiple times. @@ -1084,13 +1152,16 @@ public static void testCompareMaskNotLongNegative() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 3", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V, "= 3", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V, "= 3", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureAnd = { "avx2", "true" }) + applyIfCPUFeatureAnd = { "avx2", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareMaskNotFloatNegative() { testCompareMaskNotFloat(F_SPECIES, VectorOperators.EQ, fa, fb, (m) -> { // The vector mask is used multiple times. @@ -1111,13 +1182,16 @@ public static void testCompareMaskNotFloatNegative() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 3", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V, "= 3", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V, "= 3", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureAnd = { "avx2", "true" }) + applyIfCPUFeatureAnd = { "avx2", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareMaskNotDoubleNegative() { testCompareMaskNotDouble(D_SPECIES, VectorOperators.EQ, da, db, (m) -> { // The vector mask is used multiple times. @@ -1156,15 +1230,18 @@ public static void testCompareMaskNotDoubleNegative() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "sve", "true" }) + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareEQMaskNotByteCast() { testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.EQ, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.EQ); @@ -1173,15 +1250,18 @@ public static void testCompareEQMaskNotByteCast() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "sve", "true" }) + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareNEMaskNotByteCast() { testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.NE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.NE); @@ -1190,15 +1270,18 @@ public static void testCompareNEMaskNotByteCast() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "sve", "true" }) + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareLTMaskNotByteCast() { testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.LT, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.LT); @@ -1207,15 +1290,18 @@ public static void testCompareLTMaskNotByteCast() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "sve", "true" }) + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareGTMaskNotByteCast() { testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.GT, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.GT); @@ -1224,15 +1310,18 @@ public static void testCompareGTMaskNotByteCast() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "sve", "true" }) + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareLEMaskNotByteCast() { testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.LE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.LE); @@ -1241,15 +1330,18 @@ public static void testCompareLEMaskNotByteCast() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "sve", "true" }) + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareGEMaskNotByteCast() { testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.GE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.GE); @@ -1258,15 +1350,18 @@ public static void testCompareGEMaskNotByteCast() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "sve", "true" }) + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareULTMaskNotByteCast() { testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.ULT, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.ULT); @@ -1275,15 +1370,18 @@ public static void testCompareULTMaskNotByteCast() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "sve", "true" }) + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareUGTMaskNotByteCast() { testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.UGT, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.UGT); @@ -1292,15 +1390,18 @@ public static void testCompareUGTMaskNotByteCast() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "sve", "true" }) + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareULEMaskNotByteCast() { testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.ULE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.ULE); @@ -1309,15 +1410,18 @@ public static void testCompareULEMaskNotByteCast() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "sve", "true" }) + applyIfCPUFeatureAnd = { "sve", "true" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareUGEMaskNotByteCast() { testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.UGE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.UGE); @@ -1327,15 +1431,17 @@ public static void testCompareUGEMaskNotByteCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "MaxVectorSize", "= 16" }) + applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareEQMaskNotShortCast() { testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.EQ, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.EQ); @@ -1347,15 +1453,17 @@ public static void testCompareEQMaskNotShortCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "MaxVectorSize", "= 16" }) + applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareNEMaskNotShortCast() { testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.NE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.NE); @@ -1367,15 +1475,17 @@ public static void testCompareNEMaskNotShortCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "MaxVectorSize", "= 16" }) + applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareLTMaskNotShortCast() { testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.LT, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.LT); @@ -1387,15 +1497,17 @@ public static void testCompareLTMaskNotShortCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "MaxVectorSize", "= 16" }) + applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareGTMaskNotShortCast() { testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.GT, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.GT); @@ -1407,15 +1519,17 @@ public static void testCompareGTMaskNotShortCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "MaxVectorSize", "= 16" }) + applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareLEMaskNotShortCast() { testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.LE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.LE); @@ -1427,15 +1541,17 @@ public static void testCompareLEMaskNotShortCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "MaxVectorSize", "= 16" }) + applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareGEMaskNotShortCast() { testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.GE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.GE); @@ -1447,15 +1563,17 @@ public static void testCompareGEMaskNotShortCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "MaxVectorSize", "= 16" }) + applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareULTMaskNotShortCast() { testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.ULT, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.ULT); @@ -1467,15 +1585,17 @@ public static void testCompareULTMaskNotShortCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "MaxVectorSize", "= 16" }) + applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareUGTMaskNotShortCast() { testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.UGT, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.UGT); @@ -1487,15 +1607,17 @@ public static void testCompareUGTMaskNotShortCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "MaxVectorSize", "= 16" }) + applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareULEMaskNotShortCast() { testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.ULE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.ULE); @@ -1507,15 +1629,17 @@ public static void testCompareULEMaskNotShortCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "MaxVectorSize", "= 16" }) + applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareUGEMaskNotShortCast() { testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.UGE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.UGE); @@ -1527,15 +1651,17 @@ public static void testCompareUGEMaskNotShortCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "MaxVectorSize", "= 16" }) + applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareEQMaskNotIntCast() { testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.EQ, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.EQ); @@ -1547,15 +1673,17 @@ public static void testCompareEQMaskNotIntCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "MaxVectorSize", "= 16" }) + applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareNEMaskNotIntCast() { testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.NE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.NE); @@ -1567,15 +1695,17 @@ public static void testCompareNEMaskNotIntCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "MaxVectorSize", "= 16" }) + applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareLTMaskNotIntCast() { testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.LT, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.LT); @@ -1587,15 +1717,17 @@ public static void testCompareLTMaskNotIntCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "MaxVectorSize", "= 16" }) + applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareGTMaskNotIntCast() { testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.GT, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.GT); @@ -1607,15 +1739,17 @@ public static void testCompareGTMaskNotIntCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "MaxVectorSize", "= 16" }) + applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareLEMaskNotIntCast() { testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.LE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.LE); @@ -1627,15 +1761,17 @@ public static void testCompareLEMaskNotIntCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "MaxVectorSize", "= 16" }) + applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareGEMaskNotIntCast() { testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.GE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.GE); @@ -1647,15 +1783,17 @@ public static void testCompareGEMaskNotIntCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "MaxVectorSize", "= 16" }) + applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareULTMaskNotIntCast() { testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.ULT, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.ULT); @@ -1667,15 +1805,17 @@ public static void testCompareULTMaskNotIntCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "MaxVectorSize", "= 16" }) + applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareUGTMaskNotIntCast() { testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.UGT, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.UGT); @@ -1687,15 +1827,17 @@ public static void testCompareUGTMaskNotIntCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "MaxVectorSize", "= 16" }) + applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareULEMaskNotIntCast() { testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.ULE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.ULE); @@ -1707,15 +1849,17 @@ public static void testCompareULEMaskNotIntCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "MaxVectorSize", "= 16" }) + applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) public static void testCompareUGEMaskNotIntCast() { testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.UGE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.UGE); @@ -1726,13 +1870,16 @@ public static void testCompareUGEMaskNotIntCast() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, + applyIf = { "TieredCompilation", "true" }) @IR(counts = { IRNode.XOR_V, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "avx2", "true", "avx512", "false" }) + applyIfCPUFeatureAnd = { "avx2", "true", "avx512", "false" }, + applyIf = { "TieredCompilation", "true" }) public static void testMaskedCompareMaskNotNegative() { int expected = F_SPECIES.length(); var ones = FloatVector.broadcast(F_SPECIES, 1f); @@ -1745,6 +1892,17 @@ public static void testMaskedCompareMaskNotNegative() { } public static void main(String[] args) { + // The @IR rules in this test verify that XorVMask(VectorMaskCmp, maskAll(true)) + // is folded away, i.e. that no XorV/XorVMask node survives. IncrementalInlineVector + // is enabled by default; when a vector intrinsic fails to intrinsify, inlining its + // fallback implementation enlarges the compilation unit and, under unstable profiling, + // may prevent AbstractMask::intoArray() from being inlined. When intoArray() is not + // inlined, the mask must be boxed before the call, and during VectorBoxNode + // scalarization a VectorStoreMask user is added to the VectorMaskCmp node. The extra + // out-edge raises VectorMaskCmp's out-count, which inhibits the fold and leaves the + // XorVMask/XorV nodes the rules expect to be absent. This only happens under + // unstable profiling (which makes the intoArray inlining decision non-deterministic); + // under the default profiling the fold is stable. TestFramework testFramework = new TestFramework(); testFramework.setDefaultWarmup(10000) .addFlags("--add-modules=jdk.incubator.vector") diff --git a/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java b/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java index 00a556cff8f5..e3c44f9d03c9 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java @@ -24,7 +24,7 @@ /** * @test -* @bug 8346236 8381617 +* @bug 8346236 8381617 8391717 * @summary Auto-vectorization support for various Float16 operations * @modules jdk.incubator.vector * @library /test/lib / @@ -238,8 +238,10 @@ public void checkResultSqrt() { @Test @Warmup(50) @IR(counts = {IRNode.FMA_VHF, " >0 "}, + applyIf = {"UseFMA", "true"}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true"}) @IR(counts = {IRNode.FMA_VHF, " >0 "}, + applyIf = {"UseFMA", "true"}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void vectorFmaFloat16() { for (int i = 0; i < LEN; ++i) { @@ -260,8 +262,10 @@ public void checkResultFma() { @Test @Warmup(50) @IR(counts = {IRNode.FMA_VHF, " >0 "}, + applyIf = {"UseFMA", "true"}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true"}) @IR(counts = {IRNode.FMA_VHF, " >0 "}, + applyIf = {"UseFMA", "true"}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void vectorFmaFloat16ScalarMixedConstants() { for (int i = 0; i < LEN; ++i) { @@ -283,8 +287,10 @@ public void checkResultFmaScalarMixedConstants() { @Test @Warmup(50) @IR(counts = {IRNode.FMA_VHF, " >0 "}, + applyIf = {"UseFMA", "true"}, applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true"}) @IR(counts = {IRNode.FMA_VHF, " >0 "}, + applyIf = {"UseFMA", "true"}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void vectorFmaFloat16MixedConstants() { short input3 = floatToFloat16(3.0f); diff --git a/test/hotspot/jtreg/gc/arguments/TestMinAndInitialSurvivorRatioFlags.java b/test/hotspot/jtreg/gc/arguments/TestMinAndInitialSurvivorRatioFlags.java deleted file mode 100644 index 52974d8c1430..000000000000 --- a/test/hotspot/jtreg/gc/arguments/TestMinAndInitialSurvivorRatioFlags.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (c) 2015, 2025, 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 gc.arguments; - -/* - * @test TestMinAndInitialSurvivorRatioFlags - * @summary Verify that MinSurvivorRatio and InitialSurvivorRatio flags work - * @library /test/lib - * @library / - * @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 driver/timeout=240 gc.arguments.TestMinAndInitialSurvivorRatioFlags - */ - -import java.lang.management.MemoryUsage; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedList; -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.Utils; -import jdk.test.whitebox.WhiteBox; - -/* Test verifies that VM can start with any GC when MinSurvivorRatio and - * InitialSurvivorRatio flags passed and for Parallel GC it verifies that - * after start up survivor ratio equal to InitialSurvivorRatio value and - * that actual survivor ratio will never be less than MinSurvivorRatio. - */ -public class TestMinAndInitialSurvivorRatioFlags { - - public static final long M = 1024 * 1024; - public static final long HEAP_SIZE = 200 * M; - public static final long NEW_SIZE = 100 * M; - - public static void main(String args[]) throws Exception { - LinkedList options = new LinkedList<>( - Arrays.asList(Utils.getFilteredTestJavaOpts("-XX:[^ ]*SurvivorRatio=[^ ]+")) - ); - - testSurvivorRatio(5, -1, -1, options, true); - testSurvivorRatio(10, -1, -1, options, true); - testSurvivorRatio(-1, 5, 3, options, true); - testSurvivorRatio(-1, 15, 3, options, true); - testSurvivorRatio(-1, 15, 3, options, false); - testSurvivorRatio(-1, 10, 10, options, true); - } - - /** - * Test that MinSurvivorRatio and InitialSurvivorRatio flags work. - * - * @param survivorRatio value for -XX:SurvivorRatio option, omitted if negative - * @param initRatio value for -XX:InitialSurvivorRatio option, omitted if negative - * @param minRatio value for -XX:MinSurvivorRatio option, omitted if negative - * @param options additional options for VM - * @param useAdaptiveSizePolicy turn on or off UseAdaptiveSizePolicy option - */ - public static void testSurvivorRatio(int survivorRatio, - int initRatio, - int minRatio, - LinkedList options, - boolean useAdaptiveSizePolicy) throws Exception { - - LinkedList vmOptions = new LinkedList<>(options); - Collections.addAll(vmOptions, - "-Xbootclasspath/a:.", - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+WhiteBoxAPI", - "-XX:MaxNewSize=" + NEW_SIZE, "-XX:NewSize=" + NEW_SIZE, - "-Xmx" + HEAP_SIZE, "-Xms" + HEAP_SIZE, - (survivorRatio >= 0 ? "-XX:SurvivorRatio=" + survivorRatio : ""), - (initRatio >= 0 ? "-XX:InitialSurvivorRatio=" + initRatio : ""), - (minRatio >= 0 ? "-XX:MinSurvivorRatio=" + minRatio : ""), - (useAdaptiveSizePolicy ? "-XX:+UseAdaptiveSizePolicy" : "-XX:-UseAdaptiveSizePolicy"), - SurvivorRatioVerifier.class.getName(), - Integer.toString(survivorRatio), - Integer.toString(initRatio), - Integer.toString(minRatio), - Boolean.toString(useAdaptiveSizePolicy) - ); - vmOptions.removeIf((String p) -> p.isEmpty()); - OutputAnalyzer analyzer = GCArguments.executeLimitedTestJava(vmOptions); - analyzer.shouldHaveExitValue(0); - } - - /** - * Class that verifies survivor ratio. - * Will be executed in tested VM. Checks initial size of eden and survivor paces with alignment. - */ - public static class SurvivorRatioVerifier { - - public static WhiteBox wb = WhiteBox.getWhiteBox(); - - public static final int MAX_ITERATIONS = 10; - public static final int ARRAY_LENGTH = 10000; - public static final int CHUNK_SIZE = 10000; - - public static byte garbage[][] = new byte[ARRAY_LENGTH][]; - - public static void main(String args[]) throws Exception { - if (args.length != 4) { - throw new IllegalArgumentException("Expected 4 args: "); - } - final int survivorRatio = Integer.valueOf(args[0]); - final int initRatio = Integer.valueOf(args[1]); - final int minRatio = Integer.valueOf(args[2]); - final boolean useAdaptiveSizePolicy = Boolean.valueOf(args[3]); - - // we stop testing only here to ensure that JVM will accept - // both MinSurvivorRatio and InitialSurvivorRatio regardles to GC - if (GCTypes.YoungGCType.getYoungGCType() != GCTypes.YoungGCType.PSNew) { - System.out.println("Test is only applicable to Parallel GC"); - return; - } - - // verify initial survivor ratio - verifySurvivorRatio(survivorRatio, initRatio, minRatio, useAdaptiveSizePolicy, true); - - // force GC - AllocationHelper allocator = new AllocationHelper(MAX_ITERATIONS, ARRAY_LENGTH, CHUNK_SIZE, - () -> (verifySurvivorRatio(survivorRatio, initRatio, minRatio, useAdaptiveSizePolicy, false))); - allocator.allocateMemoryAndVerify(); - } - - /** - * Verify actual survivor ratio. - * - * @param survivorRatio value of SurvivorRatio option, omitted if negative - * @param initRatio value of InitialSurvivorRatio option, omitted if negative - * @param minRatio value of MinSurvivorRatio option, omitted if negative - * @param useAdaptiveSizePolicy value of UseAdaptiveSizePolicy option - * @param verifyInitialRatio true if we are going to verify initial ratio - */ - public static Void verifySurvivorRatio(int survivorRatio, - int initRatio, - int minRatio, - boolean useAdaptiveSizePolicy, - boolean verifyInitialRatio) { - - MemoryUsage edenUsage = HeapRegionUsageTool.getEdenUsage(); - MemoryUsage survivorUsage = HeapRegionUsageTool.getSurvivorUsage(); - - long alignedNewSize = edenUsage.getMax() + 2 * survivorUsage.getMax(); - long spaceAlignment = wb.getHeapSpaceAlignment(); - - if (survivorRatio >= 0) { - // -XX:SurvivorRatio was passed to JVM, actual ratio should be SurvivorRatio + 2 - long expectedSize = HeapRegionUsageTool.alignDown(alignedNewSize / (survivorRatio + 2), - spaceAlignment); - - if (survivorUsage.getCommitted() != expectedSize) { - throw new RuntimeException("Expected survivor size is: " + expectedSize - + ", but observed size is: " + survivorUsage.getCommitted()); - } - } else if (verifyInitialRatio || !useAdaptiveSizePolicy) { - // In case of initial ratio verification or disabled adaptive size policy - // ratio should be equal to InitialSurvivorRatio value - long expectedSize = HeapRegionUsageTool.alignDown(alignedNewSize / initRatio, - spaceAlignment); - if (survivorUsage.getCommitted() != expectedSize) { - throw new RuntimeException("Expected survivor size is: " + expectedSize - + ", but observed size is: " + survivorUsage.getCommitted()); - } - } else { - // In any other case actual survivor ratio should not be lower than MinSurvivorRatio - // or is should be equal to InitialSurvivorRatio - long expectedMinSize = HeapRegionUsageTool.alignDown(alignedNewSize / minRatio, - spaceAlignment); - long expectedInitSize = HeapRegionUsageTool.alignDown(alignedNewSize / initRatio, - spaceAlignment); - if (survivorUsage.getCommitted() != expectedInitSize - && survivorUsage.getCommitted() < expectedMinSize) { - throw new RuntimeException("Expected survivor size should be " + expectedMinSize - + " or should be greater then " + expectedMinSize - + ", but observer survivor size is " + survivorUsage.getCommitted()); - } - } - return null; - } - } -} diff --git a/test/hotspot/jtreg/gc/arguments/TestSurvivorRatioFlag.java b/test/hotspot/jtreg/gc/arguments/TestSurvivorRatioFlag.java index 36b85e8c09de..cbd743a12cb2 100644 --- a/test/hotspot/jtreg/gc/arguments/TestSurvivorRatioFlag.java +++ b/test/hotspot/jtreg/gc/arguments/TestSurvivorRatioFlag.java @@ -26,7 +26,7 @@ /* * @test TestSurvivorRatioFlag * @summary Verify that actual survivor ratio is equal to specified SurvivorRatio value - * @requires vm.gc != "Z" & vm.gc != "Shenandoah" + * @requires vm.gc == "Serial" | vm.gc == "G1" * @library /test/lib * @library / * @modules java.base/jdk.internal.misc @@ -114,9 +114,8 @@ public static void main(String args[]) throws Exception { /** * Verify that actual survivor ratio is equal to expected. * Depending on selected young GC we verify that: - * - for DefNew and ParNew: eden_size / survivor_size is close to expectedRatio; - * - for PSNew: survivor_size equal to young_gen_size / expectedRatio; - * - for G1: survivor_regions <= num_young_regions / expectedRatio. + * - for DefNew: eden_size / survivor_size is close to expectedRatio; + * - for G1: survivor_regions <= num_young_regions / expectedRatio. */ public static Void verifySurvivorRatio(int expectedRatio) { GCTypes.YoungGCType type = GCTypes.YoungGCType.getYoungGCType(); @@ -124,9 +123,6 @@ public static Void verifySurvivorRatio(int expectedRatio) { case DefNew: verifyDefNewSurvivorRatio(expectedRatio); break; - case PSNew: - verifyPSSurvivorRatio(expectedRatio); - break; case G1: verifyG1SurvivorRatio(expectedRatio); break; @@ -147,21 +143,6 @@ private static void verifyDefNewSurvivorRatio(int expectedRatio) { } } - private static void verifyPSSurvivorRatio(int expectedRatio) { - MemoryUsage edenUsage = HeapRegionUsageTool.getEdenUsage(); - MemoryUsage survivorUsage = HeapRegionUsageTool.getSurvivorUsage(); - - long youngGenSize = edenUsage.getMax() + 2 * survivorUsage.getMax(); - // for Paralle GC Min/InitialSurvivorRatio = SurvivorRatio + 2 - long expectedSize = HeapRegionUsageTool.alignDown(youngGenSize / (expectedRatio + 2), - wb.getHeapSpaceAlignment()); - - if (expectedSize != survivorUsage.getCommitted()) { - throw new RuntimeException("Expected survivor size is: " + expectedSize - + ", but observed size is: " + survivorUsage.getCommitted()); - } - } - private static void verifyG1SurvivorRatio(int expectedRatio) { MemoryUsage survivorUsage = HeapRegionUsageTool.getSurvivorUsage(); diff --git a/test/hotspot/jtreg/gc/parallel/TestGenBoundary.java b/test/hotspot/jtreg/gc/parallel/TestGenBoundary.java new file mode 100644 index 000000000000..7909deecafee --- /dev/null +++ b/test/hotspot/jtreg/gc/parallel/TestGenBoundary.java @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2026, 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 gc.parallel; + +/* + * @test TestGenBoundary + * @bug 8386885 + * @summary Verify Parallel GC generation-boundary transitions with adaptive sizing + * @requires vm.gc.Parallel + * @requires vm.flagless + * @library /test/lib + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run driver gc.parallel.TestGenBoundary + */ + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.whitebox.WhiteBox; + +import static jdk.test.lib.Asserts.assertEQ; +import static jdk.test.lib.Asserts.assertGT; +import static jdk.test.lib.Asserts.assertLT; + +public class TestGenBoundary { + private static final Pattern HEAP_STATE = Pattern.compile( + "Young Gen: \\[(0x[0-9a-f]+), (0x[0-9a-f]+), (0x[0-9a-f]+)\\).*?" + + "Old Gen: \\[(0x[0-9a-f]+), (0x[0-9a-f]+), (0x[0-9a-f]+)\\)", + Pattern.DOTALL); + + public static void main(String[] args) throws Exception { + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( + "-Xbootclasspath/a:.", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-XX:+UseParallelGC", + "-XX:+UseAdaptiveSizePolicy", + "-Xms72m", + "-Xmx128m", + "-XX:NewSize=64m", + "-XX:MaxNewSize=64m", + // Bypass delayed shrinking and retain no extra committed old-gen space. + "-XX:MinHeapFreeRatio=0", + "-XX:MaxHeapFreeRatio=0", + "-XX:GCTimeRatio=1000000", + "-Xlog:gc+heap=debug", + DynamicBoundaryWorkload.class.getName()); + output.shouldHaveExitValue(0); + + String stdout = output.getStdout(); + + // 1. The boundary moved right while young gen remained non-empty. + List rightShift = states(stdout, "RIGHT_SHIFT"); + assertLT(rightShift.getFirst().boundary(), rightShift.getLast().boundary(), + "Full GC did not move the boundary right"); + assertGT(rightShift.getLast().youngReserved(), 0L, + "Right shift unexpectedly removed young gen"); + + // 2. Old commitment shrank without moving the boundary left. + List release = states(stdout, "RELEASE"); + assertBoundaryUnchanged(release, "Full GC moved the boundary after pressure disappeared"); + assertGT(release.getFirst().oldCommitted(), release.getLast().oldCommitted(), + "Old commitment did not decrease after pressure disappeared"); + + // 3. Adaptive young GC moved the boundary left for more room. + List youngGrowth = states(stdout, "YOUNG_GROWTH"); + assertGT(youngGrowth.getFirst().boundary(), youngGrowth.getLast().boundary(), + "Young GC did not move the boundary left"); + assertGT(youngGrowth.getLast().youngReserved(), 0L, + "Young gen is empty after young-GC growth"); + + // 4. An impossible allocation did not remove the young generation. + List impossibleAllocation = states(stdout, "IMPOSSIBLE_ALLOCATION"); + assertGT(impossibleAllocation.getLast().youngReserved(), 0L, + "Impossible allocation unexpectedly removed young gen"); + + // 5. Maximum feasible old pressure removed the young generation. + List oldOnly = states(stdout, "OLD_ONLY"); + assertEQ(oldOnly.getLast().youngReserved(), 0L, + "Maximum old pressure did not enter old-only mode"); + + // 6. Removing old pressure recreated the young generation. + List recreate = states(stdout, "RECREATE"); + assertEQ(recreate.getFirst().youngReserved(), 0L, + "Young gen was recreated before old pressure disappeared"); + assertGT(recreate.getLast().youngReserved(), 0L, + "Full GC did not recreate young gen"); + assertGT(recreate.getFirst().boundary(), recreate.getLast().boundary(), + "Young-gen recreation did not move the boundary left"); + + // 7. Further young GCs reached a stable, non-empty boundary. + List stable = states(stdout, "STABLE"); + assertStableTail(stable, 6, "Young GCs did not reach a stable boundary"); + assertGT(stable.getLast().youngReserved(), 0L, + "Young gen disappeared during stable young GCs"); + } + + private static List states(String output, String phase) { + String begin = "PHASE " + phase + " BEGIN"; + String end = "PHASE " + phase + " END"; + int beginIndex = output.indexOf(begin); + int endIndex = output.indexOf(end, beginIndex); + if (beginIndex < 0 || endIndex < 0) { + throw new RuntimeException("Missing " + phase + " markers:\n" + output); + } + + List states = new ArrayList<>(); + Matcher matcher = HEAP_STATE.matcher(output.substring(beginIndex, endIndex)); + while (matcher.find()) { + HeapState state = new HeapState(address(matcher.group(1)), + address(matcher.group(2)), + address(matcher.group(3)), + address(matcher.group(4)), + address(matcher.group(5)), + address(matcher.group(6))); + state.verify(); + states.add(state); + } + if (states.isEmpty()) { + throw new RuntimeException("No heap states in " + phase + " phase:\n" + output); + } + return states; + } + + private static long address(String value) { + return Long.parseUnsignedLong(value.substring(2), 16); + } + + private static void assertBoundaryUnchanged(List states, String message) { + long expected = states.getFirst().boundary(); + for (HeapState state : states) { + assertEQ(state.boundary(), expected, message); + } + } + + private static void assertStableTail(List states, int count, String message) { + if (states.size() < count) { + throw new RuntimeException("Not enough heap states to verify stability: " + states.size()); + } + List tail = states.subList(states.size() - count, states.size()); + long expected = tail.getFirst().boundary(); + for (HeapState state : tail) { + assertEQ(state.boundary(), expected, message); + assertGT(state.youngReserved(), 0L, "Young gen disappeared while stabilizing"); + } + } + + private record HeapState(long youngLow, long youngCommittedHigh, long youngHigh, + long oldLow, long oldCommittedHigh, long oldHigh) { + long boundary() { + return youngLow; + } + + long youngReserved() { + return youngHigh - youngLow; + } + + long oldCommitted() { + return oldCommittedHigh - oldLow; + } + + void verify() { + assertEQ(oldHigh, youngLow, "Generation reservations are not adjacent"); + if (youngLow > youngCommittedHigh || youngCommittedHigh > youngHigh) { + throw new RuntimeException("Invalid young-generation range: " + this); + } + if (oldLow > oldCommittedHigh || oldCommittedHigh > oldHigh) { + throw new RuntimeException("Invalid old-generation range: " + this); + } + } + } +} + +class DynamicBoundaryWorkload { + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final int MB = 1024 * 1024; + + private static byte[] oldPressure; + private static byte[] impossiblePressure; + private static List maximumOldPressure; + private static byte[] additionalPressure; + private static List youngPressure; + + public static void main(String[] args) throws Exception { + // 1. Move the boundary right while keeping young gen non-empty. + phaseBegin("RIGHT_SHIFT"); + // The first allocation fits the original 64m old reservation. The + // additional live data makes the explicit full GC borrow from young. + oldPressure = new byte[52 * MB]; + additionalPressure = new byte[20 * MB]; + WB.fullGC(); + phaseEnd("RIGHT_SHIFT"); + + // 2. Drop pressure; full GC should shrink old commitment without moving left. + phaseBegin("RELEASE"); + oldPressure = null; + additionalPressure = null; + WB.fullGC(); + phaseEnd("RELEASE"); + + // 3. Let adaptive young GC move the boundary left when it needs more room. + phaseBegin("YOUNG_GROWTH"); + // Immediate collection makes the adaptive policy request a larger + // young generation than the reduced reservation can satisfy. + youngPressure = new ArrayList<>(); + for (int i = 0; i < 8; i++) { + youngPressure.add(new byte[MB]); + } + WB.youngGC(); + phaseEnd("YOUNG_GROWTH"); + + // 4. An impossible pending allocation should fail without consuming + // the entire young reservation. + phaseBegin("IMPOSSIBLE_ALLOCATION"); + boolean impossibleAllocationSucceeded = false; + try { + impossiblePressure = new byte[120 * MB]; + impossibleAllocationSucceeded = true; + } catch (OutOfMemoryError expected) { + } finally { + impossiblePressure = null; + } + if (impossibleAllocationSucceeded) { + throw new RuntimeException("Impossible allocation unexpectedly succeeded"); + } + phaseEnd("IMPOSSIBLE_ALLOCATION"); + + // 5. Retain feasible allocations until live data forces old-only mode. + phaseBegin("OLD_ONLY"); + maximumOldPressure = new ArrayList<>(128); + try { + while (true) { + maximumOldPressure.add(new byte[MB]); + } + } catch (OutOfMemoryError expected) { + } + phaseEnd("OLD_ONLY"); + + // 6. Remove pressure; full GC should recreate young gen. + phaseBegin("RECREATE"); + oldPressure = null; + maximumOldPressure = null; + youngPressure = null; + WB.fullGC(); + phaseEnd("RECREATE"); + + WB.setUintVMFlag("GCTimeRatio", 0); + if (WB.getUintVMFlag("GCTimeRatio") != 0) { + throw new RuntimeException("Could not disable throughput-driven young growth"); + } + // 7. Further young GCs should converge to a stable, non-empty boundary. + phaseBegin("STABLE"); + for (int i = 0; i < 16; i++) { + // Avoid asking for throughput-driven growth in an empty young gen. + Thread.sleep(200); + WB.youngGC(); + } + phaseEnd("STABLE"); + } + + private static void phaseBegin(String phase) { + System.out.println("PHASE " + phase + " BEGIN"); + } + + private static void phaseEnd(String phase) { + System.out.println("PHASE " + phase + " END"); + } +} diff --git a/test/hotspot/jtreg/gc/parallel/TestGenBoundaryWithFixedSizing.java b/test/hotspot/jtreg/gc/parallel/TestGenBoundaryWithFixedSizing.java new file mode 100644 index 000000000000..0b19617931da --- /dev/null +++ b/test/hotspot/jtreg/gc/parallel/TestGenBoundaryWithFixedSizing.java @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2026, 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 gc.parallel; + +/* + * @test TestGenBoundaryWithFixedSizing + * @bug 8386885 + * @summary Verify that fixed young sizing preserves and recovers its maximum reservation + * @requires vm.gc.Parallel + * @requires vm.flagless + * @library /test/lib + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run driver gc.parallel.TestGenBoundaryWithFixedSizing + */ + +import java.lang.ref.Reference; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryPoolMXBean; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.whitebox.WhiteBox; + +public class TestGenBoundaryWithFixedSizing { + private static final Pattern YOUNG_GEN = Pattern.compile( + "Young Gen: \\[(0x[0-9a-f]+), (0x[0-9a-f]+), (0x[0-9a-f]+)\\)"); + + public static void main(String[] args) throws Exception { + // The 128m heap and 64m maximum young reservation leave 64m for old gen + // before it must borrow reservation from young gen. + OutputAnalyzer output = ProcessTools.executeLimitedTestJava( + "-Xbootclasspath/a:.", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-XX:+UseParallelGC", + "-XX:-UseAdaptiveSizePolicy", + "-Xms64m", + "-Xmx128m", + "-XX:NewSize=" + GenBoundaryWithFixedSizingWorkload.NEW_SIZE, + "-XX:MaxNewSize=" + GenBoundaryWithFixedSizingWorkload.MAX_NEW_SIZE, + "-XX:MarkSweepDeadRatio=100", + "-Xlog:gc+heap=debug", + GenBoundaryWithFixedSizingWorkload.class.getName()); + output.shouldHaveExitValue(0); + + String stdout = output.getStdout(); + + // 1. A low live set gives old gen no reason to borrow from young. + assertReservation(stdout, "LOW_LIVE", GenBoundaryWithFixedSizingWorkload.MAX_NEW_SIZE); + + // 2. Speculative promotion headroom must not consume young reservation. + assertReservation(stdout, "PROMOTION_HEADROOM", GenBoundaryWithFixedSizingWorkload.MAX_NEW_SIZE); + + // 3. Optional retained dead space must not consume young reservation. + assertReservation(stdout, "RETAINED_DEAD", GenBoundaryWithFixedSizingWorkload.MAX_NEW_SIZE); + + // 4. Genuine old pressure must borrow some, but not all, young reservation. + List borrowed = reservations(stdout, "BORROW"); + if (borrowed.getLast() <= 0 + || borrowed.getLast() >= GenBoundaryWithFixedSizingWorkload.MAX_NEW_SIZE) { + throw new RuntimeException("Old pressure did not partially borrow young reservation:\n" + + output.getOutput()); + } + + // 5. Removing old pressure must restore the full reservation. + List recovery = reservations(stdout, "RECOVER"); + if (recovery.getFirst() >= GenBoundaryWithFixedSizingWorkload.MAX_NEW_SIZE + || recovery.getLast() != GenBoundaryWithFixedSizingWorkload.MAX_NEW_SIZE) { + throw new RuntimeException("Young reservation did not recover to MaxNewSize:\n" + output.getOutput()); + } + + // 6. Another full GC without renewed pressure must leave the boundary stable. + assertReservation(stdout, "STABLE", GenBoundaryWithFixedSizingWorkload.MAX_NEW_SIZE); + } + + private static void assertReservation(String output, String phase, long expected) { + List reservations = reservations(output, phase); + if (reservations.getLast() != expected) { + throw new RuntimeException("Unexpected young reservation in " + phase + ": " + + reservations.getLast() + " != " + expected + "\n" + output); + } + } + + // GC heap logs describe young gen as [reserved-low, committed-high, reserved-high): + // PSYoungGen ... Young Gen: [0x00000007fc000000, 0x00000007ff000000, 0x0000000800000000) + // Subtracting the first address from the third gives the reservation size. + // The first and last entries within a phase are the pre- and post-GC states. + private static List reservations(String output, String phase) { + String begin = "PHASE " + phase + " BEGIN"; + String end = "PHASE " + phase + " END"; + int beginIndex = output.indexOf(begin); + int endIndex = output.indexOf(end, beginIndex); + if (beginIndex < 0 || endIndex < 0) { + throw new RuntimeException("Missing " + phase + " markers:\n" + output); + } + + List reservations = new ArrayList<>(); + Matcher matcher = YOUNG_GEN.matcher(output.substring(beginIndex, endIndex)); + while (matcher.find()) { + long low = Long.parseUnsignedLong(matcher.group(1).substring(2), 16); + long high = Long.parseUnsignedLong(matcher.group(3).substring(2), 16); + reservations.add(high - low); + } + if (reservations.isEmpty()) { + throw new RuntimeException("No young-generation states in " + phase + ":\n" + output); + } + return reservations; + } +} + +/** + * Exercises dynamic generation-boundary changes with adaptive sizing disabled. + * The child VM has a 128m maximum heap, a 48m initial young commitment, a 64m + * maximum young reservation, and aggressive dead-space retention. + * + * The scenario: + * 1. Run a low-live full GC without moving the generation boundary. + * 2. Build a live set below the old-generation partition and verify that + * promotion headroom does not consume the young reservation. + * 3. Replace part of the live set and verify that retained dead space does not + * consume the young reservation. + * 4. Increase the live set until old gen must borrow from young. + * 5. Remove that pressure and verify that the young reservation recovers. + * 6. Run another full GC and verify that the recovered boundary remains stable. + * + * The driver reads phase-delimited heap logs to verify reservation changes, + * while MXBeans verify non-adaptive commitment behavior. + */ +class GenBoundaryWithFixedSizingWorkload { + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final int MB = 1024 * 1024; + private static final int TARGET_PRESERVING_OBJECTS = 56; + private static final int REPLACED_OBJECTS = 24; + private static final int PRESSURE_OBJECTS = 88; + private static final int RETAINED_OBJECTS = 8; + static final long NEW_SIZE = 48L * MB; + static final long MAX_NEW_SIZE = 64L * MB; + + public static void main(String[] args) { + // 1. A low-live full GC while young gen still owns its full MaxNewSize + // reservation exercises the zero-shift boundary path. + phaseBegin("LOW_LIVE"); + WB.fullGC(); + phaseEnd("LOW_LIVE"); + + List live = new ArrayList<>(); + // 2. Speculative promotion headroom must not consume the maximum reservation. + for (int i = 0; i < TARGET_PRESERVING_OBJECTS; i++) { + live.add(new byte[MB]); + } + phaseBegin("PROMOTION_HEADROOM"); + WB.fullGC(); + phaseEnd("PROMOTION_HEADROOM"); + assertYoungCommitted(); + + // 3. Retained dead space must not consume the maximum reservation either. + live.subList(0, REPLACED_OBJECTS).clear(); + for (int i = 0; i < REPLACED_OBJECTS; i++) { + live.add(new byte[MB]); + } + phaseBegin("RETAINED_DEAD"); + WB.fullGC(); + phaseEnd("RETAINED_DEAD"); + assertYoungCommitted(); + + // 4. Actual old-gen pressure may borrow from the maximum reservation. + for (int i = TARGET_PRESERVING_OBJECTS; i < PRESSURE_OBJECTS; i++) { + live.add(new byte[MB]); + } + phaseBegin("BORROW"); + WB.fullGC(); + phaseEnd("BORROW"); + long heapCommittedBeforeRecovery = heapCommitted(); + + // 5. Drop old-gen pressure. Full GC should restore the maximum reservation. + live.subList(RETAINED_OBJECTS, live.size()).clear(); + phaseBegin("RECOVER"); + WB.fullGC(); + phaseEnd("RECOVER"); + assertYoungCommitted(); + assertHeapCommittedAtLeast(heapCommittedBeforeRecovery); + + // 6. Recovery must remain stable across another full GC. + phaseBegin("STABLE"); + WB.fullGC(); + phaseEnd("STABLE"); + assertYoungCommitted(); + assertHeapCommittedAtLeast(heapCommittedBeforeRecovery); + Reference.reachabilityFence(live); + } + + // Delimit explicit full GCs so the driver can associate heap logs with each scenario. + private static void phaseBegin(String phase) { + System.out.println("PHASE " + phase + " BEGIN"); + } + + private static void phaseEnd(String phase) { + System.out.println("PHASE " + phase + " END"); + } + + private static long heapCommitted() { + return oldCommitted() + youngCommitted(); + } + + private static void assertHeapCommittedAtLeast(long expected) { + long actual = heapCommitted(); + if (actual < expected) { + throw new RuntimeException("Heap commitment shrank with adaptive sizing disabled: " + + actual + " < " + expected); + } + } + + private static void assertYoungCommitted() { + long youngCommitted = youngCommitted(); + if (youngCommitted < NEW_SIZE) { + throw new RuntimeException("Young generation commitment did not recover: " + + youngCommitted + " < " + NEW_SIZE); + } + } + + private static long youngCommitted() { + long edenCommitted = -1; + long survivorCommitted = -1; + for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) { + if (pool.getName().contains("Eden")) { + edenCommitted = pool.getUsage().getCommitted(); + } else if (pool.getName().contains("Survivor")) { + survivorCommitted = pool.getUsage().getCommitted(); + } + } + if (edenCommitted < 0 || survivorCommitted < 0) { + throw new RuntimeException("Parallel young-generation memory pools not found"); + } + // The MXBean exposes one survivor pool, but both from and to spaces are committed. + return edenCommitted + 2 * survivorCommitted; + } + + private static long oldCommitted() { + for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) { + if (pool.getName().contains("Old")) { + return pool.getUsage().getCommitted(); + } + } + throw new RuntimeException("Parallel old-generation memory pool not found"); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/AOTMapReader.java b/test/hotspot/jtreg/runtime/cds/AOTMapReader.java index b1557f29dc84..3bb3197296f8 100644 --- a/test/hotspot/jtreg/runtime/cds/AOTMapReader.java +++ b/test/hotspot/jtreg/runtime/cds/AOTMapReader.java @@ -195,14 +195,14 @@ public static class Field { // - final 'key' 'Ljava/lang/Object;' @16 0x00000007ffc68260 (0xfff8d04c) java.lang.String static Pattern oopFieldPattern2 = Pattern.compile(" - [^']* '([^']+)'.*@([0-9]+) 0x([0-9a-f]+) [(]0x([0-9a-f]+)[)] (.*)"); - // - Flat inline type element 'java/lang/Integer': - Index 1 offset 24: + // - Flat value type element 'java/lang/Integer': - Index 1 offset 24: // or - // - Flat inline type field 'java/lang/Integer': - static Pattern flatFieldPattern = Pattern.compile(" - Flat inline type field '([^']+)':\\s*(null)?\\s*$"); - static Pattern flatElementPattern = Pattern.compile(" - Flat inline type element '([^']+)':\\s*- Index\\s+(\\d+)\\s+offset\\s+(\\d+):\\s*(null)?\\s*$"); + // - Flat value type field 'java/lang/Integer': + static Pattern flatFieldPattern = Pattern.compile(" - Flat value type field '([^']+)':\\s*(null)?\\s*$"); + static Pattern flatElementPattern = Pattern.compile(" - Flat value type element '([^']+)':\\s*- Index\\s+(\\d+)\\s+offset\\s+(\\d+):\\s*(null)?\\s*$"); - static Pattern flatNullFreeFieldPattern = Pattern.compile(" - Flat inline null-free type field '([^']+)':\\s*$"); - static Pattern flatNullFreeElementPattern = Pattern.compile(" - Flat inline null-free type element '([^']+)':\\s*- Index\\s+(\\d+)\\s+offset\\s+(\\d+):\\s*$"); + static Pattern flatNullFreeFieldPattern = Pattern.compile(" - Flat value null-free type field '([^']+)':\\s*$"); + static Pattern flatNullFreeElementPattern = Pattern.compile(" - Flat value null-free type element '([^']+)':\\s*- Index\\s+(\\d+)\\s+offset\\s+(\\d+):\\s*$"); static Pattern nullMarkerPattern = Pattern.compile(" - \\[null_marker\\] @[0-9]+ Field marked as (.*)"); diff --git a/test/hotspot/jtreg/runtime/cds/TestDefaultArchiveLoading.java b/test/hotspot/jtreg/runtime/cds/TestDefaultArchiveLoading.java index 479a50dcd3c9..5788f302391c 100644 --- a/test/hotspot/jtreg/runtime/cds/TestDefaultArchiveLoading.java +++ b/test/hotspot/jtreg/runtime/cds/TestDefaultArchiveLoading.java @@ -82,6 +82,7 @@ import jdk.test.lib.Platform; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.Utils; import jtreg.SkippedException; @@ -112,9 +113,11 @@ public static void main(String[] args) throws Exception { String archiveSuffix; char coh, coops; - String preview = System.getProperty("test.java.opts", ""); - if (preview.contains("--enable-preview")) { - archivePreviewSuffix = "_preview"; + for (String opt : Utils.getTestJavaOpts()) { + if (opt.contains("--enable-preview")) { + archivePreviewSuffix = "_preview"; + break; + } } switch (args[0]) { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/HelloInlineClassTest.java b/test/hotspot/jtreg/runtime/cds/appcds/HelloValueClassTest.java similarity index 81% rename from test/hotspot/jtreg/runtime/cds/appcds/HelloInlineClassTest.java rename to test/hotspot/jtreg/runtime/cds/appcds/HelloValueClassTest.java index a1215023482a..0e3b1582e90b 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/HelloInlineClassTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/HelloValueClassTest.java @@ -24,29 +24,29 @@ /* * @test - * @summary Hello World test for using inline classes with CDS + * @summary Hello World test for using value classes with CDS * @requires vm.cds * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds/test-classes * @enablePreview * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation - * @compile test-classes/HelloInlineClassApp.java + * @compile test-classes/HelloValueClassApp.java * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar hello_inline.jar - * HelloInlineClassApp HelloInlineClassApp$Point - * HelloInlineClassApp$Rectangle HelloInlineClassApp$ValueRecord - * @run main/othervm HelloInlineClassTest + * HelloValueClassApp HelloValueClassApp$Point + * HelloValueClassApp$Rectangle HelloValueClassApp$ValueRecord + * @run main/othervm HelloValueClassTest */ import jdk.test.lib.helpers.ClassFileInstaller; import jdk.test.lib.process.OutputAnalyzer; -public class HelloInlineClassTest { +public class HelloValueClassTest { public static void main(String[] args) throws Exception { String appJar = ClassFileInstaller.getJarPath("hello_inline.jar"); - String mainClass = "HelloInlineClassApp"; + String mainClass = "HelloValueClassApp"; OutputAnalyzer output = TestCommon.dump(appJar, TestCommon.list(mainClass, - "HelloInlineClassApp$Point", - "HelloInlineClassApp$Rectangle"), + "HelloValueClassApp$Point", + "HelloValueClassApp$Rectangle"), "--enable-preview"); output.shouldHaveExitValue(0); @@ -58,7 +58,7 @@ public static void main(String[] args) throws Exception { "-cp", appJar, mainClass) .assertNormalExit(); - String compFlag = "-XX:CompileCommand=compileonly,HelloInlineClassApp*::*"; + String compFlag = "-XX:CompileCommand=compileonly,HelloValueClassApp*::*"; TestCommon.run("--enable-preview", "-Xcomp", compFlag, diff --git a/test/hotspot/jtreg/runtime/cds/appcds/InlineFieldExclusionTest.java b/test/hotspot/jtreg/runtime/cds/appcds/ValueFieldExclusionTest.java similarity index 88% rename from test/hotspot/jtreg/runtime/cds/appcds/InlineFieldExclusionTest.java rename to test/hotspot/jtreg/runtime/cds/appcds/ValueFieldExclusionTest.java index 3de7baf84ab9..763a39150fa2 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/InlineFieldExclusionTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/ValueFieldExclusionTest.java @@ -30,10 +30,10 @@ * @library /test/lib * @modules java.base/jdk.internal.vm.annotation * @enablePreview - * @compile test-classes/InlineFieldExclusionApp.java test-classes/excluded/ExcludedValueClass.java - * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar InlineFieldExclusionApp + * @compile test-classes/ValueFieldExclusionApp.java test-classes/excluded/ExcludedValueClass.java + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar ValueFieldExclusionApp * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar excluded.jar excluded/ExcludedValueClass - * @run main/othervm InlineFieldExclusionTest InlineFieldExclusionApp + * @run main/othervm ValueFieldExclusionTest ValueFieldExclusionApp */ /* @test id=static @@ -46,14 +46,14 @@ * @compile test-classes/StaticNullRestrictedExclusionApp.java test-classes/excluded/ExcludedValueClass.java * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar StaticNullRestrictedExclusionApp * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar excluded.jar excluded/ExcludedValueClass - * @run main/othervm InlineFieldExclusionTest StaticNullRestrictedExclusionApp + * @run main/othervm ValueFieldExclusionTest StaticNullRestrictedExclusionApp */ import jdk.test.lib.helpers.ClassFileInstaller; import jdk.test.lib.process.OutputAnalyzer; import java.io.File; -public class InlineFieldExclusionTest { +public class ValueFieldExclusionTest { public static void main(String[] args) throws Exception { if (args.length < 1) { throw new RuntimeException("Missing main class name"); @@ -77,13 +77,13 @@ public static void main(String[] args) throws Exception { String loadFromJar = ".class,load\s*. " + mainClass + " source: file:.*app.jar"; // ExcludedValueClass should be excluded from the archive because it is found inside - // a signed JAR. InlineFieldExclusionApp has a flat field of type ExcludedValueClass and + // a signed JAR. ValueFieldExclusionApp has a flat field of type ExcludedValueClass and // relies on this class to calculate the layout of the field, so it too must be excluded // from the archive. output = TestCommon.dump(classpath, TestCommon.list(mainClass, "excluded/ExcludedValueClass"), suffix); TestCommon.checkDump(output, skipMsg1, skipMsg2); - // At runtime, both InlineFieldExclusionApp and ExcludedValueClass should be loaded from + // At runtime, both ValueFieldExclusionApp and ExcludedValueClass should be loaded from // the jar file instead of from the shared archive. output = TestCommon.exec(classpath, TestCommon.concat(suffix, mainClass)); try { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DynamicArchiveRelocationTest.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DynamicArchiveRelocationTest.java index 26abad36bb7d..6d257be13b1d 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DynamicArchiveRelocationTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/DynamicArchiveRelocationTest.java @@ -33,9 +33,9 @@ * @enablePreview * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation - * @compile ../test-classes/HelloInlineClassApp.java ../test-classes/HelloRelocation.java + * @compile ../test-classes/HelloValueClassApp.java ../test-classes/HelloRelocation.java * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar hello.jar HelloRelocation HelloInlineClassApp HelloInlineClassApp$Point HelloInlineClassApp$Rectangle HelloInlineClassApp$ValueRecord + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar hello.jar HelloRelocation HelloValueClassApp HelloValueClassApp$Point HelloValueClassApp$Rectangle HelloValueClassApp$ValueRecord * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. DynamicArchiveRelocationTest */ diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/HelloDynamicInlineClass.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/HelloDynamicValueClass.java similarity index 83% rename from test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/HelloDynamicInlineClass.java rename to test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/HelloDynamicValueClass.java index 59835b5ba6e8..214c0bfbf0c9 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/HelloDynamicInlineClass.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/HelloDynamicValueClass.java @@ -30,18 +30,18 @@ * @enablePreview * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation - * @compile ../test-classes/HelloInlineClassApp.java + * @compile ../test-classes/HelloValueClassApp.java * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar hello_inline.jar HelloInlineClassApp HelloInlineClassApp$Point HelloInlineClassApp$Rectangle HelloInlineClassApp$ValueRecord + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar hello_value.jar HelloValueClassApp HelloValueClassApp$Point HelloValueClassApp$Rectangle HelloValueClassApp$ValueRecord * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. HelloDynamicInlineClass + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. HelloDynamicValueClass */ import jdk.test.lib.helpers.ClassFileInstaller; -public class HelloDynamicInlineClass extends DynamicArchiveTestBase { +public class HelloDynamicValueClass extends DynamicArchiveTestBase { public static void main(String[] args) throws Exception { - runTest(HelloDynamicInlineClass::test); + runTest(HelloDynamicValueClass::test); } static void test() throws Exception { @@ -52,8 +52,8 @@ static void test() throws Exception { } private static void doTest(String baseArchiveName, String topArchiveName) throws Exception { - String appJar = ClassFileInstaller.getJarPath("hello_inline.jar"); - String mainClass = "HelloInlineClassApp"; + String appJar = ClassFileInstaller.getJarPath("hello_value.jar"); + String mainClass = "HelloValueClassApp"; dump2(baseArchiveName, topArchiveName, "--enable-preview", "-Xlog:cds", @@ -68,7 +68,7 @@ private static void doTest(String baseArchiveName, String topArchiveName) throws "-Xlog:cds+dynamic=debug,cds=debug", "-cp", appJar, mainClass) .assertNormalExit(output -> { - output.shouldContain("HelloInlineClassApp$Point source: shared objects file") + output.shouldContain("HelloValueClassApp$Point source: shared objects file") .shouldHaveExitValue(0); }); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/NullableFlatFieldDynamicTest.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/NullableFlatFieldDynamicTest.java index 5c8587a48bd1..bd048affb9c9 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/NullableFlatFieldDynamicTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/NullableFlatFieldDynamicTest.java @@ -66,7 +66,7 @@ private static void doTest(String baseArchiveName, String topArchiveName) throws "--enable-preview", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UseNullableAtomicValueFlattening", - "-XX:+PrintInlineLayout", + "-XX:+PrintValueLayout", "-Xlog:cds", "-Xlog:cds+dynamic=debug", "-cp", appJar, mainClass) @@ -77,7 +77,7 @@ private static void doTest(String baseArchiveName, String topArchiveName) throws "--enable-preview", "-XX:+UnlockDiagnosticVMOptions", "-XX:+UseNullableAtomicValueFlattening", - "-XX:+PrintInlineLayout", + "-XX:+PrintValueLayout", "-Xlog:class+load", "-Xlog:cds+dynamic=debug,cds=debug", "-cp", appJar, mainClass) diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/addmods/AddmodsOption.java b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/addmods/AddmodsOption.java index 959b507d03b5..183821b89994 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/addmods/AddmodsOption.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/addmods/AddmodsOption.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8319343 + * @bug 8319343 8381976 * @summary Test handling of the --add-modules option. * @requires vm.cds.write.archived.java.heap * @requires vm.flagless @@ -40,14 +40,15 @@ public class AddmodsOption { public static void main(String[] args) throws Exception { final String moduleOption = "jdk.httpserver/sun.net.httpserver.simpleserver.Main"; - final String incubatorModule = "jdk.incubator.vector"; + final String incubatorModules = "jdk.incubator.vector,jdk.incubator.json"; final String jconsoleModule = "jdk.jconsole"; final String multiModules = ",,jdk.jconsole,jdk.compiler,,"; final String allSystem = "ALL-SYSTEM"; final String allModulePath = "ALL-MODULE-PATH"; final String loggingOption = "-Xlog:aot=debug,aot+module=debug,aot+heap=info,cds=debug,module=trace"; final String versionPattern = "java.[0-9][0-9].*"; - final String warningIncubator = "WARNING: Using incubator modules: jdk.incubator.vector"; + final String incubatorPattern = "jdk\\.incubator\\.(vector|json),\\s*jdk\\.incubator\\.(?!\\1)(vector|json)"; + final String warningIncubatorPattern = "^WARNING: Using incubator modules: " + incubatorPattern + ".*"; String archiveName = TestCommon.getNewArchiveName("addmods-option"); TestCommon.setCurrentArchiveName(archiveName); @@ -75,12 +76,12 @@ public static void main(String[] args) throws Exception { // different --add-modules specified during runtime oa = TestCommon.execCommon( loggingOption, - "--add-modules", incubatorModule, + "--add-modules", incubatorModules, "-m", moduleOption, "-version"); oa.shouldHaveExitValue(0) .shouldContain("Mismatched values for property jdk.module.addmods") - .shouldContain("runtime jdk.incubator.vector dump time jdk.jconsole"); + .shouldMatch("runtime " + incubatorPattern + " dump time jdk\\.jconsole"); // no module specified during runtime oa = TestCommon.execCommon( @@ -110,29 +111,31 @@ public static void main(String[] args) throws Exception { // version of the jdk.httpserver module, e.g. java 22-ea .shouldMatch(versionPattern); - // dump an archive with an incubator module, -add-modules jdk.incubator.vector + // dump an archive with incubator modules, + // --add-modules jdk.incubator.vector,jdk.incubator.json archiveName = TestCommon.getNewArchiveName("incubator-module"); TestCommon.setCurrentArchiveName(archiveName); oa = TestCommon.dumpBaseArchive( archiveName, loggingOption, - "--add-modules", incubatorModule, + "--add-modules", incubatorModules, "-m", moduleOption, "-version"); oa.shouldHaveExitValue(0) // module graph won't be archived with an incubator module .shouldContain("archivedBootLayer not available, disabling full module graph"); - // run with the same incubator module + // run with the same incubator modules oa = TestCommon.execCommon( loggingOption, - "--add-modules", incubatorModule, + "--add-modules", incubatorModules, "-m", moduleOption, "-version"); oa.shouldContain("full module graph: disabled") - // module is not restored from archive + // modules are not restored from archive .shouldContain("define_module(): creation of module: jdk.incubator.vector") - .shouldContain("WARNING: Using incubator modules: jdk.incubator.vector") + .shouldContain("define_module(): creation of module: jdk.incubator.json") + .shouldMatch(warningIncubatorPattern) .shouldHaveExitValue(0); // dump an archive with multiple modules in -add-modules @@ -146,7 +149,7 @@ public static void main(String[] args) throws Exception { "-version"); oa.shouldHaveExitValue(0); - // run with the same multiple modules with a duplicate module in --add-modules + // run with the same multiple modules with a duplicate module in ---add-modules oa = TestCommon.execCommon( loggingOption, "--add-modules", multiModules, @@ -157,7 +160,7 @@ public static void main(String[] args) throws Exception { .shouldMatch("aot,module.*Restored from archive: entry.0x.*name jdk.compiler") .shouldMatch("aot,module.*Restored from archive: entry.0x.*name jdk.jconsole"); - // dump an archive with ALL-SYSTEM in -add-modules + // dump an archive with ALL-SYSTEM in --add-modules archiveName = TestCommon.getNewArchiveName("muti-modules"); TestCommon.setCurrentArchiveName(archiveName); oa = TestCommon.dumpBaseArchive( @@ -167,7 +170,7 @@ public static void main(String[] args) throws Exception { "-m", moduleOption, "-version"); oa.shouldHaveExitValue(0) - .shouldContain(warningIncubator); + .shouldMatch(warningIncubatorPattern); // run with the same ALL-SYSTEM in --add-modules oa = TestCommon.execCommon( @@ -176,11 +179,11 @@ public static void main(String[] args) throws Exception { "-m", moduleOption, "-version"); oa.shouldHaveExitValue(0) - // the jdk.incubator.vector was specified indirectly via ALL-SYSTEM - .shouldContain(warningIncubator) + // the jdk.incubator.vector and jdk.incubator.json were specified indirectly via ALL-SYSTEM + .shouldMatch(warningIncubatorPattern) .shouldContain("full module graph cannot be loaded: archive was created without full module graph"); - // dump an archive with ALL-MODULE-PATH in -add-modules + // dump an archive with ALL-MODULE-PATH in --add-modules archiveName = TestCommon.getNewArchiveName("muti-modules"); TestCommon.setCurrentArchiveName(archiveName); oa = TestCommon.dumpBaseArchive( diff --git a/test/hotspot/jtreg/runtime/cds/appcds/test-classes/HelloRelocation.java b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/HelloRelocation.java index d9d679e0e1d9..4f558d45ff8b 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/test-classes/HelloRelocation.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/HelloRelocation.java @@ -25,6 +25,6 @@ public class HelloRelocation { public static void main(String args[]) throws Exception { System.out.println("Hello World"); - HelloInlineClassApp.main(args); + HelloValueClassApp.main(args); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/test-classes/HelloInlineClassApp.java b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/HelloValueClassApp.java similarity index 94% rename from test/hotspot/jtreg/runtime/cds/appcds/test-classes/HelloInlineClassApp.java rename to test/hotspot/jtreg/runtime/cds/appcds/test-classes/HelloValueClassApp.java index c694f419e050..3905170f64af 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/test-classes/HelloInlineClassApp.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/HelloValueClassApp.java @@ -25,9 +25,9 @@ import jdk.internal.vm.annotation.LooselyConsistentValue; import jdk.internal.vm.annotation.NullRestricted; -public class HelloInlineClassApp { +public class HelloValueClassApp { - public HelloInlineClassApp() { + public HelloValueClassApp() { point = new Point(0, 0); super(); } @@ -113,11 +113,11 @@ public static void main(String[] args) throws Exception { Point pzero = new Point(0,0); Point pone = new Point(1, 1); - if (HelloInlineClassApp.rectangle.p0 != pzero || HelloInlineClassApp.rectangle.p1 != pone) { + if (HelloValueClassApp.rectangle.p0 != pzero || HelloValueClassApp.rectangle.p1 != pone) { throw new RuntimeException("Static field rectangle not as expected"); } - HelloInlineClassApp app = new HelloInlineClassApp(); + HelloValueClassApp app = new HelloValueClassApp(); if (app.point != pzero) { throw new RuntimeException("Non-static field point not as expected"); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/test-classes/InlineFieldExclusionApp.java b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/ValueFieldExclusionApp.java similarity index 87% rename from test/hotspot/jtreg/runtime/cds/appcds/test-classes/InlineFieldExclusionApp.java rename to test/hotspot/jtreg/runtime/cds/appcds/test-classes/ValueFieldExclusionApp.java index 4a112b3cf973..f341cfaff41a 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/test-classes/InlineFieldExclusionApp.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/ValueFieldExclusionApp.java @@ -24,20 +24,20 @@ import excluded.ExcludedValueClass; -public class InlineFieldExclusionApp { +public class ValueFieldExclusionApp { ExcludedValueClass v; - InlineFieldExclusionApp() { + ValueFieldExclusionApp() { v = new ExcludedValueClass(); } public static void main(String args[]) { - InlineFieldExclusionApp h = new InlineFieldExclusionApp(); + ValueFieldExclusionApp h = new ValueFieldExclusionApp(); ExcludedValueClass test = new ExcludedValueClass(); if (h.v != test) { throw new RuntimeException("Should be flattened"); } - System.out.println("Hello from InlineFieldExclusionApp!"); + System.out.println("Hello from ValueFieldExclusionApp!"); } } diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/AbstractValueClassTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/AbstractValueClassTest.java similarity index 94% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/AbstractValueClassTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/AbstractValueClassTest.java index 100c95b4ada7..cb7baabfed65 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/AbstractValueClassTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/AbstractValueClassTest.java @@ -26,10 +26,10 @@ * @bug 8293134 * @summary Test that a super abstract value class is allowed. * @enablePreview - * @run main runtime.valhalla.inlinetypes.AbstractValueClassTest + * @run main runtime.valhalla.valuetypes.AbstractValueClassTest */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; public class AbstractValueClassTest { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/AcmpTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/AcmpTest.java similarity index 98% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/AcmpTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/AcmpTest.java index b04498f87c68..5e9a50e49923 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/AcmpTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/AcmpTest.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import java.util.ArrayList; import jdk.internal.vm.annotation.LooselyConsistentValue; @@ -33,7 +33,7 @@ * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @enablePreview - * @run main/othervm runtime.valhalla.inlinetypes.AcmpTest + * @run main/othervm runtime.valhalla.valuetypes.AcmpTest */ public class AcmpTest { static record TestCase(Object a, Object b, boolean equal) {} diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/AnnotationsTests.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/AnnotationsTests.java similarity index 98% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/AnnotationsTests.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/AnnotationsTests.java index 1f2b9eb034a0..ad5933d4911e 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/AnnotationsTests.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/AnnotationsTests.java @@ -21,7 +21,7 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.test.lib.Asserts; import java.lang.management.ManagementFactory; @@ -43,7 +43,7 @@ * @enablePreview * @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 runtime.valhalla.inlinetypes.AnnotationsTests + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI runtime.valhalla.valuetypes.AnnotationsTests */ public class AnnotationsTests { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ArrayCopyStoreNull.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ArrayCopyStoreNull.java similarity index 95% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/ArrayCopyStoreNull.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/ArrayCopyStoreNull.java index 6c8719ba6edd..758fc72e42e7 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ArrayCopyStoreNull.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ArrayCopyStoreNull.java @@ -21,7 +21,7 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.value.ValueClass; @@ -34,7 +34,7 @@ * @enablePreview * @run main/othervm -XX:+UnlockExperimentalVMOptions * -XX:-UseNullFreeAtomicValueFlattening -XX:-UseNullFreeNonAtomicValueFlattening - * runtime.valhalla.inlinetypes.ArrayCopyStoreNull + * runtime.valhalla.valuetypes.ArrayCopyStoreNull */ public class ArrayCopyStoreNull { value record MyRecord(int f) {} diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ArrayQueryTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ArrayQueryTest.java similarity index 98% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/ArrayQueryTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/ArrayQueryTest.java index 30773d572a2a..1fc908b34575 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ArrayQueryTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ArrayQueryTest.java @@ -31,10 +31,10 @@ * @enablePreview * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseArrayFlattening -XX:+UseFieldFlattening * -XX:+UseNullFreeNonAtomicValueFlattening -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening - * runtime.valhalla.inlinetypes.ArrayQueryTest + * runtime.valhalla.valuetypes.ArrayQueryTest */ - package runtime.valhalla.inlinetypes; + package runtime.valhalla.valuetypes; import jdk.internal.value.ValueClass; import jdk.internal.vm.annotation.LooselyConsistentValue; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ClassInitializationFailuresTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ClassInitializationFailuresTest.java similarity index 98% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/ClassInitializationFailuresTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/ClassInitializationFailuresTest.java index 35ae940fe2da..459a81ef1682 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ClassInitializationFailuresTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ClassInitializationFailuresTest.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.value.ValueClass; import jdk.test.lib.Asserts; @@ -35,7 +35,7 @@ * java.base/jdk.internal.value * @enablePreview * @compile ClassInitializationFailuresTest.java - * @run main runtime.valhalla.inlinetypes.ClassInitializationFailuresTest + * @run main runtime.valhalla.valuetypes.ClassInitializationFailuresTest */ public class ClassInitializationFailuresTest { static boolean failingInitialization = true; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ClassPrintLayoutDcmd.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ClassPrintLayoutDcmd.java similarity index 93% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/ClassPrintLayoutDcmd.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/ClassPrintLayoutDcmd.java index e792fea3422f..de98c7ca1141 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ClassPrintLayoutDcmd.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ClassPrintLayoutDcmd.java @@ -22,7 +22,7 @@ * questions. * */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; @@ -38,7 +38,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile ClassPrintLayoutDcmd.java - * @run main runtime.valhalla.inlinetypes.ClassPrintLayoutDcmd + * @run main runtime.valhalla.valuetypes.ClassPrintLayoutDcmd */ public value class ClassPrintLayoutDcmd { @@ -85,6 +85,6 @@ public static void main(String args[]) throws Exception { testCmd("", 1, "IllegalArgumentException", "mandatory"); testCmd("java.lang.Object", 0, "java.lang.Object", "@bootstrap"); testCmd("java.lang.Class", 0, "java.lang.Class", "@bootstrap"); - testCmd("runtime.valhalla.inlinetypes.ClassPrintLayoutDcmd$Line", 0, "@app", "p1", "p2"); + testCmd("runtime.valhalla.valuetypes.ClassPrintLayoutDcmd$Line", 0, "@app", "p1", "p2"); } } diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ContendedFlatFieldOopMap.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ContendedFlatFieldOopMap.java similarity index 95% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/ContendedFlatFieldOopMap.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/ContendedFlatFieldOopMap.java index f36852d45be4..4c7897631627 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ContendedFlatFieldOopMap.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ContendedFlatFieldOopMap.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.vm.annotation.Contended; import java.lang.ref.WeakReference; @@ -38,7 +38,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-RestrictContended * -XX:+WhiteBoxAPI -Xbootclasspath/a:. - * runtime.valhalla.inlinetypes.ContendedFlatFieldOopMap + * runtime.valhalla.valuetypes.ContendedFlatFieldOopMap */ public class ContendedFlatFieldOopMap { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/DirectMethodTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/DirectMethodTest.java similarity index 96% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/DirectMethodTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/DirectMethodTest.java index b5b01a3786c2..dc86218cab31 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/DirectMethodTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/DirectMethodTest.java @@ -31,7 +31,7 @@ * @library /test/lib * @enablePreview * @compile --source 28 DirectMethodTest.java - * @run main/othervm -Djdk.reflect.useNativeAccessorOnly=true -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseArrayFlattening -XX:+UseFieldFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.inlinetypes.DirectMethodTest flat + * @run main/othervm -Djdk.reflect.useNativeAccessorOnly=true -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseArrayFlattening -XX:+UseFieldFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.valuetypes.DirectMethodTest flat */ /* @@ -44,10 +44,10 @@ * @library /test/lib * @enablePreview * @compile --source 28 DirectMethodTest.java - * @run main/othervm -Djdk.reflect.useNativeAccessorOnly=true -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:-UseArrayFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.inlinetypes.DirectMethodTest noflat + * @run main/othervm -Djdk.reflect.useNativeAccessorOnly=true -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:-UseArrayFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.valuetypes.DirectMethodTest noflat */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import java.lang.reflect.Array; import java.lang.reflect.Method; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/EmptyInlineTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/EmptyValueTest.java similarity index 65% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/EmptyInlineTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/EmptyValueTest.java index 5665347723b4..c7061cf8d00c 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/EmptyInlineTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/EmptyValueTest.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.test.lib.Asserts; @@ -33,19 +33,19 @@ /* * @test - * @summary Test support for empty inline types (no instance fields) + * @summary Test support for empty value types (no instance fields) * @library /test/lib * @modules java.base/jdk.internal.vm.annotation * java.base/jdk.internal.value * @enablePreview - * @compile EmptyInlineTest.java - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening runtime.valhalla.inlinetypes.EmptyInlineTest + * @compile EmptyValueTest.java + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening runtime.valhalla.valuetypes.EmptyValueTest */ -public class EmptyInlineTest { +public class EmptyValueTest { @LooselyConsistentValue - static value class EmptyInline { + static value class EmptyValue { public boolean isEmpty() { return true; } @@ -54,10 +54,10 @@ public boolean isEmpty() { @LooselyConsistentValue static value class EmptyField { @NullRestricted - EmptyInline empty; + EmptyValue empty; EmptyField() { - this.empty = new EmptyInline(); + this.empty = new EmptyValue(); } } @@ -67,69 +67,69 @@ static class WithInt { static class WithEmptyField extends WithInt { // With current layout strategy for reference classs, the empty - // inline field would be placed between the int and the Object + // value field would be placed between the int and the Object // fields, along with some padding. Object o; @NullRestricted - EmptyInline empty; + EmptyValue empty; WithEmptyField() { - empty = new EmptyInline(); + empty = new EmptyValue(); super(); } } public static void main(String[] args) { - // Create an empty inline - EmptyInline empty = new EmptyInline(); + // Create an empty value + EmptyValue empty = new EmptyValue(); Asserts.assertTrue(empty.isEmpty()); - // Create an inline with an empty inline field + // Create a value with an empty value field EmptyField emptyField = new EmptyField(); - Asserts.assertEquals(emptyField.empty.getClass(), EmptyInline.class); + Asserts.assertEquals(emptyField.empty.getClass(), EmptyValue.class); Asserts.assertTrue(emptyField.empty.isEmpty()); System.out.println(emptyField.empty.isEmpty()); // Regular instance with an empty field inside WithEmptyField w = new WithEmptyField(); - Asserts.assertEquals(w.empty.getClass(), EmptyInline.class); + Asserts.assertEquals(w.empty.getClass(), EmptyValue.class); Asserts.assertTrue(w.empty.isEmpty()); - w.empty = new EmptyInline(); - Asserts.assertEquals(w.empty.getClass(), EmptyInline.class); + w.empty = new EmptyValue(); + Asserts.assertEquals(w.empty.getClass(), EmptyValue.class); Asserts.assertTrue(w.empty.isEmpty()); - // Create an array of empty inlines - EmptyInline[] emptyArray = (EmptyInline[])ValueClass.newNullRestrictedNonAtomicArray(EmptyInline.class, 100, new EmptyInline()); - for(EmptyInline element : emptyArray) { - Asserts.assertEquals(element.getClass(), EmptyInline.class); + // Create an array of empty values + EmptyValue[] emptyArray = (EmptyValue[])ValueClass.newNullRestrictedNonAtomicArray(EmptyValue.class, 100, new EmptyValue()); + for(EmptyValue element : emptyArray) { + Asserts.assertEquals(element.getClass(), EmptyValue.class); Asserts.assertTrue(element.isEmpty()); } // Testing arrayCopy - EmptyInline[] array2 = (EmptyInline[])ValueClass.newNullRestrictedNonAtomicArray(EmptyInline.class, 100, new EmptyInline()); + EmptyValue[] array2 = (EmptyValue[])ValueClass.newNullRestrictedNonAtomicArray(EmptyValue.class, 100, new EmptyValue()); // with two arrays System.arraycopy(emptyArray, 10, array2, 20, 50); - for(EmptyInline element : array2) { - Asserts.assertEquals(element.getClass(), EmptyInline.class); + for(EmptyValue element : array2) { + Asserts.assertEquals(element.getClass(), EmptyValue.class); Asserts.assertTrue(element.isEmpty()); } // single array, no overlap System.arraycopy(emptyArray, 10, emptyArray, 50, 20); - for(EmptyInline element : emptyArray) { - Asserts.assertEquals(element.getClass(), EmptyInline.class); + for(EmptyValue element : emptyArray) { + Asserts.assertEquals(element.getClass(), EmptyValue.class); Asserts.assertTrue(element.isEmpty()); } // single array with overlap System.arraycopy(emptyArray, 10, emptyArray, 20, 50); - for(EmptyInline element : emptyArray) { - Asserts.assertEquals(element.getClass(), EmptyInline.class); + for(EmptyValue element : emptyArray) { + Asserts.assertEquals(element.getClass(), EmptyValue.class); Asserts.assertTrue(element.isEmpty()); } - // Passing an empty inline in argument + // Passing an empty value in argument assert isEmpty(empty); - // Returning an empty inline + // Returning an empty value assert getEmpty().isEmpty(); // Checking fields with reflection @@ -145,12 +145,12 @@ public static void main(String[] args) { Class c2 = w0.getClass(); try { Field emptyfield = c2.getDeclaredField("empty"); - EmptyInline e = (EmptyInline)emptyfield.get(w0); - Asserts.assertEquals(e.getClass(), EmptyInline.class); + EmptyValue e = (EmptyValue)emptyfield.get(w0); + Asserts.assertEquals(e.getClass(), EmptyValue.class); Asserts.assertTrue(e.isEmpty()); - emptyfield.set(w0, new EmptyInline()); - e = (EmptyInline)emptyfield.get(w0); - Asserts.assertEquals(e.getClass(), EmptyInline.class); + emptyfield.set(w0, new EmptyValue()); + e = (EmptyValue)emptyfield.get(w0); + Asserts.assertEquals(e.getClass(), EmptyValue.class); Asserts.assertTrue(e.isEmpty()); } catch(Throwable t) { t.printStackTrace(); @@ -163,12 +163,12 @@ public static void main(String[] args) { // } } - static boolean isEmpty(EmptyInline empty) { + static boolean isEmpty(EmptyValue empty) { return empty.isEmpty(); } - static EmptyInline getEmpty() { - return new EmptyInline(); + static EmptyValue getEmpty() { + return new EmptyValue(); } static void test() { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArrayCopyingTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayCopyingTest.java similarity index 93% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArrayCopyingTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayCopyingTest.java index 41f4c6e0c221..17d1bf6404cc 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArrayCopyingTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayCopyingTest.java @@ -38,7 +38,7 @@ * @run junit/othervm/timeout=480 -Xint -XX:+UseSerialGC -XX:+UseCompressedOops -Xlog:gc*=info -XX:+UseCompressedClassPointers -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - runtime.valhalla.inlinetypes.FlatArrayCopyingTest + runtime.valhalla.valuetypes.FlatArrayCopyingTest */ /* @@ -57,7 +57,7 @@ * @run junit/othervm/timeout=480 -Xint -XX:+UseParallelGC -XX:+UseCompressedOops -Xlog:gc*=info -XX:ParallelGCThreads=1 -XX:-UseDynamicNumberOfGCThreads -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - runtime.valhalla.inlinetypes.FlatArrayCopyingTest + runtime.valhalla.valuetypes.FlatArrayCopyingTest */ /* @@ -78,7 +78,7 @@ -XX:ParallelGCThreads=1 -XX:ConcGCThreads=1 -XX:-UseDynamicNumberOfGCThreads -XX:-G1UseConcRefinement -XX:+UseCompressedClassPointers -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - runtime.valhalla.inlinetypes.FlatArrayCopyingTest + runtime.valhalla.valuetypes.FlatArrayCopyingTest */ /* @@ -99,10 +99,10 @@ -XX:ParallelGCThreads=1 -XX:ConcGCThreads=1 -XX:-UseDynamicNumberOfGCThreads -XX:+UseCompressedClassPointers -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - runtime.valhalla.inlinetypes.FlatArrayCopyingTest + runtime.valhalla.valuetypes.FlatArrayCopyingTest */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import java.util.Arrays; import jdk.internal.value.ValueClass; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArrayDoesNotInitialize.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayDoesNotInitialize.java similarity index 94% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArrayDoesNotInitialize.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayDoesNotInitialize.java index 50138c433b54..4efb71569022 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArrayDoesNotInitialize.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayDoesNotInitialize.java @@ -27,9 +27,9 @@ * @summary Test that creating an array of T does not initialize class T * @enablePreview * @compile FlatArrayDoesNotInitialize.java - * @run main/othervm runtime.valhalla.inlinetypes.FlatArrayDoesNotInitialize + * @run main/othervm runtime.valhalla.valuetypes.FlatArrayDoesNotInitialize */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArrayLargeIndicesTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayLargeIndicesTest.java similarity index 93% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArrayLargeIndicesTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayLargeIndicesTest.java index 89c162c0ec0b..d23fa8f1c58e 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArrayLargeIndicesTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayLargeIndicesTest.java @@ -31,7 +31,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.value * @run junit/othervm/timeout=480 -Xmx18G -Xint - runtime.valhalla.inlinetypes.FlatArrayLargeIndicesTest + runtime.valhalla.valuetypes.FlatArrayLargeIndicesTest */ /* @@ -43,7 +43,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.value * @run junit/othervm/timeout=480 -Xmx18G -XX:TieredStopAtLevel=3 -Xcomp - runtime.valhalla.inlinetypes.FlatArrayLargeIndicesTest + runtime.valhalla.valuetypes.FlatArrayLargeIndicesTest */ /* @@ -55,10 +55,10 @@ * @library /test/lib / * @modules java.base/jdk.internal.value * @run junit/othervm/timeout=480 -Xmx18G -XX:-TieredCompilation -Xcomp - runtime.valhalla.inlinetypes.FlatArrayLargeIndicesTest + runtime.valhalla.valuetypes.FlatArrayLargeIndicesTest */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import java.util.Arrays; import jdk.internal.value.ValueClass; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArrayLargeOverlapCopyTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayLargeOverlapCopyTest.java similarity index 95% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArrayLargeOverlapCopyTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayLargeOverlapCopyTest.java index 0fd14059fdba..9fe9c2c0b1da 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArrayLargeOverlapCopyTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayLargeOverlapCopyTest.java @@ -29,10 +29,10 @@ * @requires os.maxMemory >= 7G * @modules java.base/jdk.internal.value * @run main/othervm/timeout=240 -Xint -Xmx6G - * runtime.valhalla.inlinetypes.FlatArrayLargeOverlapCopyTest + * runtime.valhalla.valuetypes.FlatArrayLargeOverlapCopyTest */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.value.ValueClass; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArrayLargePrimitiveOnly.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayLargePrimitiveOnly.java similarity index 95% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArrayLargePrimitiveOnly.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayLargePrimitiveOnly.java index 346972f7618b..80e61631e8c2 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArrayLargePrimitiveOnly.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArrayLargePrimitiveOnly.java @@ -33,10 +33,10 @@ * java.base/jdk.internal.vm.annotation * @run main/othervm -Xmx1G * -XX:+UseZGC - * runtime.valhalla.inlinetypes.FlatArrayLargePrimitiveOnly + * runtime.valhalla.valuetypes.FlatArrayLargePrimitiveOnly */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.value.ValueClass; import jdk.internal.vm.annotation.LooselyConsistentValue; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArraysTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArraysTest.java similarity index 98% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArraysTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArraysTest.java index cffff869aa3d..7cdffd3150fc 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatArraysTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatArraysTest.java @@ -21,7 +21,7 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.misc.Unsafe; import jdk.internal.value.ValueClass; @@ -43,7 +43,7 @@ /* * @test id=default - * @summary Plain array test for Inline Types + * @summary Plain array test for Value Types * @requires vm.flagless * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation @@ -51,12 +51,12 @@ * @library /test/lib * @enablePreview * @compile --source 28 FlatArraysTest.java - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseArrayFlattening -XX:+UseFieldFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.inlinetypes.FlatArraysTest + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseArrayFlattening -XX:+UseFieldFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.valuetypes.FlatArraysTest */ /* * @test id=no-array-flattening - * @summary Plain array test for Inline Types + * @summary Plain array test for Value Types * @requires vm.flagless * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation @@ -64,7 +64,7 @@ * @library /test/lib * @enablePreview * @compile --source 28 FlatArraysTest.java - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:-UseArrayFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.inlinetypes.FlatArraysTest + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:-UseArrayFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.valuetypes.FlatArraysTest */ public class FlatArraysTest { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatFieldAccessorMethods.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatFieldAccessorMethods.java similarity index 97% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatFieldAccessorMethods.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatFieldAccessorMethods.java index 1933a7286a86..d5b3c33c3f71 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlatFieldAccessorMethods.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlatFieldAccessorMethods.java @@ -30,10 +30,10 @@ * @modules java.base/jdk.internal.misc * @enablePreview * @compile FlatFieldAccessorMethods.java - * @run main runtime.valhalla.inlinetypes.FlatFieldAccessorMethods + * @run main runtime.valhalla.valuetypes.FlatFieldAccessorMethods */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import java.lang.reflect.Field; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlattenableSemanticTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlattenableSemanticTest.java similarity index 92% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlattenableSemanticTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/FlattenableSemanticTest.java index 6899e3ad481e..170657976277 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/FlattenableSemanticTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/FlattenableSemanticTest.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.test.lib.Asserts; @@ -35,8 +35,8 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FlattenableSemanticTest.java - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening runtime.valhalla.inlinetypes.FlattenableSemanticTest - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:ForceNonTearable=* runtime.valhalla.inlinetypes.FlattenableSemanticTest + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening runtime.valhalla.valuetypes.FlattenableSemanticTest + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:ForceNonTearable=* runtime.valhalla.valuetypes.FlattenableSemanticTest */ public class FlattenableSemanticTest { @@ -99,7 +99,7 @@ static Object getNull() { public static void main(String[] args) { FlattenableSemanticTest test = new FlattenableSemanticTest(); - // Uninitialized inline fields must be null for non flattenable fields + // Uninitialized value fields must be null for non flattenable fields Asserts.assertNull(nfsp, "Invalid non null value for uninitialized non flattenable field"); Asserts.assertNull(nfsj, "Invalid non null value for uninitialized non flattenable field"); Asserts.assertNull(test.nfip, "Invalid non null value for uninitialized non flattenable field"); @@ -107,13 +107,13 @@ public static void main(String[] args) { // fsp.equals(null); - // Uninitialized inline fields must be non null for flattenable fields + // Uninitialized value fields must be non null for flattenable fields Asserts.assertNotNull(fsp, "Invalid null value for uninitialized flattenable field"); Asserts.assertNotNull(fsj, "Invalid null value for uninitialized flattenable field"); Asserts.assertNotNull(test.fip, "Invalid null value for uninitialized flattenable field"); Asserts.assertNotNull(test.fij, "Invalid null value for uninitialized flattenable field"); - // Assigning null must be allowed for non flattenable inline fields + // Assigning null must be allowed for non flattenable value fields boolean exception = true; try { nfsp = (Point)getNull(); @@ -151,7 +151,7 @@ public static void main(String[] args) { } Asserts.assertFalse(exception, "Invalid NPE when assigning null to a non flattenable field"); - // Assigning null to a flattenable inline field must trigger a NPE + // Assigning null to a flattenable value field must trigger a NPE exception = false; try { fsp = (Point)getNull(); diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/HashOverflowTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/HashOverflowTest.java similarity index 95% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/HashOverflowTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/HashOverflowTest.java index 97221d0caecd..430bc7f0a752 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/HashOverflowTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/HashOverflowTest.java @@ -31,10 +31,10 @@ * @requires vm.flagless * @compile HashOverflowTest.java * @run main/othervm -Xint -Xss256K - * runtime.valhalla.inlinetypes.HashOverflowTest + * runtime.valhalla.valuetypes.HashOverflowTest */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; public class HashOverflowTest { private static final int N_ELEMS = 1000; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/HiddenInlineClassTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/HiddenValueClassTest.java similarity index 87% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/HiddenInlineClassTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/HiddenValueClassTest.java index 6c6412cb5d21..f9db43a92f1b 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/HiddenInlineClassTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/HiddenValueClassTest.java @@ -23,13 +23,13 @@ /* * @test - * @summary Test a hidden inline class. + * @summary Test a hidden value class. * @library /test/lib * @enablePreview - * @run main runtime.valhalla.inlinetypes.HiddenInlineClassTest + * @run main runtime.valhalla.valuetypes.HiddenValueClassTest */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import java.io.File; import java.lang.invoke.MethodHandles; @@ -38,7 +38,7 @@ import java.nio.file.Path; import java.nio.file.Paths; -public class HiddenInlineClassTest { +public class HiddenValueClassTest { static final Path CLASSES_DIR = Paths.get(System.getProperty("test.classes", ".")); static byte[] readClassFile(String classFileName) throws Exception { @@ -48,9 +48,9 @@ static byte[] readClassFile(String classFileName) throws Exception { public static void main(String[] args) throws Throwable { Lookup lookup = MethodHandles.lookup(); - byte[] bytes = readClassFile("runtime.valhalla.inlinetypes.HiddenPoint"); + byte[] bytes = readClassFile("runtime.valhalla.valuetypes.HiddenPoint"); - // Define a hidden class that is an inline type. + // Define a hidden class that is a value type. Class c = lookup.defineHiddenClass(bytes, true).lookupClass(); Object hp = c.newInstance(); String s = (String)c.getMethod("getValue").invoke(hp); @@ -75,4 +75,3 @@ public String getValue() { return "x: " + x + ", y: " + y; } } - diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/Ifacmp.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/Ifacmp.java similarity index 94% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/Ifacmp.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/Ifacmp.java index fd36370e45e1..b1666a37e4d4 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/Ifacmp.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/Ifacmp.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import java.lang.ref.*; import jdk.internal.vm.annotation.LooselyConsistentValue; @@ -34,7 +34,7 @@ * java.base/jdk.internal.vm.annotation * @enablePreview * @compile --source 28 Ifacmp.java - * @run main/othervm -Xms16m -Xmx16m -XX:+UseSerialGC runtime.valhalla.inlinetypes.Ifacmp + * @run main/othervm -Xms16m -Xmx16m -XX:+UseSerialGC runtime.valhalla.valuetypes.Ifacmp */ public class Ifacmp { @@ -97,9 +97,9 @@ static value class MyValue2 { public Ifacmp(boolean acmpModeInlineAlwaysFalse) { this.acmpModeInlineAlwaysFalse = acmpModeInlineAlwaysFalse; if (acmpModeInlineAlwaysFalse) { - System.out.println("ifacmp always false for inline types"); + System.out.println("ifacmp always false for value types"); } else { - System.out.println("ifacmp substitutability inline types"); + System.out.println("ifacmp substitutability value types"); } } @@ -209,8 +209,8 @@ public static void testNotEquals(Object a, Object b, boolean expected) { } public static void main(String[] args) { - boolean inlineTypesAlwaysFalse = (args.length > 0) && args[0].equals("alwaysFalse"); - new Ifacmp(inlineTypesAlwaysFalse).test(); - new Ifacmp(inlineTypesAlwaysFalse).testUntilGc(3); + boolean valueTypesAlwaysFalse = (args.length > 0) && args[0].equals("alwaysFalse"); + new Ifacmp(valueTypesAlwaysFalse).test(); + new Ifacmp(valueTypesAlwaysFalse).testUntilGc(3); } } diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/InheritedFlatFieldTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/InheritedFlatFieldTest.java similarity index 96% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/InheritedFlatFieldTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/InheritedFlatFieldTest.java index 367185ff1ed5..85f932eabf10 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/InheritedFlatFieldTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/InheritedFlatFieldTest.java @@ -21,7 +21,7 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import java.lang.reflect.Field; @@ -35,7 +35,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @run main/othervm/native --enable-native-access=ALL-UNNAMED - * runtime.valhalla.inlinetypes.InheritedFlatFieldTest + * runtime.valhalla.valuetypes.InheritedFlatFieldTest */ public class InheritedFlatFieldTest { static { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/JumboInline.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/JumboValue.java similarity index 93% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/JumboInline.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/JumboValue.java index b4cdeec30d8f..3b705a110c78 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/JumboInline.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/JumboValue.java @@ -20,12 +20,12 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.vm.annotation.LooselyConsistentValue; @LooselyConsistentValue -public value class JumboInline { +public value class JumboValue { final long l0; final long l1; final long l2; @@ -47,7 +47,7 @@ public value class JumboInline { final long l18; final long l19; - public JumboInline(long l0Val, long l1Val) { + public JumboValue(long l0Val, long l1Val) { l0 = l0Val; l1 = l1Val; l2 = l0Val+1; @@ -80,8 +80,8 @@ public boolean verify() { } public boolean equals(Object o) { - if(o instanceof JumboInline) { - JumboInline j = (JumboInline)o; + if(o instanceof JumboValue) { + JumboValue j = (JumboValue)o; return (l0 == j.l0 && l1 == j.l1 && l2 == j.l2 && l3 == j.l3 && l4 == j.l4 && l5 == j.l5 && l6 == j.l6 && l7 == j.l7 && l8 == j.l8 && l9 == j.l9 && l10 == j.l10 && l11 == j.l11 diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/Long8Inline.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/Long8Value.java similarity index 92% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/Long8Inline.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/Long8Value.java index 32fb5b4559db..6f37f2a92be9 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/Long8Inline.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/Long8Value.java @@ -21,13 +21,13 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.vm.annotation.LooselyConsistentValue; import jdk.test.lib.Asserts; @LooselyConsistentValue -public final value class Long8Inline { +public final value class Long8Value { final long longField1; final long longField2; @@ -38,11 +38,11 @@ public final value class Long8Inline { final long longField7; final long longField8; - public Long8Inline() { + public Long8Value() { this(0, 0, 0, 0, 0, 0, 0, 0); } - public Long8Inline(long l1, long l2, long l3, long l4, long l5, long l6, long l7, long l8) { + public Long8Value(long l1, long l2, long l3, long l4, long l5, long l6, long l7, long l8) { longField1 = l1; longField2 = l2; longField3 = l3; @@ -62,7 +62,7 @@ public Long8Inline(long l1, long l2, long l3, long l4, long l5, long l6, long l7 public long getLongField7() { return longField7; } public long getLongField8() { return longField8; } - static void check(Long8Inline value, + static void check(Long8Value value, long long1, long long2, long long3, diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/MonitorEnterTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/MonitorEnterTest.java similarity index 94% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/MonitorEnterTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/MonitorEnterTest.java index 342f3add768b..b414d3e4ba2f 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/MonitorEnterTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/MonitorEnterTest.java @@ -26,10 +26,10 @@ * @library /test/lib * @enablePreview * @compile MonitorEnterTest.java -* @run main/othervm/native -Xcheck:jni runtime.valhalla.inlinetypes.MonitorEnterTest +* @run main/othervm/native -Xcheck:jni runtime.valhalla.valuetypes.MonitorEnterTest */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.test.lib.Asserts; @@ -81,7 +81,7 @@ public static void main(String[] args) { for (int i = 0; i < 20000; i++) { monitorEnter(new Object(), true, ""); monitorEnter(new String(), true, ""); - monitorEnter(new MyValue(), false, "Cannot synchronize on an instance of value class runtime.valhalla.inlinetypes.MonitorEnterTest$MyValue"); + monitorEnter(new MyValue(), false, "Cannot synchronize on an instance of value class runtime.valhalla.valuetypes.MonitorEnterTest$MyValue"); monitorEnter(Integer.valueOf(42), false, "Cannot synchronize on an instance of value class java.lang.Integer"); } } diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/NPEInPreviewTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/NPEInPreviewTest.java similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/NPEInPreviewTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/NPEInPreviewTest.java diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/NullRestrictedArrayTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/NullRestrictedArrayTest.java similarity index 97% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/NullRestrictedArrayTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/NullRestrictedArrayTest.java index 7ba6c65bbd2d..df85d7e89ad2 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/NullRestrictedArrayTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/NullRestrictedArrayTest.java @@ -21,7 +21,7 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.value.ValueClass; import jdk.test.lib.Asserts; @@ -39,7 +39,7 @@ * java.base/jdk.internal.misc * java.base/jdk.internal.value * @enablePreview - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseArrayFlattening runtime.valhalla.inlinetypes.NullRestrictedArrayTest + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseArrayFlattening runtime.valhalla.valuetypes.NullRestrictedArrayTest */ public class NullRestrictedArrayTest { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/NullableFlatFieldTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/NullableFlatFieldTest.java similarity index 98% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/NullableFlatFieldTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/NullableFlatFieldTest.java index ee50fe02175f..4959ecfb9fd3 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/NullableFlatFieldTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/NullableFlatFieldTest.java @@ -27,10 +27,10 @@ * @library /test/lib * @modules java.base/jdk.internal.vm.annotation * @enablePreview - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseNullableAtomicValueFlattening -XX:+PrintInlineLayout runtime.valhalla.inlinetypes.NullableFlatFieldTest + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseNullableAtomicValueFlattening -XX:+PrintValueLayout runtime.valhalla.valuetypes.NullableFlatFieldTest */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.vm.annotation.LooselyConsistentValue; import jdk.internal.vm.annotation.NullRestricted; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ObjectMethods.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ObjectMethods.java similarity index 97% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/ObjectMethods.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/ObjectMethods.java index f55314a31604..a09eff48a135 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ObjectMethods.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ObjectMethods.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import java.lang.invoke.*; @@ -32,7 +32,7 @@ * @library /test/lib /test/jdk/java/lang/invoke/common * @enablePreview * @compile ObjectMethods.java - * @run main/othervm -XX:+UseCompressedClassPointers runtime.valhalla.inlinetypes.ObjectMethods + * @run main/othervm -XX:+UseCompressedClassPointers runtime.valhalla.valuetypes.ObjectMethods */ /* @@ -41,7 +41,7 @@ * @library /test/lib /test/jdk/java/lang/invoke/common * @enablePreview * @compile ObjectMethods.java - * @run main/othervm -XX:-UseCompressedClassPointers runtime.valhalla.inlinetypes.ObjectMethods + * @run main/othervm -XX:-UseCompressedClassPointers runtime.valhalla.valuetypes.ObjectMethods */ /* @@ -50,7 +50,7 @@ * @library /test/lib /test/jdk/java/lang/invoke/common * @enablePreview * @compile ObjectMethods.java - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-BytecodeVerificationLocal -XX:-BytecodeVerificationRemote runtime.valhalla.inlinetypes.ObjectMethods noverify + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-BytecodeVerificationLocal -XX:-BytecodeVerificationRemote runtime.valhalla.valuetypes.ObjectMethods noverify */ public class ObjectMethods { @@ -154,8 +154,8 @@ static void checkSynchronized(Object val) { if (!sawIe) { throw new RuntimeException("monitorenter did not fail"); } - // synchronized method modifiers tested by "BadInlineTypes" CFP tests - // jni monitor ops tested by "InlineWithJni" + // synchronized method modifiers tested by "BadValueTypes" CFP tests + // jni monitor ops tested by "ValueWithJni" } // Check we haven't broken the mismatched monitor block check... diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/Person.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/Person.java similarity index 97% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/Person.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/Person.java index 8c8320cab26e..40edf68b2706 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/Person.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/Person.java @@ -21,7 +21,7 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.vm.annotation.LooselyConsistentValue; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/Point.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/Point.java similarity index 97% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/Point.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/Point.java index 2e4d80a97418..8ee235bc0aba 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/Point.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/Point.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.vm.annotation.LooselyConsistentValue; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/PreloadCircularityTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/PreloadCircularityTest.java similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/PreloadCircularityTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/PreloadCircularityTest.java diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/PreloadShared.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/PreloadShared.java similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/PreloadShared.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/PreloadShared.java diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/PreloadValue0.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/PreloadValue0.java similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/PreloadValue0.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/PreloadValue0.java diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/QuickeningTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/QuickeningTest.java similarity index 91% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/QuickeningTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/QuickeningTest.java index 38c13faa0780..9a0fe6bf27fa 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/QuickeningTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/QuickeningTest.java @@ -21,7 +21,7 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.vm.annotation.LooselyConsistentValue; import jdk.internal.vm.annotation.NullRestricted; @@ -29,12 +29,12 @@ /* * @test QuickeningTest - * @summary Test quickening of getfield and putfield applied to inline fields + * @summary Test quickening of getfield and putfield applied to value fields * @library /test/lib * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile QuickeningTest.java - * @run main runtime.valhalla.inlinetypes.QuickeningTest + * @run main runtime.valhalla.valuetypes.QuickeningTest */ public class QuickeningTest { @@ -98,11 +98,11 @@ public JumboInline(long l0Val, long l1Val) { } static class Parent { - Point nfp; /* Not flattenable inline field */ + Point nfp; /* Not flattenable value field */ @NullRestricted - Point fp; /* Flattenable and flattened inline field */ + Point fp; /* Flattenable and flattened value field */ @NullRestricted - JumboInline fj; /* Flattenable not flattened inline field */ + JumboInline fj; /* Flattenable not flattened value field */ Parent() { fp = new Point(1, 2); @@ -117,11 +117,11 @@ static class Parent { static class Child extends Parent { // This class inherited fields from the Parent class - Point nfp2; /* Not flattenable inline field */ + Point nfp2; /* Not flattenable value field */ @NullRestricted - Point fp2; /* Flattenable and flattened inline field */ + Point fp2; /* Flattenable and flattened value field */ @NullRestricted - JumboInline fj2; /* Flattenable not flattened inline field */ + JumboInline fj2; /* Flattenable not flattened value field */ Child() { fp2 = new Point(5, 6); @@ -136,11 +136,11 @@ static class Child extends Parent { @LooselyConsistentValue static value class Value { - final Point nfp; /* Not flattenable inline field */ + final Point nfp; /* Not flattenable value field */ @NullRestricted - final Point fp; /* Flattenable and flattened inline field */ + final Point fp; /* Flattenable and flattened value field */ @NullRestricted - final JumboInline fj; /* Flattenable not flattened inline field */ + final JumboInline fj; /* Flattenable not flattened value field */ private Value() { nfp = null; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/StaticFieldsTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/StaticFieldsTest.java similarity index 97% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/StaticFieldsTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/StaticFieldsTest.java index 9503f202309c..46a0bc958bf0 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/StaticFieldsTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/StaticFieldsTest.java @@ -20,7 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.test.lib.Asserts; import jdk.internal.vm.annotation.LooselyConsistentValue; @@ -34,7 +34,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile StaticFieldsTest.java - * @run main runtime.valhalla.inlinetypes.StaticFieldsTest + * @run main runtime.valhalla.valuetypes.StaticFieldsTest */ public class StaticFieldsTest { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/Test8186715.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/Test8186715.java similarity index 92% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/Test8186715.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/Test8186715.java index a3523551e960..c799b57c6b3e 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/Test8186715.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/Test8186715.java @@ -21,20 +21,20 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.value.ValueClass; import jdk.internal.vm.annotation.LooselyConsistentValue; /* * @test Test8186715 - * @summary test return of buffered inline type passed in argument by caller + * @summary test return of buffered value type passed in argument by caller * @library /test/lib * @modules java.base/jdk.internal.vm.annotation * java.base/jdk.internal.value * @enablePreview * @compile Test8186715.java - * @run main runtime.valhalla.inlinetypes.Test8186715 + * @run main runtime.valhalla.valuetypes.Test8186715 */ public class Test8186715 { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestArrayCopy.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestArrayCopy.java similarity index 99% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestArrayCopy.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/TestArrayCopy.java index 8f605a870c22..a540e8859a58 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestArrayCopy.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestArrayCopy.java @@ -28,10 +28,10 @@ * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @enablePreview - * @run main/othervm runtime.valhalla.inlinetypes.TestArrayCopy + * @run main/othervm runtime.valhalla.valuetypes.TestArrayCopy */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import java.lang.reflect.Method; import java.util.ArrayList; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestArrayFactories.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestArrayFactories.java similarity index 99% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestArrayFactories.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/TestArrayFactories.java index d837a21d2c10..e5b7eb0837e3 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestArrayFactories.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestArrayFactories.java @@ -22,7 +22,7 @@ * */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import java.lang.reflect.Method; import java.util.ArrayList; @@ -37,7 +37,7 @@ * @library /test/lib / * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation - * @run main runtime.valhalla.inlinetypes.TestArrayFactories + * @run main runtime.valhalla.valuetypes.TestArrayFactories */ public class TestArrayFactories { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestCloneableValue.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestCloneableValue.java similarity index 96% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestCloneableValue.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/TestCloneableValue.java index 1b3cba48cbfb..1f1c731b2cc5 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestCloneableValue.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestCloneableValue.java @@ -26,10 +26,10 @@ * @library /test/lib * @enablePreview * @compile TestCloneableValue.java - * @run main runtime.valhalla.inlinetypes.TestCloneableValue + * @run main runtime.valhalla.valuetypes.TestCloneableValue */ - package runtime.valhalla.inlinetypes; + package runtime.valhalla.valuetypes; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestFieldNullability.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestFieldNullability.java similarity index 97% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestFieldNullability.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/TestFieldNullability.java index 9baa42a4b0a5..0c3b0ac9798e 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestFieldNullability.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestFieldNullability.java @@ -28,10 +28,10 @@ * @enablePreview * @compile TestFieldNullability.java * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening - * runtime.valhalla.inlinetypes.TestFieldNullability + * runtime.valhalla.valuetypes.TestFieldNullability */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.vm.annotation.LooselyConsistentValue; import jdk.internal.vm.annotation.NullRestricted; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestFinalizableValues.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestFinalizableValues.java similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestFinalizableValues.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/TestFinalizableValues.java diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestFlatArrayElementMaxOops.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestFlatArrayElementMaxOops.java similarity index 93% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestFlatArrayElementMaxOops.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/TestFlatArrayElementMaxOops.java index 789f8b330e62..04b7b45b8fe1 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestFlatArrayElementMaxOops.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestFlatArrayElementMaxOops.java @@ -21,7 +21,7 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.value.ValueClass; import jdk.internal.vm.annotation.LooselyConsistentValue; @@ -38,7 +38,7 @@ * @enablePreview * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseArrayFlattening -XX:FlatArrayElementMaxOops=0 * -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening - * runtime.valhalla.inlinetypes.TestFlatArrayElementMaxOops 0 + * runtime.valhalla.valuetypes.TestFlatArrayElementMaxOops 0 */ /* @@ -51,7 +51,7 @@ * @enablePreview * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseArrayFlattening -XX:FlatArrayElementMaxOops=1 * -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening - * runtime.valhalla.inlinetypes.TestFlatArrayElementMaxOops 1 + * runtime.valhalla.valuetypes.TestFlatArrayElementMaxOops 1 */ /* @@ -64,7 +64,7 @@ * @enablePreview * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseArrayFlattening -XX:FlatArrayElementMaxOops=2 * -XX:+UseNullableAtomicValueFlattening -XX:+UseNullFreeAtomicValueFlattening -XX:+UseNullFreeNonAtomicValueFlattening - * runtime.valhalla.inlinetypes.TestFlatArrayElementMaxOops 2 + * runtime.valhalla.valuetypes.TestFlatArrayElementMaxOops 2 */ public class TestFlatArrayElementMaxOops { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestFlatteningBudget.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestFlatteningBudget.java similarity index 91% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestFlatteningBudget.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/TestFlatteningBudget.java index 9e3906137139..3f14170d3e75 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestFlatteningBudget.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestFlatteningBudget.java @@ -31,10 +31,10 @@ * @requires vm.opt.UseFieldFlattening != "false" * @requires vm.opt.UseNullableAtomicValueFlattening != "false" * @requires vm.compMode != "Xcomp" - * @run main runtime.valhalla.inlinetypes.TestFlatteningBudget + * @run main runtime.valhalla.valuetypes.TestFlatteningBudget */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import com.sun.management.HotSpotDiagnosticMXBean; import com.sun.management.VMOption; @@ -140,10 +140,10 @@ static void runTest(String... args) throws Exception { } static public void main(String[] args) throws Exception { - runTest("runtime.valhalla.inlinetypes.TestFlatteningBudget$Test0"); - runTest("-XX:FlatteningBudget=128", "runtime.valhalla.inlinetypes.TestFlatteningBudget$Test1", "128"); - runTest("-XX:FlatteningBudget=4", "runtime.valhalla.inlinetypes.TestFlatteningBudget$Test1", "4"); - runTest("-XX:FlatteningBudget=2", "runtime.valhalla.inlinetypes.TestFlatteningBudget$Test1", "2"); - runTest("-XX:FlatteningBudget=0", "runtime.valhalla.inlinetypes.TestFlatteningBudget$Test1", "0"); + runTest("runtime.valhalla.valuetypes.TestFlatteningBudget$Test0"); + runTest("-XX:FlatteningBudget=128", "runtime.valhalla.valuetypes.TestFlatteningBudget$Test1", "128"); + runTest("-XX:FlatteningBudget=4", "runtime.valhalla.valuetypes.TestFlatteningBudget$Test1", "4"); + runTest("-XX:FlatteningBudget=2", "runtime.valhalla.valuetypes.TestFlatteningBudget$Test1", "2"); + runTest("-XX:FlatteningBudget=0", "runtime.valhalla.valuetypes.TestFlatteningBudget$Test1", "0"); } } diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestInheritedInlineTypeFields.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestInheritedValueTypeFields.java similarity index 88% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestInheritedInlineTypeFields.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/TestInheritedValueTypeFields.java index 948c66a6855a..dd628a361519 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestInheritedInlineTypeFields.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestInheritedValueTypeFields.java @@ -21,19 +21,19 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.vm.annotation.NullRestricted; import jdk.test.lib.Asserts; /* - * @test TestInheritedInlineTypeFields - * @summary Test if inline field klasses are correctly retrieved for inherited fields + * @test TestInheritedValueTypeFields + * @summary Test if value field klasses are correctly retrieved for inherited fields * @library /test/lib * @modules java.base/jdk.internal.vm.annotation * @enablePreview - * @compile Point.java TestInheritedInlineTypeFields.java - * @run main runtime.valhalla.inlinetypes.TestInheritedInlineTypeFields + * @compile Point.java TestInheritedValueTypeFields.java + * @run main runtime.valhalla.valuetypes.TestInheritedValueTypeFields */ class A { @@ -82,7 +82,7 @@ class G extends F { } } -public class TestInheritedInlineTypeFields { +public class TestInheritedValueTypeFields { public static void main(String[] args) { for (int i = 0; i < 100000; i++) { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestJNIAllocObject.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestJNIAllocObject.java similarity index 91% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestJNIAllocObject.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/TestJNIAllocObject.java index dda30524e23e..83d1ccca66b5 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestJNIAllocObject.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestJNIAllocObject.java @@ -21,17 +21,17 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.test.lib.Asserts; /* * @test - * @summary Test JNI AllocObject with inline types + * @summary Test JNI AllocObject with value types * @library /test/lib * @enablePreview * @run main/othervm/native --enable-native-access=ALL-UNNAMED -Xcheck:jni - * runtime.valhalla.inlinetypes.TestJNIAllocObject + * runtime.valhalla.valuetypes.TestJNIAllocObject */ public class TestJNIAllocObject { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestJNIHasIdentity.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestJNIHasIdentity.java similarity index 91% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestJNIHasIdentity.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/TestJNIHasIdentity.java index 4c4e648c9de7..ceb13681f9b7 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestJNIHasIdentity.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestJNIHasIdentity.java @@ -21,17 +21,17 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.test.lib.Asserts; /* * @test - * @summary Test JNI HasIdentity with inline types + * @summary Test JNI HasIdentity with value types * @library /test/lib * @enablePreview * @run main/othervm/native --enable-native-access=ALL-UNNAMED - * runtime.valhalla.inlinetypes.TestJNIHasIdentity + * runtime.valhalla.valuetypes.TestJNIHasIdentity */ public class TestJNIHasIdentity { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestJNIIsSameObject.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestJNIIsSameObject.java similarity index 92% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestJNIIsSameObject.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/TestJNIIsSameObject.java index ea2499f0e528..a04ff46a7e57 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestJNIIsSameObject.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestJNIIsSameObject.java @@ -21,7 +21,7 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.vm.annotation.LooselyConsistentValue; import jdk.test.lib.Asserts; @@ -29,12 +29,12 @@ /* * @test - * @summary Test JNI IsSameObject semantic with inline types + * @summary Test JNI IsSameObject semantic with value types * @library /testlibrary /test/lib * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile TestJNIIsSameObject.java - * @run main/othervm/native runtime.valhalla.inlinetypes.TestJNIIsSameObject + * @run main/othervm/native runtime.valhalla.valuetypes.TestJNIIsSameObject */ public class TestJNIIsSameObject { @LooselyConsistentValue @@ -76,7 +76,7 @@ public static void main(String[] args) { Asserts.assertFalse(isSameObject(t0, null)); Asserts.assertFalse(isSameObject(null, t0)); - // Object vs inline + // Object vs value Asserts.assertFalse(isSameObject(v0, t0)); Asserts.assertFalse(isSameObject(t0, v0)); diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestJNINewWeakGlobalRef.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestJNINewWeakGlobalRef.java similarity index 92% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestJNINewWeakGlobalRef.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/TestJNINewWeakGlobalRef.java index 26a99ee22a56..cac4146685d1 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestJNINewWeakGlobalRef.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestJNINewWeakGlobalRef.java @@ -21,17 +21,17 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.test.lib.Asserts; /* * @test - * @summary Test JNI NewWeakGlobalRef with inline types + * @summary Test JNI NewWeakGlobalRef with value types * @library /test/lib * @enablePreview * @run main/othervm/native --enable-native-access=ALL-UNNAMED - * runtime.valhalla.inlinetypes.TestJNINewWeakGlobalRef + * runtime.valhalla.valuetypes.TestJNINewWeakGlobalRef */ public class TestJNINewWeakGlobalRef { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestValueObjectMethodsInit.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/TestValueObjectMethodsInit.java similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/TestValueObjectMethodsInit.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/TestValueObjectMethodsInit.java diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/UnsafeTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/UnsafeTest.java similarity index 98% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/UnsafeTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/UnsafeTest.java index 758929db704e..dc4d34e37383 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/UnsafeTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/UnsafeTest.java @@ -21,14 +21,14 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; /* * @test UnsafeTest * @requires vm.debug == true - * @summary unsafe get/put/with inline type + * @summary unsafe get/put/with value type * @modules java.base/jdk.internal.misc * @modules java.base/jdk.internal.value * @library /test/lib @@ -38,7 +38,7 @@ * @compile Point.java UnsafeTest.java * @run main/othervm -Xint -XX:+UnlockDiagnosticVMOptions -XX:+UseNullableAtomicValueFlattening -XX:+UseArrayFlattening -XX:+UseFieldFlattening - -XX:+PrintInlineLayout -Xlog:valuetypes=trace runtime.valhalla.inlinetypes.UnsafeTest + -XX:+PrintValueLayout -Xlog:valuetypes=trace runtime.valhalla.valuetypes.UnsafeTest */ // TODO 8350865 Implement unsafe intrinsics for nullable flat fields/arrays in C2 diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ValueCopyingTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueCopyingTest.java similarity index 96% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/ValueCopyingTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueCopyingTest.java index 3bf6d1c8ef5e..fcebfc87c2e4 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ValueCopyingTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueCopyingTest.java @@ -28,10 +28,10 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile ValueCopyingTest.java - * @run main/othervm -Xint -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlineLayout runtime.valhalla.inlinetypes.ValueCopyingTest + * @run main/othervm -Xint -XX:+UnlockDiagnosticVMOptions -XX:+PrintValueLayout runtime.valhalla.valuetypes.ValueCopyingTest */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.vm.annotation.LooselyConsistentValue; import jdk.internal.vm.annotation.NullRestricted; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineOops.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueOops.java similarity index 91% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineOops.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueOops.java index 2437c82b622f..2248ed2bbccb 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineOops.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueOops.java @@ -21,7 +21,7 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import java.lang.constant.ClassDesc; import java.lang.constant.MethodTypeDesc; @@ -36,108 +36,108 @@ import static jdk.test.lib.Asserts.*; import jdk.test.lib.Utils; import jdk.test.whitebox.WhiteBox; -import runtime.valhalla.inlinetypes.InlineOops.FooValue; +import runtime.valhalla.valuetypes.ValueOops.FooValue; import test.java.lang.invoke.lib.InstructionHelper; import static test.java.lang.invoke.lib.InstructionHelper.classDesc; /** * @test id=Serial * @requires vm.gc.Serial - * @summary Test embedding oops into Inline types + * @summary Test embedding oops into Value types * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @library /test/lib /test/jdk/java/lang/invoke/common * @enablePreview * @requires vm.flagless - * @compile Person.java InlineOops.java + * @compile Person.java ValueOops.java * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -XX:+UseSerialGC -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * runtime.valhalla.inlinetypes.InlineOops + * runtime.valhalla.valuetypes.ValueOops */ /** * @test id=G1 * @requires vm.gc.G1 - * @summary Test embedding oops into Inline types + * @summary Test embedding oops into Value types * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @library /test/lib /test/jdk/java/lang/invoke/common * @enablePreview * @requires vm.flagless - * @compile Person.java InlineOops.java + * @compile Person.java ValueOops.java * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -XX:+UseG1GC -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * runtime.valhalla.inlinetypes.InlineOops 20 + * runtime.valhalla.valuetypes.ValueOops 20 */ /** * @test id=Parallel * @requires vm.gc.Parallel - * @summary Test embedding oops into Inline types + * @summary Test embedding oops into Value types * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @library /test/lib /test/jdk/java/lang/invoke/common * @enablePreview * @requires vm.flagless - * @compile Person.java InlineOops.java + * @compile Person.java ValueOops.java * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -XX:+UseParallelGC -XX:+UnlockDiagnosticVMOptions -Xmx128m -XX:+UseFieldFlattening * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * runtime.valhalla.inlinetypes.InlineOops + * runtime.valhalla.valuetypes.ValueOops */ /** * @test id=Shenandoah * @requires vm.gc.Shenandoah - * @summary Test embedding oops into Inline types + * @summary Test embedding oops into Value types * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @library /test/lib /test/jdk/java/lang/invoke/common * @enablePreview * @requires vm.flagless - * @compile Person.java InlineOops.java + * @compile Person.java ValueOops.java * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -XX:+UseShenandoahGC -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * runtime.valhalla.inlinetypes.InlineOops + * runtime.valhalla.valuetypes.ValueOops */ /** * @test id=Z * @requires vm.gc.Z - * @summary Test embedding oops into Inline types + * @summary Test embedding oops into Value types * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @library /test/lib /test/jdk/java/lang/invoke/common * @enablePreview * @requires vm.flagless - * @compile Person.java InlineOops.java + * @compile Person.java ValueOops.java * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xmx128m * -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * runtime.valhalla.inlinetypes.InlineOops + * runtime.valhalla.valuetypes.ValueOops */ /** * @test id=ZXint * @requires vm.gc.Z - * @summary Test embedding oops into Inline types (sanity check with interpreter only the most complex GC) + * @summary Test embedding oops into Value types (sanity check with interpreter only the most complex GC) * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @library /test/lib /test/jdk/java/lang/invoke/common * @enablePreview * @requires vm.flagless - * @compile Person.java InlineOops.java + * @compile Person.java ValueOops.java * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xint -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xmx128m * -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * runtime.valhalla.inlinetypes.InlineOops + * runtime.valhalla.valuetypes.ValueOops */ -public class InlineOops { +public class ValueOops { // Extra debug: -XX:+VerifyOops -XX:+VerifyStack -XX:+VerifyLastFrame -XX:+VerifyBeforeGC -XX:+VerifyAfterGC -XX:+VerifyDuringGC -XX:VerifySubSet=threads,heap // Even more debugging: -XX:+TraceNewOopMapGeneration -Xlog:gc*=info @@ -174,7 +174,7 @@ public static void main(String[] args) { } /** - * Test ClassFileParser can load inline types with reference fields + * Test ClassFileParser can load value types with reference fields */ public static void testClassLoad() { String s = Person.class.toString(); @@ -213,7 +213,7 @@ public Composition(Person onePerson, Person otherPerson) { } /** - * Check inline type operations with "Valhalla Inline Types" (VVT) + * Check value type operations with "Valhalla Value Types" (VVT) */ public static void testValues() { // Exercise creation, getfield, vreturn with null refs @@ -394,14 +394,14 @@ public static void testOverGc() { CODE->{ CODE .aload(0) - .invokestatic(classDesc(InlineOops.class), "doGc", MethodTypeDesc.ofDescriptor("()V")) // Stack + .invokestatic(classDesc(ValueOops.class), "doGc", MethodTypeDesc.ofDescriptor("()V")) // Stack .astore(0) - .invokestatic(classDesc(InlineOops.class), "doGc", MethodTypeDesc.ofDescriptor("()V")) // LVT + .invokestatic(classDesc(ValueOops.class), "doGc", MethodTypeDesc.ofDescriptor("()V")) // LVT .aload(0) .astore(1024) // LVT wide index .aload(1024) .iconst_1() // push a litte further down - .invokestatic(classDesc(InlineOops.class), "doGc", MethodTypeDesc.ofDescriptor("()V")) // Stack,LVT + .invokestatic(classDesc(ValueOops.class), "doGc", MethodTypeDesc.ofDescriptor("()V")) // Stack,LVT .pop() .areturn(); }); @@ -421,7 +421,7 @@ public static void testOverGc() { static void submitNewWork(ForkJoinPool fjPool) { for (int j = 0; j < 100; j++) { - fjPool.execute(InlineOops::testValues); + fjPool.execute(ValueOops::testValues); } } @@ -635,12 +635,12 @@ public static void testFrameOopsDefault(Object[][] oopMaps) { .invokespecial(classDesc(FooValue.class), "", MethodTypeDesc.ofDescriptor("()V")) .aload(oopMapsSlot) .iconst_0() // Test-D0 Slots=R Stack=Q(RRR)RV - .invokestatic(classDesc(InlineOops.class), GET_OOP_MAP_NAME, GET_OOP_MAP_DESC) + .invokestatic(classDesc(ValueOops.class), GET_OOP_MAP_NAME, GET_OOP_MAP_DESC) .aastore() .pop() .aload(oopMapsSlot) .iconst_1() // Test-D1 Slots=R Stack=RV - .invokestatic(classDesc(InlineOops.class), GET_OOP_MAP_NAME, GET_OOP_MAP_DESC) + .invokestatic(classDesc(ValueOops.class), GET_OOP_MAP_NAME, GET_OOP_MAP_DESC) .aastore() .new_(classDesc(FooValue.class)) .dup() @@ -648,14 +648,14 @@ public static void testFrameOopsDefault(Object[][] oopMaps) { .astore(vtSlot) .aload(oopMapsSlot) .iconst_2() // Test-D2 Slots=RQ(RRR) Stack=RV - .invokestatic(classDesc(InlineOops.class), GET_OOP_MAP_NAME, GET_OOP_MAP_DESC) + .invokestatic(classDesc(ValueOops.class), GET_OOP_MAP_NAME, GET_OOP_MAP_DESC) .aastore() .aload(vtSlot) .aconst_null() .astore(vtSlot) // Storing null over the Q slot won't remove the ref, but should be single null ref .aload(oopMapsSlot) .iconst_3() // Test-D3 Slots=R Stack=Q(RRR)RV - .invokestatic(classDesc(InlineOops.class), GET_OOP_MAP_NAME, GET_OOP_MAP_DESC) + .invokestatic(classDesc(ValueOops.class), GET_OOP_MAP_NAME, GET_OOP_MAP_DESC) .aastore() .pop() .return_(); @@ -679,7 +679,7 @@ public static void testFrameOopsRefs(String name, String description, String not .aaload() .aload(oopMapsSlot) .iconst_0() // Test-R0 Slots=RR Stack=Q(RRR)RV - .invokestatic(classDesc(InlineOops.class), GET_OOP_MAP_NAME, GET_OOP_MAP_DESC) + .invokestatic(classDesc(ValueOops.class), GET_OOP_MAP_NAME, GET_OOP_MAP_DESC) .aastore() .pop() .return_(); diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ValuePreloadClient0.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValuePreloadClient0.java similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/ValuePreloadClient0.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/ValuePreloadClient0.java diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ValuePreloadClient1.jcod b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValuePreloadClient1.jcod similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/ValuePreloadClient1.jcod rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/ValuePreloadClient1.jcod diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ValuePreloadTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValuePreloadTest.java similarity index 97% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/ValuePreloadTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/ValuePreloadTest.java index af4a30c4782a..79cc2e8b3873 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/ValuePreloadTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValuePreloadTest.java @@ -27,10 +27,10 @@ * @requires vm.flagless * @enablePreview * @compile ValuePreloadClient0.java PreloadValue0.java ValuePreloadClient1.jcod PreloadShared.java - * @run main runtime.valhalla.inlinetypes.ValuePreloadTest + * @run main runtime.valhalla.valuetypes.ValuePreloadTest */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import java.util.ArrayList; import java.util.Collections; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineTypeArray.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeArray.java similarity index 94% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineTypeArray.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeArray.java index 2be03354c31d..c6a844808875 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineTypeArray.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeArray.java @@ -21,7 +21,7 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.value.ValueClass; import jdk.internal.vm.annotation.LooselyConsistentValue; @@ -35,51 +35,51 @@ /* * @test id=default - * @summary Plain array test for Inline Types + * @summary Plain array test for Value Types * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @library /test/lib * @enablePreview - * @compile --source 28 InlineTypeArray.java Point.java Long8Inline.java Person.java - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseArrayFlattening -XX:+UseFieldFlattening runtime.valhalla.inlinetypes.InlineTypeArray + * @compile --source 28 ValueTypeArray.java Point.java Long8Value.java Person.java + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseArrayFlattening -XX:+UseFieldFlattening runtime.valhalla.valuetypes.ValueTypeArray */ /* * @test id=no-array-flattening - * @summary Plain array test for Inline Types + * @summary Plain array test for Value Types * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @library /test/lib * @enablePreview - * @compile --source 28 InlineTypeArray.java Point.java Long8Inline.java Person.java - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-UseArrayFlattening runtime.valhalla.inlinetypes.InlineTypeArray + * @compile --source 28 ValueTypeArray.java Point.java Long8Value.java Person.java + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-UseArrayFlattening runtime.valhalla.valuetypes.ValueTypeArray */ /* * @test id=no-tearable - * @summary Plain array test for Inline Types + * @summary Plain array test for Value Types * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @library /test/lib * @enablePreview - * @compile --source 28 InlineTypeArray.java Point.java Long8Inline.java Person.java - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:ForceNonTearable=* runtime.valhalla.inlinetypes.InlineTypeArray + * @compile --source 28 ValueTypeArray.java Point.java Long8Value.java Person.java + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:ForceNonTearable=* runtime.valhalla.valuetypes.ValueTypeArray */ /* * @test id=nullable-value-flattening - * @summary Plain array test for Inline Types + * @summary Plain array test for Value Types * @modules java.base/jdk.internal.value * java.base/jdk.internal.vm.annotation * @library /test/lib * @enablePreview - * @compile --source 28 InlineTypeArray.java Point.java Long8Inline.java Person.java - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseArrayFlattening -XX:+UseFieldFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.inlinetypes.InlineTypeArray + * @compile --source 28 ValueTypeArray.java Point.java Long8Value.java Person.java + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseArrayFlattening -XX:+UseFieldFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.valuetypes.ValueTypeArray */ -public class InlineTypeArray { +public class ValueTypeArray { public static void main(String[] args) { - InlineTypeArray inlineTypeArray = new InlineTypeArray(); - inlineTypeArray.run(); + ValueTypeArray valueTypeArray = new ValueTypeArray(); + valueTypeArray.run(); } public void run() { @@ -91,18 +91,18 @@ public void run() { testComposition(); testSanityCheckcasts(); - testObjectArrayOfInlines(); + testObjectArrayOfValues(); testReflectArray(); testUtilArraysOnNullRestrictedNonAtomicArrays(); testUtilArraysOnNullRestrictedAtomicArrays(); testUtilArraysOnNullableAtomicArrays(); - testInlineArrayOom(); + testValueArrayOom(); } void testClassForName() { - String arrayClsName = "[Lruntime.valhalla.inlinetypes.Point;"; + String arrayClsName = "[Lruntime.valhalla.valuetypes.Point;"; try { Class arrayCls = Class.forName(arrayClsName); assertTrue(arrayCls.isArray(), "Expected an array class"); @@ -199,20 +199,20 @@ static void checkSimplePointArray(Point[] points) { } void testLong8Array() { - Long8Inline[] values = (Long8Inline[])ValueClass.newNullRestrictedNonAtomicArray(Long8Inline.class, 3, new Long8Inline()); + Long8Value[] values = (Long8Value[])ValueClass.newNullRestrictedNonAtomicArray(Long8Value.class, 3, new Long8Value()); assertEquals(values.length, 3, "length"); values.toString(); - Long8Inline value = values[1]; + Long8Value value = values[1]; long zl = 0; - Long8Inline.check(value, zl, zl, zl, zl, zl, zl, zl, zl); - values[1] = new Long8Inline(1, 2, 3, 4, 5, 6, 7, 8); + Long8Value.check(value, zl, zl, zl, zl, zl, zl, zl, zl); + values[1] = new Long8Value(1, 2, 3, 4, 5, 6, 7, 8); value = values[1]; - Long8Inline.check(value, 1, 2, 3, 4, 5, 6, 7, 8); + Long8Value.check(value, 1, 2, 3, 4, 5, 6, 7, 8); - Long8Inline[] copy = (Long8Inline[])ValueClass.newNullRestrictedNonAtomicArray(Long8Inline.class, values.length, new Long8Inline()); + Long8Value[] copy = (Long8Value[])ValueClass.newNullRestrictedNonAtomicArray(Long8Value.class, values.length, new Long8Value()); System.arraycopy(values, 0, copy, 0, values.length); value = copy[1]; - Long8Inline.check(value, 1, 2, 3, 4, 5, 6, 7, 8); + Long8Value.check(value, 1, 2, 3, 4, 5, 6, 7, 8); } void testMixedPersonArray() { @@ -258,7 +258,7 @@ void testReflectArray() { assertEquals(array3[0].length, 2, "Incorrect length"); assertTrue(array3[0][0] == null, "Expected NULL"); - // Now create ObjArrays of InlineArray... + // Now create ObjArrays of ValueArray... Point[][] barray = (Point[][]) Array.newInstance(Point.class, 1, 2); assertEquals(barray.length, 1, "Incorrect length"); assertEquals(barray[0].length, 2, "Incorrect length"); @@ -367,7 +367,7 @@ void testSanityCheckcasts() { assertTrue(matrix[0] instanceof SomeSecondaryType[]); assertTrue(matrix[0] instanceof MyOtherInt[]); - // Box types vs Inline... + // Box types vs Value... MyInt[] myValueRefs = new MyInt[1]; assertTrue(myValueRefs instanceof MyInt[]); assertTrue(myValueRefs instanceof Object[]); @@ -666,7 +666,7 @@ void testUtilArraysOnNullableAtomicArrays() { aList.add(MyInt.create(5)); } - void testObjectArrayOfInlines() { + void testObjectArrayOfValues() { testSanityObjectArrays(); testMixedLayoutArrays(); } @@ -760,7 +760,7 @@ void testMixedLayoutArrays() { System.arraycopy(valArray, 0, valArray, 0, 3); checkArrayElementsEqual(valArray, objArray); - objArray[0] = "Not an inline object"; + objArray[0] = "Not a value object"; try { System.arraycopy(objArray, 0, valArray, 0, 3); throw new RuntimeException("Expected ArrayStoreException"); @@ -807,7 +807,7 @@ static MyPoint create(int x, int y) { } void testComposition() { - // Test array operations with compostion of inline types, check element payload is correct... + // Test array operations with compostion of value types, check element payload is correct... MyPoint a = MyPoint.create(1, 2); MyPoint b = MyPoint.create(7, 21); MyPoint c = MyPoint.create(Integer.MAX_VALUE, Integer.MIN_VALUE); @@ -884,7 +884,7 @@ void arrayCopy(MyPoint[] src, int srcPos, Object[] dst, int dstPos, int length) Object getNull() { return null; } - void testInlineArrayOom() { + void testValueArrayOom() { int size = Integer.MAX_VALUE; try { MyPoint[] pts = new MyPoint[size]; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineTypeCreation.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeCreation.java similarity index 81% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineTypeCreation.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeCreation.java index a9a779a7dd7c..e341dc6bd66a 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineTypeCreation.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeCreation.java @@ -20,24 +20,24 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.vm.annotation.LooselyConsistentValue; import jdk.test.lib.Asserts; /* - * @test InlineTypeCreation - * @summary Inline Type creation test + * @test ValueTypeCreation + * @summary Value Type creation test * @library /test/lib * @modules java.base/jdk.internal.vm.annotation * @enablePreview - * @compile InlineTypeCreation.java Point.java Long8Inline.java Person.java - * @run main/othervm runtime.valhalla.inlinetypes.InlineTypeCreation + * @compile ValueTypeCreation.java Point.java Long8Value.java Person.java + * @run main/othervm runtime.valhalla.valuetypes.ValueTypeCreation */ -public class InlineTypeCreation { +public class ValueTypeCreation { public static void main(String[] args) { - InlineTypeCreation inlineTypeCreation = new InlineTypeCreation(); - inlineTypeCreation.run(); + ValueTypeCreation valueTypeCreation = new ValueTypeCreation(); + valueTypeCreation.run(); } public void run() { @@ -63,10 +63,10 @@ static Point clonePoint(Point p) { } void testLong8() { - Long8Inline long8Inline = new Long8Inline(1, 2, 3, 4, 5, 6, 7, 8); - Asserts.assertEquals(long8Inline.getLongField1(), 1L, "Field 1 incorrect"); - Asserts.assertEquals(long8Inline.getLongField8(), 8L, "Field 8 incorrect"); - Long8Inline.check(long8Inline, 1, 2, 3, 4, 5, 6, 7, 8); + Long8Value long8Value = new Long8Value(1, 2, 3, 4, 5, 6, 7, 8); + Asserts.assertEquals(long8Value.getLongField1(), 1L, "Field 1 incorrect"); + Asserts.assertEquals(long8Value.getLongField8(), 8L, "Field 8 incorrect"); + Long8Value.check(long8Value, 1, 2, 3, 4, 5, 6, 7, 8); } void testPerson() { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineTypeDensity.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeDensity.java similarity index 94% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineTypeDensity.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeDensity.java index 092fdef67e19..9f016e274e8a 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineTypeDensity.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeDensity.java @@ -22,7 +22,7 @@ * */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.misc.Unsafe; import jdk.internal.value.ValueClass; @@ -34,65 +34,65 @@ /** * @test id=compressed-oops - * @summary Heap density test for InlineTypes + * @summary Heap density test for ValueTypes * @library /test/lib * @modules java.base/jdk.internal.vm.annotation * java.base/jdk.internal.value * java.base/jdk.internal.misc * @enablePreview - * @compile InlineTypeDensity.java + * @compile ValueTypeDensity.java * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseArrayFlattening -XX:+UseCompressedOops * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI runtime.valhalla.inlinetypes.InlineTypeDensity + * -XX:+WhiteBoxAPI runtime.valhalla.valuetypes.ValueTypeDensity */ /** * @test id=no-compressed-oops - * @summary Heap density test for InlineTypes + * @summary Heap density test for ValueTypes * @library /test/lib * @modules java.base/jdk.internal.vm.annotation * java.base/jdk.internal.value * java.base/jdk.internal.misc * @enablePreview - * @compile InlineTypeDensity.java + * @compile ValueTypeDensity.java * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseArrayFlattening -XX:-UseCompressedOops * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI runtime.valhalla.inlinetypes.InlineTypeDensity + * -XX:+WhiteBoxAPI runtime.valhalla.valuetypes.ValueTypeDensity */ /** * @test id=no-explicit-compression - * @summary Heap density test for InlineTypes + * @summary Heap density test for ValueTypes * @library /test/lib * @modules java.base/jdk.internal.vm.annotation * java.base/jdk.internal.value * java.base/jdk.internal.misc * @enablePreview - * @compile InlineTypeDensity.java + * @compile ValueTypeDensity.java * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseArrayFlattening * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI runtime.valhalla.inlinetypes.InlineTypeDensity + * -XX:+WhiteBoxAPI runtime.valhalla.valuetypes.ValueTypeDensity */ /** * @test id=force-non-tearable - * @summary Heap density test for InlineTypes + * @summary Heap density test for ValueTypes * @library /test/lib * @modules java.base/jdk.internal.vm.annotation * java.base/jdk.internal.value * java.base/jdk.internal.misc * @enablePreview - * @compile InlineTypeDensity.java + * @compile ValueTypeDensity.java * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+UseArrayFlattening * -Xbootclasspath/a:. -XX:ForceNonTearable=* - * -XX:+WhiteBoxAPI runtime.valhalla.inlinetypes.InlineTypeDensity + * -XX:+WhiteBoxAPI runtime.valhalla.valuetypes.ValueTypeDensity */ -public class InlineTypeDensity { +public class ValueTypeDensity { private static final Unsafe UNSAFE = Unsafe.getUnsafe(); private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); @@ -328,7 +328,7 @@ private void test() { } public static void main(String[] args) { - new InlineTypeDensity().test(); + new ValueTypeDensity().test(); } } diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineTypeGetField.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeGetField.java similarity index 88% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineTypeGetField.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeGetField.java index 0159c0510638..7c0c7407d659 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineTypeGetField.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypeGetField.java @@ -20,21 +20,21 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import jdk.internal.vm.annotation.NullRestricted; import jdk.test.lib.Asserts; /* - * @test InlineTypeGetField - * @summary Inline Type get field test + * @test ValueTypeGetField + * @summary Value Type get field test * @library /test/lib * @modules java.base/jdk.internal.vm.annotation * @enablePreview - * @compile Point.java InlineTypeGetField.java - * @run main runtime.valhalla.inlinetypes.InlineTypeGetField + * @compile Point.java ValueTypeGetField.java + * @run main runtime.valhalla.valuetypes.ValueTypeGetField */ -public class InlineTypeGetField { +public class ValueTypeGetField { @NullRestricted static Point staticPoint0; @@ -50,16 +50,16 @@ public class InlineTypeGetField { staticPoint1 = new Point(101, 2653); } - InlineTypeGetField() { + ValueTypeGetField() { instancePoint0 = new Point(1890, 1918); instancePoint1 = new Point(91, 102); super(); } public static void main(String[] args) { - InlineTypeGetField inlineTypeGetField = new InlineTypeGetField(); + ValueTypeGetField valueTypeGetField = new ValueTypeGetField(); System.gc(); // check that VTs survive GC - inlineTypeGetField.run(); + valueTypeGetField.run(); } public void run() { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineTypesTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypesTest.java similarity index 74% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineTypesTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypesTest.java index af90d868243f..af872b7b6206 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineTypesTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueTypesTest.java @@ -21,7 +21,7 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import java.io.File; import java.io.IOException; @@ -52,39 +52,39 @@ /** * @test id=default - * @summary Test data movement with inline types + * @summary Test data movement with value types * @modules java.base/jdk.internal.value * @library /test/lib /test/jdk/java/lang/invoke/common * @modules java.base/jdk.internal.vm.annotation * @enablePreview - * @compile InlineTypesTest.java + * @compile ValueTypesTest.java * @run main/othervm -Xmx128m -XX:+ExplicitGCInvokesConcurrent * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * runtime.valhalla.inlinetypes.InlineTypesTest + * runtime.valhalla.valuetypes.ValueTypesTest */ /** * @test id=force-non-tearable - * @summary Test data movement with inline types + * @summary Test data movement with value types * @modules java.base/jdk.internal.value * @library /test/lib /test/jdk/java/lang/invoke/common * @modules java.base/jdk.internal.vm.annotation * @enablePreview - * @compile InlineTypesTest.java + * @compile ValueTypesTest.java * @run main/othervm -Xmx128m -XX:+ExplicitGCInvokesConcurrent * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:ForceNonTearable=* - * runtime.valhalla.inlinetypes.InlineTypesTest + * runtime.valhalla.valuetypes.ValueTypesTest */ final class ContainerValue1 { - static TestValue1 staticInlineField; + static TestValue1 staticValueField; @NullRestricted - TestValue1 nonStaticInlineField; + TestValue1 nonStaticValueField; TestValue1[] valueArray; ContainerValue1() { - nonStaticInlineField = new TestValue1(); + nonStaticValueField = new TestValue1(); super(); } } @@ -123,13 +123,13 @@ public boolean verify() { } final class ContainerValue2 { - static TestValue2 staticInlineField; + static TestValue2 staticValueField; @NullRestricted - TestValue2 nonStaticInlineField; + TestValue2 nonStaticValueField; TestValue2[] valueArray; ContainerValue2() { - nonStaticInlineField = new TestValue2(); + nonStaticValueField = new TestValue2(); super(); } } @@ -175,13 +175,13 @@ public boolean verify() { } final class ContainerValue3 { - static TestValue3 staticInlineField; + static TestValue3 staticValueField; @NullRestricted - TestValue3 nonStaticInlineField; + TestValue3 nonStaticValueField; TestValue3[] valueArray; ContainerValue3() { - nonStaticInlineField = new TestValue3(); + nonStaticValueField = new TestValue3(); super(); } } @@ -215,13 +215,13 @@ public boolean verify() { } final class ContainerValue4 { - static TestValue4 staticInlineField; + static TestValue4 staticValueField; @NullRestricted - TestValue4 nonStaticInlineField; + TestValue4 nonStaticValueField; TestValue4[] valueArray; ContainerValue4() { - nonStaticInlineField = new TestValue4(); + nonStaticValueField = new TestValue4(); super(); } } @@ -292,28 +292,28 @@ public boolean verify() { } } -public class InlineTypesTest { +public class ValueTypesTest { public static void main(String[] args) { - Class inlineClass = runtime.valhalla.inlinetypes.TestValue1.class; + Class valueClass = runtime.valhalla.valuetypes.TestValue1.class; Class testClasses[] = { - runtime.valhalla.inlinetypes.TestValue1.class, - runtime.valhalla.inlinetypes.TestValue2.class, - runtime.valhalla.inlinetypes.TestValue3.class, - runtime.valhalla.inlinetypes.TestValue4.class + runtime.valhalla.valuetypes.TestValue1.class, + runtime.valhalla.valuetypes.TestValue2.class, + runtime.valhalla.valuetypes.TestValue3.class, + runtime.valhalla.valuetypes.TestValue4.class }; Class containerClasses[] = { - runtime.valhalla.inlinetypes.ContainerValue1.class, - runtime.valhalla.inlinetypes.ContainerValue2.class, - runtime.valhalla.inlinetypes.ContainerValue3.class, - runtime.valhalla.inlinetypes.ContainerValue4.class + runtime.valhalla.valuetypes.ContainerValue1.class, + runtime.valhalla.valuetypes.ContainerValue2.class, + runtime.valhalla.valuetypes.ContainerValue3.class, + runtime.valhalla.valuetypes.ContainerValue4.class }; for (int i = 0; i < testClasses.length; i++) { try { testExecutionStackToLocalVariable(testClasses[i]); testExecutionStackToFields(testClasses[i], containerClasses[i]); - testExecutionStackToInlineArray(testClasses[i], containerClasses[i]); + testExecutionStackToValueArray(testClasses[i], containerClasses[i]); } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); @@ -323,11 +323,11 @@ public static void main(String[] args) { static MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); - static void testExecutionStackToLocalVariable(Class inlineClass) throws Throwable { - String sig = "()L" + inlineClass.getName().replace('.', '/') + ";"; + static void testExecutionStackToLocalVariable(Class valueClass) throws Throwable { + String sig = "()L" + valueClass.getName().replace('.', '/') + ";"; final MethodTypeDesc voidReturnClass = MethodTypeDesc.ofDescriptor(sig); final ClassDesc systemClassDesc = classDesc(System.class); - final ClassDesc inlineClassDesc = classDesc(inlineClass); + final ClassDesc valueClassDesc = classDesc(valueClass); MethodHandle fromExecStackToLocalVar = InstructionHelper.buildMethodHandle( LOOKUP, "execStackToLocalVar", @@ -338,11 +338,11 @@ static void testExecutionStackToLocalVariable(Class inlineClass) throws Throw while (n < 1024) { n++; CODE - .invokestatic(inlineClassDesc, "getInstance", voidReturnClass) + .invokestatic(valueClassDesc, "getInstance", voidReturnClass) .astore(n); n++; CODE - .invokestatic(inlineClassDesc, "getNonBufferedInstance", voidReturnClass) + .invokestatic(valueClassDesc, "getNonBufferedInstance", voidReturnClass) .astore(n); } CODE.invokestatic(systemClassDesc, "gc", MethodTypeDesc.ofDescriptor("()V")); @@ -350,7 +350,7 @@ static void testExecutionStackToLocalVariable(Class inlineClass) throws Throw while (n > 0) { CODE .aload(n) - .invokevirtual(inlineClassDesc, "verify", MethodTypeDesc.ofDescriptor("()Z")) + .invokevirtual(valueClassDesc, "verify", MethodTypeDesc.ofDescriptor("()Z")) .iconst_1() .if_icmpne(endLabel); n--; @@ -367,12 +367,12 @@ static void testExecutionStackToLocalVariable(Class inlineClass) throws Throw assertTrue(result, "Invariant"); } - static void testExecutionStackToFields(Class inlineClass, Class containerClass) throws Throwable { + static void testExecutionStackToFields(Class valueClass, Class containerClass) throws Throwable { final int ITERATIONS = Platform.isDebugBuild() ? 3 : 512; - String sig = "()L" + inlineClass.getName().replace('.', '/') + ";"; + String sig = "()L" + valueClass.getName().replace('.', '/') + ";"; final MethodTypeDesc voidReturnClass = MethodTypeDesc.ofDescriptor(sig); final ClassDesc systemClassDesc = classDesc(System.class); - final ClassDesc inlineClassDesc = classDesc(inlineClass); + final ClassDesc valueClassDesc = classDesc(valueClass); final ClassDesc containerClassDesc = classDesc(containerClass); MethodHandle fromExecStackToFields = InstructionHelper.buildMethodHandle( @@ -396,37 +396,37 @@ static void testExecutionStackToFields(Class inlineClass, Class containerC .ldc(ITERATIONS) .if_icmpeq(end) .aload(1) - .invokestatic(inlineClassDesc, "getInstance", voidReturnClass) - .putfield(containerClassDesc, "nonStaticInlineField", inlineClassDesc) + .invokestatic(valueClassDesc, "getInstance", voidReturnClass) + .putfield(containerClassDesc, "nonStaticValueField", valueClassDesc) .invokestatic(systemClassDesc, "gc", MethodTypeDesc.ofDescriptor("()V")) .aload(1) - .getfield(containerClassDesc, "nonStaticInlineField", inlineClassDesc) - .invokevirtual(inlineClassDesc, "verify", MethodTypeDesc.ofDescriptor("()Z")) + .getfield(containerClassDesc, "nonStaticValueField", valueClassDesc) + .invokevirtual(valueClassDesc, "verify", MethodTypeDesc.ofDescriptor("()Z")) .iconst_1() .if_icmpne(failed) .aload(1) - .invokestatic(inlineClassDesc, "getNonBufferedInstance", voidReturnClass) - .putfield(containerClassDesc, "nonStaticInlineField", inlineClassDesc) + .invokestatic(valueClassDesc, "getNonBufferedInstance", voidReturnClass) + .putfield(containerClassDesc, "nonStaticValueField", valueClassDesc) .invokestatic(systemClassDesc, "gc", MethodTypeDesc.ofDescriptor("()V")) .aload(1) - .getfield(containerClassDesc, "nonStaticInlineField", inlineClassDesc) - .invokevirtual(inlineClassDesc, "verify", MethodTypeDesc.ofDescriptor("()Z")) + .getfield(containerClassDesc, "nonStaticValueField", valueClassDesc) + .invokevirtual(valueClassDesc, "verify", MethodTypeDesc.ofDescriptor("()Z")) .iconst_1() .if_icmpne(failed) - .invokestatic(inlineClassDesc, "getInstance", voidReturnClass) - .putstatic(containerClassDesc, "staticInlineField", inlineClassDesc) + .invokestatic(valueClassDesc, "getInstance", voidReturnClass) + .putstatic(containerClassDesc, "staticValueField", valueClassDesc) .invokestatic(systemClassDesc, "gc", MethodTypeDesc.ofDescriptor("()V")) - .getstatic(containerClassDesc, "staticInlineField", inlineClassDesc) - .checkcast(inlineClassDesc) - .invokevirtual(inlineClassDesc, "verify", MethodTypeDesc.ofDescriptor("()Z")) + .getstatic(containerClassDesc, "staticValueField", valueClassDesc) + .checkcast(valueClassDesc) + .invokevirtual(valueClassDesc, "verify", MethodTypeDesc.ofDescriptor("()Z")) .iconst_1() .if_icmpne(failed) - .invokestatic(inlineClassDesc, "getNonBufferedInstance", voidReturnClass) - .putstatic(containerClassDesc, "staticInlineField", inlineClassDesc) + .invokestatic(valueClassDesc, "getNonBufferedInstance", voidReturnClass) + .putstatic(containerClassDesc, "staticValueField", valueClassDesc) .invokestatic(systemClassDesc, "gc", MethodTypeDesc.ofDescriptor("()V")) - .getstatic(containerClassDesc, "staticInlineField", inlineClassDesc) - .checkcast(inlineClassDesc) - .invokevirtual(inlineClassDesc, "verify", MethodTypeDesc.ofDescriptor("()Z")) + .getstatic(containerClassDesc, "staticValueField", valueClassDesc) + .checkcast(valueClassDesc) + .invokevirtual(valueClassDesc, "verify", MethodTypeDesc.ofDescriptor("()Z")) .iconst_1() .if_icmpne(failed) .iinc(2, 1) @@ -443,17 +443,17 @@ static void testExecutionStackToFields(Class inlineClass, Class containerC assertTrue(result, "Invariant"); } - static void testExecutionStackToInlineArray(Class inlineClass, Class containerClass) throws Throwable { + static void testExecutionStackToValueArray(Class valueClass, Class containerClass) throws Throwable { final int ITERATIONS = Platform.isDebugBuild() ? 3 : 100; - String sig = "()L" + inlineClass.getName().replace('.', '/') + ";"; + String sig = "()L" + valueClass.getName().replace('.', '/') + ";"; final MethodTypeDesc voidReturnClass = MethodTypeDesc.ofDescriptor(sig); final ClassDesc systemClassDesc = classDesc(System.class); - final ClassDesc inlineClassDesc = classDesc(inlineClass); + final ClassDesc valueClassDesc = classDesc(valueClass); final ClassDesc containerClassDesc = classDesc(containerClass); - MethodHandle fromExecStackToInlineArray = InstructionHelper.buildMethodHandle( + MethodHandle fromExecStackToValueArray = InstructionHelper.buildMethodHandle( LOOKUP, - "execStackToInlineArray", + "execStackToValueArray", MethodType.methodType(boolean.class), CODE -> { Label loop1 = CODE.newLabel(); @@ -468,12 +468,12 @@ static void testExecutionStackToInlineArray(Class inlineClass, Class conta .invokespecial(containerClassDesc, "", MethodTypeDesc.ofDescriptor("()V")) .astore(1) .ldc(ITERATIONS * 3) - .anewarray(inlineClassDesc) + .anewarray(valueClassDesc) .astore(2) .aload(2) .aload(1) .swap() - .putfield(containerClassDesc, "valueArray", inlineClassDesc.arrayType()) + .putfield(containerClassDesc, "valueArray", valueClassDesc.arrayType()) .iconst_0() .istore(3) .labelBinding(loop1) @@ -482,19 +482,19 @@ static void testExecutionStackToInlineArray(Class inlineClass, Class conta .if_icmpge(end1) .aload(2) .iload(3) - .invokestatic(inlineClassDesc, "getInstance", voidReturnClass) + .invokestatic(valueClassDesc, "getInstance", voidReturnClass) .aastore() .iinc(3, 1) .aload(2) .iload(3) - .invokestatic(inlineClassDesc, "getNonBufferedInstance", voidReturnClass) + .invokestatic(valueClassDesc, "getNonBufferedInstance", voidReturnClass) .aastore() .iinc(3, 1) .aload(2) .iload(3) - .new_(inlineClassDesc) + .new_(valueClassDesc) .dup() - .invokespecial(inlineClassDesc, "", MethodTypeDesc.ofDescriptor("()V")) + .invokespecial(valueClassDesc, "", MethodTypeDesc.ofDescriptor("()V")) .aastore() .iinc(3, 1) .goto_(loop1) @@ -509,7 +509,7 @@ static void testExecutionStackToInlineArray(Class inlineClass, Class conta .aload(2) .iload(3) .aaload() - .invokevirtual(inlineClassDesc, "verify", MethodTypeDesc.ofDescriptor("()Z")) + .invokevirtual(valueClassDesc, "verify", MethodTypeDesc.ofDescriptor("()Z")) .iconst_1() .if_icmpne(failed) .iinc(3, 1) @@ -521,7 +521,7 @@ static void testExecutionStackToInlineArray(Class inlineClass, Class conta .iconst_0() .return_(TypeKind.BOOLEAN); }); - boolean result = (boolean) fromExecStackToInlineArray.invokeExact(); + boolean result = (boolean) fromExecStackToValueArray.invokeExact(); System.out.println(result); assertTrue(result, "Invariant"); } diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineWithJni.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueWithJni.java similarity index 97% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineWithJni.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueWithJni.java index f01f8b95c062..2d96952c7774 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineWithJni.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/ValueWithJni.java @@ -21,7 +21,7 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; /* @test * @summary test JNI functions with instances of value classes @@ -29,7 +29,7 @@ * @modules java.base/jdk.internal.vm.annotation * java.base/jdk.internal.value * @enablePreview - * @run main/othervm/native --enable-native-access=ALL-UNNAMED -XX:+UnlockDiagnosticVMOptions -XX:+UseNullableAtomicValueFlattening runtime.valhalla.inlinetypes.InlineWithJni + * @run main/othervm/native --enable-native-access=ALL-UNNAMED -XX:+UnlockDiagnosticVMOptions -XX:+UseNullableAtomicValueFlattening runtime.valhalla.valuetypes.ValueWithJni */ @@ -41,13 +41,13 @@ import jdk.test.lib.Asserts; -public value class InlineWithJni { +public value class ValueWithJni { static int returnValue = 999; static final int JNI_ERR = -1; // from jni.h static { - System.loadLibrary("InlineWithJni"); + System.loadLibrary("ValueWithJni"); } public static void main(String[] args) { @@ -58,7 +58,7 @@ public static void main(String[] args) { final int x; - public InlineWithJni(int x) { + public ValueWithJni(int x) { this.x = x; } @@ -69,14 +69,14 @@ public static void testJniMonitorOps() { boolean sawIe = false; boolean sawImse = false; try { - new InlineWithJni(0).doJniMonitorEnter(); + new ValueWithJni(0).doJniMonitorEnter(); } catch (IdentityException ie) { sawIe = true; } Asserts.assertTrue(sawIe, "Missing IdentityException"); Asserts.assertEQ(returnValue, JNI_ERR); try { - new InlineWithJni(0).doJniMonitorExit(); + new ValueWithJni(0).doJniMonitorExit(); } catch (IllegalMonitorStateException imse) { sawImse = true; } diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/VarArgsArray.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/VarArgsArray.java similarity index 96% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/VarArgsArray.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/VarArgsArray.java index b088f2d472a1..4238c86083b7 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/VarArgsArray.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/VarArgsArray.java @@ -22,7 +22,7 @@ */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; import java.lang.reflect.*; import static jdk.test.lib.Asserts.*; @@ -31,13 +31,13 @@ /* * @test VarArgsArray - * @summary Test if JVM API using varargs work with inline type arrays + * @summary Test if JVM API using varargs work with value type arrays * @modules java.base/jdk.internal.value * @library /test/lib * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile VarArgsArray.java - * @run main runtime.valhalla.inlinetypes.VarArgsArray + * @run main runtime.valhalla.valuetypes.VarArgsArray */ @LooselyConsistentValue @@ -95,7 +95,7 @@ public VarArgsArray() { } public void test() throws Throwable { - // test publicly accessable API in the VM...given an inline type array + // test publicly accessable API in the VM...given a value type array testJvmInvokeMethod(); testJvmNewInstanceFromConstructor(); } @@ -143,7 +143,7 @@ public void testJvmInvokeMethod() throws Throwable { } public void testJvmNewInstanceFromConstructor() throws Throwable { - // Inner classes use outer in param list, so these won't exercise inline type array + // Inner classes use outer in param list, so these won't exercise value type array Class tc = NewInstanceFromConstructor.class; Class pt = IntValue.class; Constructor consARef = tc.getConstructor(pt); diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/VolatileTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/VolatileTest.java similarity index 96% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/VolatileTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/VolatileTest.java index 60ff3d5c3af8..6fb6b1ceb6f7 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/VolatileTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/VolatileTest.java @@ -21,7 +21,7 @@ * questions. */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; /* * @test VolatileTest @@ -31,7 +31,7 @@ * @library /test/lib * @enablePreview * @compile VolatileTest.java - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening runtime.valhalla.inlinetypes.VolatileTest + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening runtime.valhalla.valuetypes.VolatileTest */ import jdk.internal.misc.Unsafe; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/WrappersOffsetTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/WrappersOffsetTest.java similarity index 88% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/WrappersOffsetTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/WrappersOffsetTest.java index 963db88aea3c..a1fb9d7788ba 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/WrappersOffsetTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/WrappersOffsetTest.java @@ -26,59 +26,59 @@ * @test id=nf-na-nn * @summary Test verification of wrappers classes' field offset with various layout * @enablePreview - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-UseFieldFlattening -XX:-UseArrayFlattening -XX:-UseNullableAtomicValueFlattening runtime.valhalla.inlinetypes.WrappersOffsetTest + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-UseFieldFlattening -XX:-UseArrayFlattening -XX:-UseNullableAtomicValueFlattening runtime.valhalla.valuetypes.WrappersOffsetTest */ /* * @test id=nf-na-n * @summary Test verification of wrappers classes' field offset with various layout * @enablePreview - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-UseFieldFlattening -XX:-UseArrayFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.inlinetypes.WrappersOffsetTest + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-UseFieldFlattening -XX:-UseArrayFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.valuetypes.WrappersOffsetTest */ /* * @test id=nf-a-nn * @summary Test verification of wrappers classes' field offset with various layout * @enablePreview - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-UseFieldFlattening -XX:+UseArrayFlattening -XX:-UseNullableAtomicValueFlattening runtime.valhalla.inlinetypes.WrappersOffsetTest + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-UseFieldFlattening -XX:+UseArrayFlattening -XX:-UseNullableAtomicValueFlattening runtime.valhalla.valuetypes.WrappersOffsetTest */ /* * @test id=f-na-nn * @summary Test verification of wrappers classes' field offset with various layout * @enablePreview - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening -XX:-UseArrayFlattening -XX:-UseNullableAtomicValueFlattening runtime.valhalla.inlinetypes.WrappersOffsetTest + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening -XX:-UseArrayFlattening -XX:-UseNullableAtomicValueFlattening runtime.valhalla.valuetypes.WrappersOffsetTest */ /* * @test id=f-na-n * @summary Test verification of wrappers classes' field offset with various layout * @enablePreview - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening -XX:-UseArrayFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.inlinetypes.WrappersOffsetTest + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening -XX:-UseArrayFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.valuetypes.WrappersOffsetTest */ /* * @test id=nf-a-n * @summary Test verification of wrappers classes' field offset with various layout * @enablePreview - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-UseFieldFlattening -XX:+UseArrayFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.inlinetypes.WrappersOffsetTest + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-UseFieldFlattening -XX:+UseArrayFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.valuetypes.WrappersOffsetTest */ /* * @test id=f-a-nn * @summary Test verification of wrappers classes' field offset with various layout * @enablePreview - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening -XX:+UseArrayFlattening -XX:-UseNullableAtomicValueFlattening runtime.valhalla.inlinetypes.WrappersOffsetTest + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening -XX:+UseArrayFlattening -XX:-UseNullableAtomicValueFlattening runtime.valhalla.valuetypes.WrappersOffsetTest */ /* * @test id=f-a-n * @summary Test verification of wrappers classes' field offset with various layout * @enablePreview - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening -XX:+UseArrayFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.inlinetypes.WrappersOffsetTest + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseFieldFlattening -XX:+UseArrayFlattening -XX:+UseNullableAtomicValueFlattening runtime.valhalla.valuetypes.WrappersOffsetTest */ -package runtime.valhalla.inlinetypes; +package runtime.valhalla.valuetypes; public class WrappersOffsetTest { public static void main(String[] args) { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classfileparser/IllegalFieldModifiers.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classfileparser/IllegalFieldModifiers.java similarity index 94% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/classfileparser/IllegalFieldModifiers.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/classfileparser/IllegalFieldModifiers.java index 4d6f9970d8b3..0490fee0e2c8 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classfileparser/IllegalFieldModifiers.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classfileparser/IllegalFieldModifiers.java @@ -26,10 +26,10 @@ * @summary test that illegal field modifiers are detected correctly * @enablePreview * @compile fieldModifiersTest.jcod - * @run main/othervm -Xverify:remote runtime.valhalla.inlinetypes.classfileparser.IllegalFieldModifiers + * @run main/othervm -Xverify:remote runtime.valhalla.valuetypes.classfileparser.IllegalFieldModifiers */ -package runtime.valhalla.inlinetypes.classfileparser; +package runtime.valhalla.valuetypes.classfileparser; public class IllegalFieldModifiers { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classfileparser/LDTest.jcod b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classfileparser/LDTest.jcod similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/classfileparser/LDTest.jcod rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/classfileparser/LDTest.jcod diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classfileparser/NullRestrictionWithoutPreview.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classfileparser/NullRestrictionWithoutPreview.java similarity index 97% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/classfileparser/NullRestrictionWithoutPreview.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/classfileparser/NullRestrictionWithoutPreview.java index f5d28f98ee71..e92634a2a9b8 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classfileparser/NullRestrictionWithoutPreview.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classfileparser/NullRestrictionWithoutPreview.java @@ -30,7 +30,7 @@ * @run main/othervm --enable-preview ${test.main.class} */ -package runtime.valhalla.inlinetypes.classfileparser; +package runtime.valhalla.valuetypes.classfileparser; import jdk.internal.vm.annotation.NullRestricted; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classfileparser/TestIllegalLoadableDescriptors.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classfileparser/TestIllegalLoadableDescriptors.java similarity index 92% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/classfileparser/TestIllegalLoadableDescriptors.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/classfileparser/TestIllegalLoadableDescriptors.java index 73f743069394..dd6fd0042c86 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classfileparser/TestIllegalLoadableDescriptors.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classfileparser/TestIllegalLoadableDescriptors.java @@ -26,10 +26,10 @@ * @summary test a LoadableDescriptors attribute with an invalid entry * @enablePreview * @compile LDTest.jcod TestIllegalLoadableDescriptors.java - * @run main runtime.valhalla.inlinetypes.classfileparser.TestIllegalLoadableDescriptors + * @run main runtime.valhalla.valuetypes.classfileparser.TestIllegalLoadableDescriptors */ -package runtime.valhalla.inlinetypes.classfileparser; +package runtime.valhalla.valuetypes.classfileparser; public class TestIllegalLoadableDescriptors { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classfileparser/ValueClassValidation.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classfileparser/ValueClassValidation.java similarity index 97% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/classfileparser/ValueClassValidation.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/classfileparser/ValueClassValidation.java index d56663e2b315..f0e0ecdc40ec 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classfileparser/ValueClassValidation.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classfileparser/ValueClassValidation.java @@ -26,10 +26,10 @@ * @summary test validation of value classes * @enablePreview * @compile cfpValueClassValidation.jcod - * @run main/othervm -Xverify:remote runtime.valhalla.inlinetypes.classfileparser.ValueClassValidation + * @run main/othervm -Xverify:remote runtime.valhalla.valuetypes.classfileparser.ValueClassValidation */ -package runtime.valhalla.inlinetypes.classfileparser; +package runtime.valhalla.valuetypes.classfileparser; import javax.management.RuntimeErrorException; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classfileparser/cfpValueClassValidation.jcod b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classfileparser/cfpValueClassValidation.jcod similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/classfileparser/cfpValueClassValidation.jcod rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/classfileparser/cfpValueClassValidation.jcod diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classfileparser/fieldModifiersTest.jcod b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classfileparser/fieldModifiersTest.jcod similarity index 99% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/classfileparser/fieldModifiersTest.jcod rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/classfileparser/fieldModifiersTest.jcod index 3ee889a6153b..41dc2e2712ba 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classfileparser/fieldModifiersTest.jcod +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classfileparser/fieldModifiersTest.jcod @@ -22,7 +22,7 @@ * */ - // This file contains multiple illegal inline type classes that should cause +// This file contains multiple illegal value type classes that should cause // ClassFormatError exceptions when attempted to be loaded. // // Many of these test were originally generated from this Java file and then diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/BigClassTreeClassLoader.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/BigClassTreeClassLoader.java similarity index 98% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/BigClassTreeClassLoader.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/BigClassTreeClassLoader.java index 7237d3cbc2eb..0725dcad1eaf 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/BigClassTreeClassLoader.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/BigClassTreeClassLoader.java @@ -26,10 +26,10 @@ * @test * @summary Sanity test for BigClassTreeClassLoader * @enablePreview - * @run main runtime.valhalla.inlinetypes.classloading.BigClassTreeClassLoader + * @run main runtime.valhalla.valuetypes.classloading.BigClassTreeClassLoader */ -package runtime.valhalla.inlinetypes.classloading; +package runtime.valhalla.valuetypes.classloading; import java.lang.classfile.*; import java.lang.classfile.attribute.*; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/Child.jcod b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/Child.jcod similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/Child.jcod rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/Child.jcod diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/ConcurrentClassLoadingTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/ConcurrentClassLoadingTest.java similarity index 97% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/ConcurrentClassLoadingTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/ConcurrentClassLoadingTest.java index 296e14495d45..b40c51678494 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/ConcurrentClassLoadingTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/ConcurrentClassLoadingTest.java @@ -30,10 +30,10 @@ * @library /test/lib * @enablePreview * @compile BigClassTreeClassLoader.java - * @run junit/othervm/timeout=480 -XX:ReservedCodeCacheSize=1G runtime.valhalla.inlinetypes.classloading.ConcurrentClassLoadingTest + * @run junit/othervm/timeout=480 -XX:ReservedCodeCacheSize=1G runtime.valhalla.valuetypes.classloading.ConcurrentClassLoadingTest */ -package runtime.valhalla.inlinetypes.classloading; +package runtime.valhalla.valuetypes.classloading; import java.util.Optional; import java.util.concurrent.BrokenBarrierException; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/InnerValue.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/InnerValue.java similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/InnerValue.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/InnerValue.java diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/LoadableDescriptorsTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/LoadableDescriptorsTest.java similarity index 95% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/LoadableDescriptorsTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/LoadableDescriptorsTest.java index d32c807ce87a..3a16bc59039c 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/LoadableDescriptorsTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/LoadableDescriptorsTest.java @@ -27,10 +27,10 @@ * @summary Ensures preloading. * @library /test/lib * @enablePreview - * @run junit runtime.valhalla.inlinetypes.classloading.LoadableDescriptorsTest + * @run junit runtime.valhalla.valuetypes.classloading.LoadableDescriptorsTest */ -package runtime.valhalla.inlinetypes.classloading; +package runtime.valhalla.valuetypes.classloading; import java.lang.classfile.ClassFile; import java.lang.classfile.attribute.LoadableDescriptorsAttribute; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/OuterValue.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/OuterValue.java similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/OuterValue.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/OuterValue.java diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/Parent.jcod b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/Parent.jcod similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/Parent.jcod rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/Parent.jcod diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/PreLoadCircularityTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/PreLoadCircularityTest.java similarity index 95% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/PreLoadCircularityTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/PreLoadCircularityTest.java index 765a7317ee46..1883d41f4c88 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/PreLoadCircularityTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/PreLoadCircularityTest.java @@ -28,10 +28,10 @@ * @summary Ensures circularity does not cause crashes. * @enablePreview * @compile BigClassTreeClassLoader.java - * @run junit runtime.valhalla.inlinetypes.classloading.PreLoadCircularityTest + * @run junit runtime.valhalla.valuetypes.classloading.PreLoadCircularityTest */ -package runtime.valhalla.inlinetypes.classloading; +package runtime.valhalla.valuetypes.classloading; import java.util.Optional; import java.util.stream.Stream; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/PreLoadDoesNotInitTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/PreLoadDoesNotInitTest.java similarity index 94% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/PreLoadDoesNotInitTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/PreLoadDoesNotInitTest.java index 99e1fb4f9928..ba6a44f56dde 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/PreLoadDoesNotInitTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/PreLoadDoesNotInitTest.java @@ -26,10 +26,10 @@ * @test * @summary Ensures that a value class is not initialized when preloaded. * @enablePreview - * @run junit runtime.valhalla.inlinetypes.classloading.PreLoadDoesNotInitTest + * @run junit runtime.valhalla.valuetypes.classloading.PreLoadDoesNotInitTest */ -package runtime.valhalla.inlinetypes.classloading; +package runtime.valhalla.valuetypes.classloading; import org.junit.jupiter.api.Test; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/PreLoadFailuresDoNotImpactApplicationTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/PreLoadFailuresDoNotImpactApplicationTest.java similarity index 97% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/PreLoadFailuresDoNotImpactApplicationTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/PreLoadFailuresDoNotImpactApplicationTest.java index cbec7ebcb702..f57be0a44a7b 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/PreLoadFailuresDoNotImpactApplicationTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/PreLoadFailuresDoNotImpactApplicationTest.java @@ -30,10 +30,10 @@ @compile OuterValue.java @compile InnerValue.java * @enablePreview - * @run junit runtime.valhalla.inlinetypes.classloading.PreLoadFailuresDoNotImpactApplicationTest + * @run junit runtime.valhalla.valuetypes.classloading.PreLoadFailuresDoNotImpactApplicationTest */ -package runtime.valhalla.inlinetypes.classloading; +package runtime.valhalla.valuetypes.classloading; import java.io.IOException; import java.lang.reflect.InvocationTargetException; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/ValueClassInheritanceTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/ValueClassInheritanceTest.java similarity index 94% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/ValueClassInheritanceTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/ValueClassInheritanceTest.java index 7b88bdb27f92..9547068238f9 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/classloading/ValueClassInheritanceTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/classloading/ValueClassInheritanceTest.java @@ -30,10 +30,10 @@ * @clean Child * @compile Parent.jcod * @compile Child.jcod - * @run junit runtime.valhalla.inlinetypes.classloading.ValueClassInheritanceTest + * @run junit runtime.valhalla.valuetypes.classloading.ValueClassInheritanceTest */ -package runtime.valhalla.inlinetypes.classloading; +package runtime.valhalla.valuetypes.classloading; import java.lang.reflect.InvocationTargetException; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ContendedValueClassInheritanceTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ContendedValueClassInheritanceTest.java similarity index 97% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ContendedValueClassInheritanceTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ContendedValueClassInheritanceTest.java index 4f56b9c75131..4931ffc547ea 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ContendedValueClassInheritanceTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ContendedValueClassInheritanceTest.java @@ -30,10 +30,10 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java ContendedValueClassInheritanceTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.ContendedValueClassInheritanceTest + * @run main runtime.valhalla.valuetypes.field_layout.ContendedValueClassInheritanceTest */ -package runtime.valhalla.inlinetypes.field_layout; +package runtime.valhalla.valuetypes.field_layout; import jdk.internal.vm.annotation.Contended; import jdk.test.lib.Asserts; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/EmptyValueTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/EmptyValueTest.java similarity index 98% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/EmptyValueTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/EmptyValueTest.java index 4589e0beeecb..0d400ea15846 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/EmptyValueTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/EmptyValueTest.java @@ -45,7 +45,7 @@ import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; -import runtime.valhalla.inlinetypes.field_layout.FieldLayoutAnalyzer; +import runtime.valhalla.valuetypes.field_layout.FieldLayoutAnalyzer; public class EmptyValueTest { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/FieldAlignmentTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/FieldAlignmentTest.java similarity index 95% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/FieldAlignmentTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/FieldAlignmentTest.java index 90324ea3dca8..fc2117cd0c26 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/FieldAlignmentTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/FieldAlignmentTest.java @@ -29,7 +29,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java FieldAlignmentTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.FieldAlignmentTest 32 + * @run main runtime.valhalla.valuetypes.field_layout.FieldAlignmentTest 32 */ /* @@ -40,7 +40,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java FieldAlignmentTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.FieldAlignmentTest 64_COOP_CCP_NCOH + * @run main runtime.valhalla.valuetypes.field_layout.FieldAlignmentTest 64_COOP_CCP_NCOH */ /* @@ -51,7 +51,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java FieldAlignmentTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.FieldAlignmentTest 64_NCOOP_CCP_NCOH + * @run main runtime.valhalla.valuetypes.field_layout.FieldAlignmentTest 64_NCOOP_CCP_NCOH */ /* @@ -62,7 +62,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java FieldAlignmentTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.FieldAlignmentTest 64_NCOOP_NCCP_NCOH + * @run main runtime.valhalla.valuetypes.field_layout.FieldAlignmentTest 64_NCOOP_NCCP_NCOH */ /* @@ -73,7 +73,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java FieldAlignmentTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.FieldAlignmentTest 64_COOP_CCP_COH + * @run main runtime.valhalla.valuetypes.field_layout.FieldAlignmentTest 64_COOP_CCP_COH */ /* @@ -84,10 +84,10 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java FieldAlignmentTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.FieldAlignmentTest 64_NCOOP_CCP_COH + * @run main runtime.valhalla.valuetypes.field_layout.FieldAlignmentTest 64_NCOOP_CCP_COH */ - package runtime.valhalla.inlinetypes.field_layout; + package runtime.valhalla.valuetypes.field_layout; import java.util.ArrayList; import java.util.Collections; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/FieldLayoutAnalyzer.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/FieldLayoutAnalyzer.java similarity index 99% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/FieldLayoutAnalyzer.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/FieldLayoutAnalyzer.java index cb99539e7836..39452dea94b3 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/FieldLayoutAnalyzer.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/FieldLayoutAnalyzer.java @@ -21,7 +21,7 @@ * questions. */ -package runtime.valhalla.inlinetypes.field_layout; +package runtime.valhalla.valuetypes.field_layout; import java.io.PrintStream; import java.util.ArrayList; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/NullMarkersTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/NullMarkersTest.java similarity index 94% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/NullMarkersTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/NullMarkersTest.java index 25142a23c9a6..84afee1105dd 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/NullMarkersTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/NullMarkersTest.java @@ -29,7 +29,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java NullMarkersTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.NullMarkersTest 32 + * @run main runtime.valhalla.valuetypes.field_layout.NullMarkersTest 32 */ /* @@ -40,7 +40,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java NullMarkersTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.NullMarkersTest 64_COOP_CCP_NCOH + * @run main runtime.valhalla.valuetypes.field_layout.NullMarkersTest 64_COOP_CCP_NCOH */ /* @@ -51,7 +51,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java NullMarkersTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.NullMarkersTest 64_NCOOP_CCP_NCOH + * @run main runtime.valhalla.valuetypes.field_layout.NullMarkersTest 64_NCOOP_CCP_NCOH */ /* @@ -62,7 +62,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java NullMarkersTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.NullMarkersTest 64_NCOOP_NCCP_NCOH + * @run main runtime.valhalla.valuetypes.field_layout.NullMarkersTest 64_NCOOP_NCCP_NCOH */ /* @@ -73,7 +73,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java NullMarkersTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.NullMarkersTest 64_COOP_CCP_COH + * @run main runtime.valhalla.valuetypes.field_layout.NullMarkersTest 64_COOP_CCP_COH */ /* @@ -84,10 +84,10 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java NullMarkersTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.NullMarkersTest 64_NCOOP_CCP_COH + * @run main runtime.valhalla.valuetypes.field_layout.NullMarkersTest 64_NCOOP_CCP_COH */ -package runtime.valhalla.inlinetypes.field_layout; +package runtime.valhalla.valuetypes.field_layout; import java.util.ArrayList; import java.util.Collections; @@ -104,8 +104,8 @@ public class NullMarkersTest { -static final String pkg = "runtime/valhalla/inlinetypes/field_layout/"; -static final String pkg_path = "runtime.valhalla.inlinetypes.field_layout."; +static final String pkg = "runtime/valhalla/valuetypes/field_layout/"; +static final String pkg_path = "runtime.valhalla.valuetypes.field_layout."; static class TestRunner { public static void main(String[] args) throws Exception { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/StrictFinalTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/StrictFinalTest.java similarity index 99% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/StrictFinalTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/StrictFinalTest.java index 4b4c12c309b3..ea560898219e 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/StrictFinalTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/StrictFinalTest.java @@ -48,7 +48,7 @@ import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; -import runtime.valhalla.inlinetypes.field_layout.FieldLayoutAnalyzer; +import runtime.valhalla.valuetypes.field_layout.FieldLayoutAnalyzer; public class StrictFinalTest { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/TEST.properties b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/TEST.properties similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/TEST.properties rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/TEST.properties diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/TestAbstractValueTemplate.java.template b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/TestAbstractValueTemplate.java.template similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/TestAbstractValueTemplate.java.template rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/TestAbstractValueTemplate.java.template diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/TestLayoutFlags.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/TestLayoutFlags.java similarity index 90% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/TestLayoutFlags.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/TestLayoutFlags.java index be3d67f76a59..a99792192787 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/TestLayoutFlags.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/TestLayoutFlags.java @@ -28,7 +28,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java TestLayoutFlags.java - * @run main runtime.valhalla.inlinetypes.field_layout.TestLayoutFlags 0 + * @run main runtime.valhalla.valuetypes.field_layout.TestLayoutFlags 0 */ /* @@ -38,7 +38,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java TestLayoutFlags.java - * @run main runtime.valhalla.inlinetypes.field_layout.TestLayoutFlags 1 + * @run main runtime.valhalla.valuetypes.field_layout.TestLayoutFlags 1 */ /* @test id=TestLayoutFlags_2 @@ -47,7 +47,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java TestLayoutFlags.java - * @run main runtime.valhalla.inlinetypes.field_layout.TestLayoutFlags 2 + * @run main runtime.valhalla.valuetypes.field_layout.TestLayoutFlags 2 */ /* @test id=TestLayoutFlags_3 @@ -56,7 +56,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java TestLayoutFlags.java - * @run main runtime.valhalla.inlinetypes.field_layout.TestLayoutFlags 3 + * @run main runtime.valhalla.valuetypes.field_layout.TestLayoutFlags 3 */ /* @test id=TestLayoutFlags_4 @@ -65,7 +65,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java TestLayoutFlags.java - * @run main runtime.valhalla.inlinetypes.field_layout.TestLayoutFlags 4 + * @run main runtime.valhalla.valuetypes.field_layout.TestLayoutFlags 4 */ /* @test id=TestLayoutFlags_5 @@ -74,7 +74,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java TestLayoutFlags.java - * @run main runtime.valhalla.inlinetypes.field_layout.TestLayoutFlags 5 + * @run main runtime.valhalla.valuetypes.field_layout.TestLayoutFlags 5 */ /* @test id=TestLayoutFlags_6 @@ -83,7 +83,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java TestLayoutFlags.java - * @run main runtime.valhalla.inlinetypes.field_layout.TestLayoutFlags 6 + * @run main runtime.valhalla.valuetypes.field_layout.TestLayoutFlags 6 */ /* @test id=TestLayoutFlags_7 @@ -92,10 +92,10 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java TestLayoutFlags.java - * @run main runtime.valhalla.inlinetypes.field_layout.TestLayoutFlags 7 + * @run main runtime.valhalla.valuetypes.field_layout.TestLayoutFlags 7 */ -package runtime.valhalla.inlinetypes.field_layout; +package runtime.valhalla.valuetypes.field_layout; import java.util.ArrayList; import java.util.Collections; @@ -114,7 +114,7 @@ public class TestLayoutFlags { static class TestRunner { public static void main(String[] args) throws Exception { - Class testClass = Class.forName("runtime.valhalla.inlinetypes.field_layout.TestLayoutFlags"); + Class testClass = Class.forName("runtime.valhalla.valuetypes.field_layout.TestLayoutFlags"); Asserts.assertNotNull(testClass); Method[] testMethods = testClass.getMethods(); for (Method test : testMethods) { @@ -143,7 +143,7 @@ static public void test_0() { } static public void check_0(FieldLayoutAnalyzer fla) { - FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/inlinetypes/field_layout/TestLayoutFlags$Container0"); + FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/valuetypes/field_layout/TestLayoutFlags$Container0"); FieldLayoutAnalyzer.FieldBlock f0 = cl.getFieldFromName("val0", false); if (useNullableAtomicFlat) { Asserts.assertEquals(FieldLayoutAnalyzer.LayoutKind.NULLABLE_ATOMIC_FLAT, f0.layoutKind()); @@ -167,7 +167,7 @@ static public void test_1() { } static public void check_1(FieldLayoutAnalyzer fla) { - FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/inlinetypes/field_layout/TestLayoutFlags$Container1"); + FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/valuetypes/field_layout/TestLayoutFlags$Container1"); FieldLayoutAnalyzer.FieldBlock f0 = cl.getFieldFromName("val0", false); // volatile fields are never flattened Asserts.assertEquals(FieldLayoutAnalyzer.LayoutKind.NON_FLAT, f0.layoutKind()); @@ -188,7 +188,7 @@ static public void test_2() { } static public void check_2(FieldLayoutAnalyzer fla) { - FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/inlinetypes/field_layout/TestLayoutFlags$Container2"); + FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/valuetypes/field_layout/TestLayoutFlags$Container2"); FieldLayoutAnalyzer.FieldBlock f0 = cl.getFieldFromName("val0", false); if (useNonAtomicFlat) { Asserts.assertEquals(FieldLayoutAnalyzer.LayoutKind.NULL_FREE_NON_ATOMIC_FLAT, f0.layoutKind()); @@ -259,7 +259,7 @@ public static void main(String[] args) throws Exception { TestLayoutFlags vct = new TestLayoutFlags(); // Execute the test runner in charge of loading all test classes - ProcessBuilder pb = exec("runtime.valhalla.inlinetypes.field_layout.TestLayoutFlags$TestRunner"); + ProcessBuilder pb = exec("runtime.valhalla.valuetypes.field_layout.TestLayoutFlags$TestRunner"); OutputAnalyzer out = new OutputAnalyzer(pb.start()); // Checking the status of the process execution before trying to parse the output diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/TestValueTemplate.java.template b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/TestValueTemplate.java.template similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/TestValueTemplate.java.template rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/TestValueTemplate.java.template diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ValueClassGenerator.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ValueClassGenerator.java similarity index 99% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ValueClassGenerator.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ValueClassGenerator.java index 19df8db6bd12..b2135a37fcd8 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ValueClassGenerator.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ValueClassGenerator.java @@ -21,7 +21,7 @@ * questions. */ -package runtime.valhalla.inlinetypes.field_layout; +package runtime.valhalla.valuetypes.field_layout; import java.io.File; import java.io.FileNotFoundException; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ValueComparisonTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ValueComparisonTest.java similarity index 96% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ValueComparisonTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ValueComparisonTest.java index 2b5f7f011081..f773773ff299 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ValueComparisonTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ValueComparisonTest.java @@ -29,10 +29,10 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile ValueClassGenerator.java ValueComparisonTest.java - * @run main/othervm -XX:CompileCommand=exclude,ValueClass*::* runtime.valhalla.inlinetypes.field_layout.ValueComparisonTest + * @run main/othervm -XX:CompileCommand=exclude,ValueClass*::* runtime.valhalla.valuetypes.field_layout.ValueComparisonTest */ -package runtime.valhalla.inlinetypes.field_layout; +package runtime.valhalla.valuetypes.field_layout; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ValueCompositionTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ValueCompositionTest.java similarity index 91% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ValueCompositionTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ValueCompositionTest.java index 6179dd77c2e3..a420d2f0683f 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ValueCompositionTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ValueCompositionTest.java @@ -28,7 +28,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java ValueCompositionTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.ValueCompositionTest 0 + * @run main runtime.valhalla.valuetypes.field_layout.ValueCompositionTest 0 */ /* @@ -38,7 +38,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java ValueCompositionTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.ValueCompositionTest 1 + * @run main runtime.valhalla.valuetypes.field_layout.ValueCompositionTest 1 */ /* @test id=ValueCompositionTest_no_atomic_flat_and_nullable_flat @@ -47,7 +47,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java ValueCompositionTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.ValueCompositionTest 2 + * @run main runtime.valhalla.valuetypes.field_layout.ValueCompositionTest 2 */ /* @test id=ValueCompositionTest_atomic_flat_and_no_nullable_atomic_flat_and_no_nullable_nonatomic_flat @@ -56,7 +56,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java ValueCompositionTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.ValueCompositionTest 3 + * @run main runtime.valhalla.valuetypes.field_layout.ValueCompositionTest 3 */ /* @test id=ValueCompositionTest_no_atomic_flat_and_nullable_atomic_flat_and_no_nullable_non_atomic_flat @@ -65,7 +65,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java ValueCompositionTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.ValueCompositionTest 4 + * @run main runtime.valhalla.valuetypes.field_layout.ValueCompositionTest 4 */ /* @test id=ValueCompositionTest_no_atomic_flat_and_nullable_atomic_flat_and_nullable_non_atomic_flat @@ -74,10 +74,10 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java ValueCompositionTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.ValueCompositionTest 5 + * @run main runtime.valhalla.valuetypes.field_layout.ValueCompositionTest 5 */ -package runtime.valhalla.inlinetypes.field_layout; +package runtime.valhalla.valuetypes.field_layout; import java.util.ArrayList; import java.util.Collections; @@ -96,7 +96,7 @@ public class ValueCompositionTest { static class TestRunner { public static void main(String[] args) throws Exception { - Class testClass = Class.forName("runtime.valhalla.inlinetypes.field_layout.ValueCompositionTest"); + Class testClass = Class.forName("runtime.valhalla.valuetypes.field_layout.ValueCompositionTest"); Asserts.assertNotNull(testClass); Method[] testMethods = testClass.getMethods(); for (Method test : testMethods) { @@ -131,7 +131,7 @@ static public void test_0() { } static public void check_0(FieldLayoutAnalyzer fla) { - FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/inlinetypes/field_layout/ValueCompositionTest$Container0"); + FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/valuetypes/field_layout/ValueCompositionTest$Container0"); FieldLayoutAnalyzer.FieldBlock f0 = cl.getFieldFromName("val0", false); if (useAtomicFlat) { Asserts.assertEquals(FieldLayoutAnalyzer.LayoutKind.NULL_FREE_ATOMIC_FLAT, f0.layoutKind()); @@ -157,7 +157,7 @@ static public void test_1() { } static public void check_1(FieldLayoutAnalyzer fla) { - FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/inlinetypes/field_layout/ValueCompositionTest$Container1"); + FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/valuetypes/field_layout/ValueCompositionTest$Container1"); FieldLayoutAnalyzer.FieldBlock f = cl.getFieldFromName("val0", false); if (useAtomicFlat) { Asserts.assertEquals(FieldLayoutAnalyzer.LayoutKind.NULL_FREE_ATOMIC_FLAT, f.layoutKind()); @@ -187,7 +187,7 @@ static public void test_2() { // An atomic value should not be flattened in a non-atomic value static public void check_2(FieldLayoutAnalyzer fla) { - FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/inlinetypes/field_layout/ValueCompositionTest$Container2"); + FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/valuetypes/field_layout/ValueCompositionTest$Container2"); FieldLayoutAnalyzer.FieldBlock f = cl.getFieldFromName("val0", false); Asserts.assertEquals(FieldLayoutAnalyzer.LayoutKind.NON_FLAT, f.layoutKind()); FieldLayoutAnalyzer.FieldBlock f1 = cl.getFieldFromName("val1", false); @@ -216,7 +216,7 @@ static public void test_3() { } static public void check_3(FieldLayoutAnalyzer fla) { - FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/inlinetypes/field_layout/ValueCompositionTest$Container3"); + FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/valuetypes/field_layout/ValueCompositionTest$Container3"); FieldLayoutAnalyzer.FieldBlock f0 = cl.getFieldFromName("val0", false); Asserts.assertEquals(FieldLayoutAnalyzer.LayoutKind.NULL_FREE_NON_ATOMIC_FLAT, f0.layoutKind()); FieldLayoutAnalyzer.FieldBlock f1 = cl.getFieldFromName("val1", false); @@ -238,7 +238,7 @@ static public void test_4() { } static public void check_4(FieldLayoutAnalyzer fla) { - FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/inlinetypes/field_layout/ValueCompositionTest$Container4"); + FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/valuetypes/field_layout/ValueCompositionTest$Container4"); FieldLayoutAnalyzer.FieldBlock f0 = cl.getFieldFromName("val0", false); Asserts.assertEquals(FieldLayoutAnalyzer.LayoutKind.NULL_FREE_NON_ATOMIC_FLAT, f0.layoutKind()); FieldLayoutAnalyzer.FieldBlock f1 = cl.getFieldFromName("val1", false); @@ -263,7 +263,7 @@ static public void test_5() { } static public void check_5(FieldLayoutAnalyzer fla) { - FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/inlinetypes/field_layout/ValueCompositionTest$Container5"); + FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/valuetypes/field_layout/ValueCompositionTest$Container5"); FieldLayoutAnalyzer.FieldBlock f0 = cl.getFieldFromName("val0", false); Asserts.assertEquals(FieldLayoutAnalyzer.LayoutKind.NULL_FREE_NON_ATOMIC_FLAT, f0.layoutKind()); FieldLayoutAnalyzer.FieldBlock f1 = cl.getFieldFromName("val1", false); @@ -290,7 +290,7 @@ static public void test_6() { } static public void check_6(FieldLayoutAnalyzer fla) { - FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/inlinetypes/field_layout/ValueCompositionTest$Container6"); + FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/valuetypes/field_layout/ValueCompositionTest$Container6"); FieldLayoutAnalyzer.FieldBlock f0 = cl.getFieldFromName("val0", false); Asserts.assertEquals(FieldLayoutAnalyzer.LayoutKind.NULL_FREE_NON_ATOMIC_FLAT, f0.layoutKind()); FieldLayoutAnalyzer.FieldBlock f1 = cl.getFieldFromName("val1", false); @@ -312,7 +312,7 @@ static public void test_7() { } static public void check_7(FieldLayoutAnalyzer fla) { - FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/inlinetypes/field_layout/ValueCompositionTest$Container7"); + FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/valuetypes/field_layout/ValueCompositionTest$Container7"); FieldLayoutAnalyzer.FieldBlock f0 = cl.getFieldFromName("val0", false); Asserts.assertEquals(FieldLayoutAnalyzer.LayoutKind.NULL_FREE_NON_ATOMIC_FLAT, f0.layoutKind()); FieldLayoutAnalyzer.FieldBlock f1 = cl.getFieldFromName("val1", false); @@ -337,7 +337,7 @@ static public void test_8() { } static public void check_8(FieldLayoutAnalyzer fla) { - FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/inlinetypes/field_layout/ValueCompositionTest$Container8"); + FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/valuetypes/field_layout/ValueCompositionTest$Container8"); FieldLayoutAnalyzer.FieldBlock f0 = cl.getFieldFromName("val0", false); Asserts.assertEquals(FieldLayoutAnalyzer.LayoutKind.NULL_FREE_NON_ATOMIC_FLAT, f0.layoutKind()); FieldLayoutAnalyzer.FieldBlock f1 = cl.getFieldFromName("val1", false); @@ -381,7 +381,7 @@ static public void test_9() { } static public void check_9(FieldLayoutAnalyzer fla) { - FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/inlinetypes/field_layout/ValueCompositionTest$Container9"); + FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/valuetypes/field_layout/ValueCompositionTest$Container9"); if(useNullableNonAtomicFlat) { FieldLayoutAnalyzer.FieldBlock f2 = cl.getFieldFromName("f2", false); // Flat null-free naturally atomic value, should have a NULL_FREE_NON_ATOMIC_FLAT layout @@ -413,7 +413,7 @@ static public void test_10() { } static public void check_10(FieldLayoutAnalyzer fla) { - FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/inlinetypes/field_layout/ValueCompositionTest$Container10"); + FieldLayoutAnalyzer.ClassLayout cl = fla.getClassLayoutFromName("runtime/valhalla/valuetypes/field_layout/ValueCompositionTest$Container10"); if(useNullableNonAtomicFlat) { FieldLayoutAnalyzer.FieldBlock f0 = cl.getFieldFromName("f0", false); // Flat null-free empty value, should have a NULL_FREE_NON_ATOMIC_FLAT layout @@ -478,7 +478,7 @@ public static void main(String[] args) throws Exception { ValueCompositionTest vct = new ValueCompositionTest(); // Execute the test runner in charge of loading all test classes - ProcessBuilder pb = exec("runtime.valhalla.inlinetypes.field_layout.ValueCompositionTest$TestRunner"); + ProcessBuilder pb = exec("runtime.valhalla.valuetypes.field_layout.ValueCompositionTest$TestRunner"); OutputAnalyzer out = new OutputAnalyzer(pb.start()); // Checking the status of the process execution before trying to parse the output diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ValueFieldInheritanceTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ValueFieldInheritanceTest.java similarity index 91% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ValueFieldInheritanceTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ValueFieldInheritanceTest.java index 87fa4591d961..54d25755063d 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ValueFieldInheritanceTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ValueFieldInheritanceTest.java @@ -29,7 +29,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java ValueFieldInheritanceTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.ValueFieldInheritanceTest 32 + * @run main runtime.valhalla.valuetypes.field_layout.ValueFieldInheritanceTest 32 */ /* @@ -40,7 +40,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java ValueFieldInheritanceTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.ValueFieldInheritanceTest 64_COOP_CCP_NCOH + * @run main runtime.valhalla.valuetypes.field_layout.ValueFieldInheritanceTest 64_COOP_CCP_NCOH */ /* @@ -51,7 +51,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java ValueFieldInheritanceTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.ValueFieldInheritanceTest 64_NCOOP_CCP_NCOH + * @run main runtime.valhalla.valuetypes.field_layout.ValueFieldInheritanceTest 64_NCOOP_CCP_NCOH */ /* @@ -62,7 +62,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java ValueFieldInheritanceTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.ValueFieldInheritanceTest 64_NCOOP_NCCP_NCOH + * @run main runtime.valhalla.valuetypes.field_layout.ValueFieldInheritanceTest 64_NCOOP_NCCP_NCOH */ /* @@ -73,7 +73,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java ValueFieldInheritanceTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.ValueFieldInheritanceTest 64_COOP_CCP_COH + * @run main runtime.valhalla.valuetypes.field_layout.ValueFieldInheritanceTest 64_COOP_CCP_COH */ /* @@ -84,10 +84,10 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java ValueFieldInheritanceTest.java - * @run main runtime.valhalla.inlinetypes.field_layout.ValueFieldInheritanceTest 64_NCOOP_CCP_COH + * @run main runtime.valhalla.valuetypes.field_layout.ValueFieldInheritanceTest 64_NCOOP_CCP_COH */ -package runtime.valhalla.inlinetypes.field_layout; +package runtime.valhalla.valuetypes.field_layout; import java.util.ArrayList; import java.util.Collections; @@ -179,7 +179,7 @@ static public void test_0() { static class TestRunner { public static void main(String[] args) throws Exception { - Class testClass = Class.forName("runtime.valhalla.inlinetypes.field_layout.ValueFieldInheritanceTest"); + Class testClass = Class.forName("runtime.valhalla.valuetypes.field_layout.ValueFieldInheritanceTest"); Asserts.assertNotNull(testClass); Method[] testMethods = testClass.getMethods(); for (Method test : testMethods) { @@ -258,7 +258,7 @@ public static void main(String[] args) throws Exception { // Execute the test runner in charge of loading all test classes ProcessBuilder pb = exec(compressedOopsArg, compressedKlassPointersArg, compactObjectHeader, - "runtime.valhalla.inlinetypes.field_layout.ValueFieldInheritanceTest$TestRunner"); + "runtime.valhalla.valuetypes.field_layout.ValueFieldInheritanceTest$TestRunner"); OutputAnalyzer out = new OutputAnalyzer(pb.start()); // Checking the status of the process execution before trying to parse the output diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ValueObjectContainerTemplate.java.template b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ValueObjectContainerTemplate.java.template similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ValueObjectContainerTemplate.java.template rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ValueObjectContainerTemplate.java.template diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ValueObjectContainerTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ValueObjectContainerTest.java similarity index 97% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ValueObjectContainerTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ValueObjectContainerTest.java index 2fdee6abbc9e..308d6c5c7ee1 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ValueObjectContainerTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ValueObjectContainerTest.java @@ -30,10 +30,10 @@ * java.base/jdk.internal.misc * @enablePreview * @compile FieldLayoutAnalyzer.java ValueClassGenerator.java ValueObjectContainerTest.java - * @run main/othervm/timeout=2000 runtime.valhalla.inlinetypes.field_layout.ValueObjectContainerTest + * @run main/othervm/timeout=2000 runtime.valhalla.valuetypes.field_layout.ValueObjectContainerTest */ -package runtime.valhalla.inlinetypes.field_layout; +package runtime.valhalla.valuetypes.field_layout; import java.io.File; import java.io.FileNotFoundException; @@ -183,7 +183,7 @@ static void runContainerTestWithConfig(List containerFilesNames, default: throw new RuntimeException("Unrecognized configuration"); } String[] testArgs = new String[containerFilesNames.size()+1]; - testArgs[0] = "runtime.valhalla.inlinetypes.field_layout.ValueObjectContainerTest$TestRunner"; + testArgs[0] = "runtime.valhalla.valuetypes.field_layout.ValueObjectContainerTest$TestRunner"; System.arraycopy(containerFilesNames.toArray(), 0, testArgs, 1, containerFilesNames.size()); // Execute the test runner in charge of loading all test classes diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ValueRandomLayoutTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ValueRandomLayoutTest.java similarity index 96% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ValueRandomLayoutTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ValueRandomLayoutTest.java index 7d9a648291ac..d8a965bbfd49 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/field_layout/ValueRandomLayoutTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/field_layout/ValueRandomLayoutTest.java @@ -29,10 +29,10 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @compile FieldLayoutAnalyzer.java ValueClassGenerator.java ValueRandomLayoutTest.java - * @run main/othervm/timeout=2000 runtime.valhalla.inlinetypes.field_layout.ValueRandomLayoutTest + * @run main/othervm/timeout=2000 runtime.valhalla.valuetypes.field_layout.ValueRandomLayoutTest */ -package runtime.valhalla.inlinetypes.field_layout; +package runtime.valhalla.valuetypes.field_layout; import java.nio.file.Path; import java.util.ArrayList; @@ -134,7 +134,7 @@ static void runScenario(int config) throws Exception { String[] classNames = gen.getValueClassesNames().toArray(new String[0]); String[] testArgs = new String[classNames.length+1]; - testArgs[0] = "runtime.valhalla.inlinetypes.field_layout.ValueRandomLayoutTest$TestRunner"; + testArgs[0] = "runtime.valhalla.valuetypes.field_layout.ValueRandomLayoutTest$TestRunner"; System.arraycopy(classNames, 0, testArgs, 1, classNames.length); // Execute the test runner in charge of loading all test classes diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/libInheritedFlatFieldTest.c b/test/hotspot/jtreg/runtime/valhalla/valuetypes/libInheritedFlatFieldTest.c similarity index 81% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/libInheritedFlatFieldTest.c rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/libInheritedFlatFieldTest.c index 922dd82df3bd..fcbc2f512d97 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/libInheritedFlatFieldTest.c +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/libInheritedFlatFieldTest.c @@ -23,7 +23,7 @@ #include -#define VALUE_SIGNATURE "Lruntime/valhalla/inlinetypes/InheritedFlatFieldTest$Value;" +#define VALUE_SIGNATURE "Lruntime/valhalla/valuetypes/InheritedFlatFieldTest$Value;" #define BASE_FIELD_NAME "baseValue" #define DERIVED_FIELD_NAME "derivedValue" @@ -38,17 +38,17 @@ static jobject read_field(JNIEnv* env, jobject obj, const char* field_name) { } JNIEXPORT jobject JNICALL -Java_runtime_valhalla_inlinetypes_InheritedFlatFieldTest_readBaseValue(JNIEnv* env, jclass klass, jobject obj) { +Java_runtime_valhalla_valuetypes_InheritedFlatFieldTest_readBaseValue(JNIEnv* env, jclass klass, jobject obj) { return read_field(env, obj, BASE_FIELD_NAME); } JNIEXPORT jobject JNICALL -Java_runtime_valhalla_inlinetypes_InheritedFlatFieldTest_readDerivedValue(JNIEnv* env, jclass klass, jobject obj) { +Java_runtime_valhalla_valuetypes_InheritedFlatFieldTest_readDerivedValue(JNIEnv* env, jclass klass, jobject obj) { return read_field(env, obj, DERIVED_FIELD_NAME); } JNIEXPORT void JNICALL -Java_runtime_valhalla_inlinetypes_InheritedFlatFieldTest_writeBaseValue(JNIEnv* env, jclass klass, jobject obj, jobject value) { +Java_runtime_valhalla_valuetypes_InheritedFlatFieldTest_writeBaseValue(JNIEnv* env, jclass klass, jobject obj, jobject value) { jfieldID field_id = get_field_id(env, obj, BASE_FIELD_NAME); (*env)->SetObjectField(env, obj, field_id, value); } diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/libJNIAllocObject.c b/test/hotspot/jtreg/runtime/valhalla/valuetypes/libJNIAllocObject.c similarity index 91% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/libJNIAllocObject.c rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/libJNIAllocObject.c index 7bab2ed34775..3d0f0616dd47 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/libJNIAllocObject.c +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/libJNIAllocObject.c @@ -24,6 +24,6 @@ #include JNIEXPORT jobject JNICALL -Java_runtime_valhalla_inlinetypes_TestJNIAllocObject_allocObject(JNIEnv* env, jclass klass, jclass target) { +Java_runtime_valhalla_valuetypes_TestJNIAllocObject_allocObject(JNIEnv* env, jclass klass, jclass target) { return (*env)->AllocObject(env, target); } diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/libJNIHasIdentity.c b/test/hotspot/jtreg/runtime/valhalla/valuetypes/libJNIHasIdentity.c similarity index 91% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/libJNIHasIdentity.c rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/libJNIHasIdentity.c index d2044ae02e94..284dfd70f25a 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/libJNIHasIdentity.c +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/libJNIHasIdentity.c @@ -24,6 +24,6 @@ #include JNIEXPORT jboolean JNICALL -Java_runtime_valhalla_inlinetypes_TestJNIHasIdentity_hasIdentity(JNIEnv* env, jclass klass, jobject target) { +Java_runtime_valhalla_valuetypes_TestJNIHasIdentity_hasIdentity(JNIEnv* env, jclass klass, jobject target) { return (*env)->HasIdentity(env, target); } diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/libJNIIsSameObject.c b/test/hotspot/jtreg/runtime/valhalla/valuetypes/libJNIIsSameObject.c similarity index 90% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/libJNIIsSameObject.c rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/libJNIIsSameObject.c index 2291d3b82925..2e0fac41abcd 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/libJNIIsSameObject.c +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/libJNIIsSameObject.c @@ -27,6 +27,6 @@ #include JNIEXPORT jboolean JNICALL -Java_runtime_valhalla_inlinetypes_TestJNIIsSameObject_isSameObject(JNIEnv* env, jclass klass, jobject obj0, jobject obj1) { +Java_runtime_valhalla_valuetypes_TestJNIIsSameObject_isSameObject(JNIEnv* env, jclass klass, jobject obj0, jobject obj1) { return (*env)->IsSameObject(env, obj0, obj1); } diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/libJNINewWeakGlobalRef.c b/test/hotspot/jtreg/runtime/valhalla/valuetypes/libJNINewWeakGlobalRef.c similarity index 90% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/libJNINewWeakGlobalRef.c rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/libJNINewWeakGlobalRef.c index 3e083bdfdc70..7de2e1efd9a5 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/libJNINewWeakGlobalRef.c +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/libJNINewWeakGlobalRef.c @@ -24,6 +24,6 @@ #include JNIEXPORT void JNICALL -Java_runtime_valhalla_inlinetypes_TestJNINewWeakGlobalRef_newWeakGlobalRef(JNIEnv* env, jclass klass, jobject target) { +Java_runtime_valhalla_valuetypes_TestJNINewWeakGlobalRef_newWeakGlobalRef(JNIEnv* env, jclass klass, jobject target) { (*env)->NewWeakGlobalRef(env, target); } diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/libMonitorEnterTest.c b/test/hotspot/jtreg/runtime/valhalla/valuetypes/libMonitorEnterTest.c similarity index 84% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/libMonitorEnterTest.c rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/libMonitorEnterTest.c index 9460d4b21b52..f8b8b697c42e 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/libMonitorEnterTest.c +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/libMonitorEnterTest.c @@ -24,11 +24,11 @@ #include JNIEXPORT void JNICALL -Java_runtime_valhalla_inlinetypes_MonitorEnterTest_JNIMonitorEnter(JNIEnv* env, jclass klass, jobject target) { +Java_runtime_valhalla_valuetypes_MonitorEnterTest_JNIMonitorEnter(JNIEnv* env, jclass klass, jobject target) { (*env)->MonitorEnter(env, target); } JNIEXPORT void JNICALL -Java_runtime_valhalla_inlinetypes_MonitorEnterTest_JNIMonitorExit(JNIEnv* env, jclass klass, jobject target) { +Java_runtime_valhalla_valuetypes_MonitorEnterTest_JNIMonitorExit(JNIEnv* env, jclass klass, jobject target) { (*env)->MonitorExit(env, target); } diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/libInlineWithJni.c b/test/hotspot/jtreg/runtime/valhalla/valuetypes/libValueWithJni.c similarity index 82% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/libInlineWithJni.c rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/libValueWithJni.c index 3e6655bdbbec..2a46ed618dbc 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/libInlineWithJni.c +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/libValueWithJni.c @@ -24,7 +24,7 @@ #include JNIEXPORT void JNICALL -Java_runtime_valhalla_inlinetypes_InlineWithJni_doJniMonitorEnter(JNIEnv *env, jobject obj) { +Java_runtime_valhalla_valuetypes_ValueWithJni_doJniMonitorEnter(JNIEnv *env, jobject obj) { int ret = (*env)->MonitorEnter(env, obj); jclass class = (*env)->GetObjectClass(env, obj); jfieldID fieldId = (*env)->GetStaticFieldID(env, class, "returnValue", "I"); @@ -32,11 +32,11 @@ Java_runtime_valhalla_inlinetypes_InlineWithJni_doJniMonitorEnter(JNIEnv *env, j } JNIEXPORT void JNICALL -Java_runtime_valhalla_inlinetypes_InlineWithJni_doJniMonitorExit(JNIEnv *env, jobject obj) { +Java_runtime_valhalla_valuetypes_ValueWithJni_doJniMonitorExit(JNIEnv *env, jobject obj) { (*env)->MonitorExit(env, obj); } -JNIEXPORT jobject JNICALL Java_runtime_valhalla_inlinetypes_InlineWithJni_readInstanceField(JNIEnv *env, +JNIEXPORT jobject JNICALL Java_runtime_valhalla_valuetypes_ValueWithJni_readInstanceField(JNIEnv *env, jclass k, jobject obj, jstring name, jstring signature) { jclass class = (*env)->GetObjectClass(env, obj); jboolean copy; @@ -49,7 +49,7 @@ JNIEXPORT jobject JNICALL Java_runtime_valhalla_inlinetypes_InlineWithJni_readIn return ret; } -JNIEXPORT void JNICALL Java_runtime_valhalla_inlinetypes_InlineWithJni_writeInstanceField(JNIEnv *env, +JNIEXPORT void JNICALL Java_runtime_valhalla_valuetypes_ValueWithJni_writeInstanceField(JNIEnv *env, jclass k, jobject obj, jstring name, jstring signature, jobject value) { jclass class = (*env)->GetObjectClass(env, obj); @@ -63,12 +63,12 @@ JNIEXPORT void JNICALL Java_runtime_valhalla_inlinetypes_InlineWithJni_writeInst return; } -JNIEXPORT jobject JNICALL Java_runtime_valhalla_inlinetypes_InlineWithJni_readArrayElement(JNIEnv *env, +JNIEXPORT jobject JNICALL Java_runtime_valhalla_valuetypes_ValueWithJni_readArrayElement(JNIEnv *env, jclass k, jarray array, int index) { return (*env)->GetObjectArrayElement(env, array, index); } -JNIEXPORT void JNICALL Java_runtime_valhalla_inlinetypes_InlineWithJni_writeArrayElement(JNIEnv *env, +JNIEXPORT void JNICALL Java_runtime_valhalla_valuetypes_ValueWithJni_writeArrayElement(JNIEnv *env, jclass k, jarray array, int index, jobject value) { (*env)->SetObjectArrayElement(env, array, index, value); } \ No newline at end of file diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/BadChild.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/BadChild.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/BadChild.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/BadChild.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/BadChild1.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/BadChild1.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/BadChild1.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/BadChild1.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/Bnoinit_BAD.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/Bnoinit_BAD.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/Bnoinit_BAD.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/Bnoinit_BAD.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/Brbefore_BAD.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/Brbefore_BAD.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/Brbefore_BAD.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/Brbefore_BAD.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/ControlFlowAlias.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/ControlFlowAlias.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/ControlFlowAlias.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/ControlFlowAlias.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/ControlFlowChildBad.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/ControlFlowChildBad.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/ControlFlowChildBad.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/ControlFlowChildBad.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/Creflbefore_BAD.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/Creflbefore_BAD.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/Creflbefore_BAD.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/Creflbefore_BAD.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/Cwreflective_OK.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/Cwreflective_OK.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/Cwreflective_OK.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/Cwreflective_OK.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/EarlyLarvalFrameOrdering.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/EarlyLarvalFrameOrdering.jasm new file mode 100644 index 000000000000..7b1f27920587 --- /dev/null +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/EarlyLarvalFrameOrdering.jasm @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2026, 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. + */ + +public identity class EarlyLarvalFrameOrdering version 72:65535 +{ + strict Field x:I; + strict Field y:I; + + public Method "":"()V" + stack 2 locals 1 + { + goto L1; + + L1: stack_frame_type early_larval; + unset_fields x:"I", + y:"I"; + frame_type same; + goto Super; + + AfterInit: stack_frame_type full; + locals_map class EarlyLarvalFrameOrdering; + stack_map; + return; + + Super: stack_frame_type early_larval; + unset_fields x:"I", + y:"I"; + frame_type full; + locals_map this; + stack_map; + aload_0; + iconst_1; + putfield Field x:"I"; + aload_0; + iconst_1; + putfield Field y:"I"; + aload_0; + invokespecial Method java/lang/Object."":"()V"; + goto AfterInit; + } +} diff --git a/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/EarlyLarvalNoUninitThis.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/EarlyLarvalNoUninitThis.jasm new file mode 100644 index 000000000000..1173205a8507 --- /dev/null +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/EarlyLarvalNoUninitThis.jasm @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2026, 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. + */ + +public identity class EarlyLarvalNoUninitThis version 72:65535 +{ + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + goto L7; + L7: stack_frame_type early_larval; + unset_fields; + frame_type full; + locals_map class EarlyLarvalNoUninitThis; + stack_map; + return; + } +} diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/EarlyLarvalNonPreviewApp.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/EarlyLarvalNonPreviewApp.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/EarlyLarvalNonPreviewApp.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/EarlyLarvalNonPreviewApp.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/EarlyLarvalNonPreviewTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/EarlyLarvalNonPreviewTest.java similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/EarlyLarvalNonPreviewTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/EarlyLarvalNonPreviewTest.java diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/EarlyLarvalNotSubset.jcod b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/EarlyLarvalNotSubset.jcod similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/EarlyLarvalNotSubset.jcod rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/EarlyLarvalNotSubset.jcod diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/EndsInEarlyLarval.jcod b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/EndsInEarlyLarval.jcod similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/EndsInEarlyLarval.jcod rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/EndsInEarlyLarval.jcod diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/InvalidIndexInEarlyLarval.jcod b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/InvalidIndexInEarlyLarval.jcod similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/InvalidIndexInEarlyLarval.jcod rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/InvalidIndexInEarlyLarval.jcod diff --git a/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/LateOrdinaryStrictFrame.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/LateOrdinaryStrictFrame.jasm new file mode 100644 index 000000000000..500887b0eca0 --- /dev/null +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/LateOrdinaryStrictFrame.jasm @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2026, 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. + */ + +public identity class LateOrdinaryStrictFrame version 72:65535 +{ + strict Field x:I; + + public Method "":"()V" + stack 2 locals 1 + { + goto L1; + + L1: stack_frame_type early_larval; + unset_fields x:"I"; + frame_type same; + + goto Late; + + Super: + stack_frame_type early_larval; + unset_fields; + frame_type full; + locals_map this; + stack_map; + aload_0; + invokespecial Method java/lang/Object."":"()V"; + goto L2; + + L2: stack_frame_type full; + locals_map class LateOrdinaryStrictFrame; + stack_map; + return; + + Late: + stack_frame_type full; + locals_map this; + stack_map; + goto Super; + } +} diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/NestedEarlyLarval.jcod b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/NestedEarlyLarval.jcod similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/NestedEarlyLarval.jcod rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/NestedEarlyLarval.jcod diff --git a/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/NoUnsetFieldsSuper.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/NoUnsetFieldsSuper.jasm new file mode 100644 index 000000000000..75911caa3232 --- /dev/null +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/NoUnsetFieldsSuper.jasm @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2026, 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. + */ + +public identity class NoUnsetFieldsSuper version 72:65535 { + strict Field x:I; + + public Method "":"()V" + stack 2 locals 1 + { + goto Super; + + Super: + stack_frame_type early_larval; + unset_fields x:"I"; + frame_type full; + locals_map this; + stack_map; + aload_0; + iconst_1; + putfield x:"I"; + aload_0; + invokespecial Method java/lang/Object."":"()V"; + goto Done; + + Done: + stack_frame_type full; + locals_map class NoUnsetFieldsSuper; + stack_map; + return; + + Unreachable: + stack_frame_type full; + locals_map this; + stack_map; + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } +} diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/RedefineStrictFieldsTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/RedefineStrictFieldsTest.java similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/RedefineStrictFieldsTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/RedefineStrictFieldsTest.java diff --git a/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/StrictFieldNoEarlyLarval.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/StrictFieldNoEarlyLarval.jasm new file mode 100644 index 000000000000..b81a51beedb2 --- /dev/null +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/StrictFieldNoEarlyLarval.jasm @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2026, 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. + */ + +public identity class StrictFieldNoEarlyLarval version 72:65535 { + strict Field x:I; + + public Method "":"()V" + stack 2 locals 1 + { + goto Super; + + Super: + stack_frame_type early_larval; + unset_fields x:"I"; + frame_type same; + aload_0; + iconst_1; + putfield Field x:"I"; + aload_0; + invokespecial Method java/lang/Object."":"()V"; + goto Done; + + Done: + stack_frame_type full; + locals_map class StrictFieldNoEarlyLarval; + stack_map; + return; + + Unreachable: + stack_frame_type full; + locals_map this; + stack_map; + aload_0; + iconst_2; + putfield Field x:"I"; + return; + } +} diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/StrictFieldNotSubset.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/StrictFieldNotSubset.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/StrictFieldNotSubset.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/StrictFieldNotSubset.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/StrictFields.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/StrictFields.java similarity index 91% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/StrictFields.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/StrictFields.java index ac40b0967f9a..c2158874fd9b 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/StrictFields.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/StrictFields.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, 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,10 @@ * @test * @enablePreview * @compile strictFields.jasm - * @run main/othervm -Xverify:remote runtime.valhalla.inlinetypes.verifier.StrictFields + * @run main/othervm -Xverify:remote runtime.valhalla.valuetypes.verifier.StrictFields */ -package runtime.valhalla.inlinetypes.verifier; +package runtime.valhalla.valuetypes.verifier; public class StrictFields { public static void main(String[] args) throws Throwable { @@ -45,7 +45,7 @@ public static void main(String[] args) throws Throwable { throw new Error("VerifyError was not thrown as expected!"); } catch (VerifyError ve) { // Once strict non-final is possible, expect "Illegal use of putfield on a strict field" - if (!ve.getMessage().startsWith("All strict final fields must be initialized before super()")) { + if (!ve.getMessage().startsWith("All strict fields must be initialized before super()")) { throw new Error("Wrong VerifyError thrown", ve); } else { System.out.println("Expected VerifyError was thrown"); diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/StrictFieldsNew.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/StrictFieldsNew.java similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/StrictFieldsNew.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/StrictFieldsNew.java diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/StrictFieldsOld.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/StrictFieldsOld.java similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/StrictFieldsOld.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/StrictFieldsOld.java diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/StrictInstanceFieldsTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/StrictInstanceFieldsTest.java similarity index 87% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/StrictInstanceFieldsTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/StrictInstanceFieldsTest.java index 394f6eb0a676..b154c9e993c7 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/StrictInstanceFieldsTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/StrictInstanceFieldsTest.java @@ -34,6 +34,11 @@ * ControlFlowAlias.jasm * TryCatchChildBad.jasm * UninitThisOnStack.jasm + * EarlyLarvalNoUninitThis.jasm + * EarlyLarvalFrameOrdering.jasm + * LateOrdinaryStrictFrame.jasm + * NoUnsetFieldsSuper.jasm + * StrictFieldNoEarlyLarval.jasm * NestedEarlyLarval.jcod * EndsInEarlyLarval.jcod * EarlyLarvalNotSubset.jcod @@ -43,7 +48,7 @@ * StrictInstanceFieldsTest * Child ControlFlowChild TryCatchChild AssignedInConditionalChild * SwitchCaseChild NestedConstructorChild FinalChild - * @run main/othervm -Xlog:verification StrictInstanceFieldsTest + * @run main/othervm -Xlog:verification -Xverify:all StrictInstanceFieldsTest */ import java.util.Arrays; @@ -110,24 +115,30 @@ public static void main(String[] args) throws Exception { UninitThisOnStack c6 = new UninitThisOnStack(); System.out.println(c6); + EarlyLarvalFrameOrdering c7 = new EarlyLarvalFrameOrdering(); + System.out.println(c7); + + NoUnsetFieldsSuper c8 = new NoUnsetFieldsSuper(); + System.out.println(c8); + // -------------- // NEGATIVE TESTS // -------------- // Field not initialized before super call - negativeTest(BadChild.class, "All strict final fields must be initialized before super()"); + negativeTest(BadChild.class, "All strict fields must be initialized before super()"); // Field not initialized before super call - negativeTest(BadChild1.class, "All strict final fields must be initialized before super()"); + negativeTest(BadChild1.class, "All strict fields must be initialized before super()"); // Attempt to assign a strict field not present in the original set of unset fields - negativeTest(StrictFieldNotSubset.class, "Initializing unknown strict field"); + negativeTest(StrictFieldNotSubset.class, "Bad method call"); // Constructor with control flow but field is not initialized negativeTest(ControlFlowChildBad.class, "Inconsistent stackmap frames at branch target", true, false); // Constructor with control flow but field is not initialized and stackmap is malformed - negativeTest(ControlFlowAlias.class, "All strict final fields must be initialized before super()", false); + negativeTest(ControlFlowAlias.class, "All strict fields must be initialized before super()", false); // Constructor with try-catch but field is not initialized negativeTest(TryCatchChildBad.class, "Inconsistent stackmap frames at branch target"); @@ -135,6 +146,9 @@ public static void main(String[] args) throws Exception { // Early_Larval frame contains another early_larval instead of a base frame negativeTest(NestedEarlyLarval.class, "Early larval frame must be followed by a base frame", true, false); + // Frame nested inside early_larval does not have uninitializedThis flag + negativeTest(EarlyLarvalNoUninitThis.class, "Cannot have uninitialized strict fields without an uninitializedThis"); + // Stack map table ends in early_larval frame without base frame negativeTest(EndsInEarlyLarval.class, "Early larval frame must be followed by a base frame", true, false); @@ -144,6 +158,10 @@ public static void main(String[] args) throws Exception { // Early_larval frame includes a constant pool index that doesn't point to a NameAndType negativeTest(InvalidIndexInEarlyLarval.class, "Invalid constant pool index in early larval frame", true, false); + negativeTest(LateOrdinaryStrictFrame.class, "Inconsistent stackmap frames at branch target"); + + negativeTest(StrictFieldNoEarlyLarval.class, "Constructor must call super() or this() before return"); + System.out.println("Passed"); } } diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/StrictStaticFieldsTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/StrictStaticFieldsTest.java similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/StrictStaticFieldsTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/StrictStaticFieldsTest.java diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/StrictStaticTests.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/StrictStaticTests.java similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/StrictStaticTests.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/StrictStaticTests.java diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/TryCatchChildBad.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/TryCatchChildBad.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/TryCatchChildBad.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/TryCatchChildBad.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitThisAcmp.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitThisAcmp.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitThisAcmp.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitThisAcmp.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitThisAcmpOld.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitThisAcmpOld.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitThisAcmpOld.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitThisAcmpOld.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitThisIfNull.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitThisIfNull.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitThisIfNull.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitThisIfNull.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitThisIfNullOld.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitThisIfNullOld.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitThisIfNullOld.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitThisIfNullOld.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitThisOnStack.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitThisOnStack.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitThisOnStack.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitThisOnStack.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitializedAcmp.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitializedAcmp.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitializedAcmp.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitializedAcmp.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitializedAcmpOld.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitializedAcmpOld.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitializedAcmpOld.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitializedAcmpOld.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitializedIfNull.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitializedIfNull.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitializedIfNull.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitializedIfNull.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitializedIfNullOld.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitializedIfNullOld.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitializedIfNullOld.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitializedIfNullOld.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitializedThisVerificationTest.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitializedThisVerificationTest.java similarity index 93% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitializedThisVerificationTest.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitializedThisVerificationTest.java index c365ac679597..020108bb97bb 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/UninitializedThisVerificationTest.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/UninitializedThisVerificationTest.java @@ -29,10 +29,10 @@ * UninitializedIfNull.jasm UninitializedAcmp.jasm * UninitThisAcmpOld.jasm UninitThisIfNullOld.jasm * UninitializedAcmpOld.jasm UninitializedIfNullOld.jasm - * @run main/othervm -Xlog:verification runtime.valhalla.inlinetypes.verifier.UninitializedThisVerificationTest + * @run main/othervm -Xlog:verification runtime.valhalla.valuetypes.verifier.UninitializedThisVerificationTest */ -package runtime.valhalla.inlinetypes.verifier; +package runtime.valhalla.valuetypes.verifier; public class UninitializedThisVerificationTest { diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/VTAssignability.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/VTAssignability.java similarity index 81% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/VTAssignability.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/VTAssignability.java index 1b9b9f7cad18..ffa34313a991 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/VTAssignability.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/VTAssignability.java @@ -23,15 +23,15 @@ /* * @test - * @summary Test basic verifier assignability of inline types. + * @summary Test basic verifier assignability of value types. * @enablePreview * @compile VTAssignability.java - * @run main/othervm -Xverify:remote runtime.valhalla.inlinetypes.verifier.VTAssignability + * @run main/othervm -Xverify:remote runtime.valhalla.valuetypes.verifier.VTAssignability */ -package runtime.valhalla.inlinetypes.verifier; +package runtime.valhalla.valuetypes.verifier; -// Test that an inline type is assignable to itself, to java.lang.Object, +// Test that a value type is assignable to itself, to java.lang.Object, // to an abstract super type and to an interface, // interface II { } @@ -74,16 +74,16 @@ public static void main(String[] args) { VTAssignability a = new VTAssignability(3, 4); VTAssignability b = new VTAssignability(2, 4); - // Test assignability of an inline type to itself. + // Test assignability of a value type to itself. boolean res = a.isSameVTAssignability(b); - // Test assignability of an inline type to java.lang.Object. + // Test assignability of a value type to java.lang.Object. res = b.equals(a); - // Test assignability of an inline type to an abstract super type. + // Test assignability of a value type to an abstract super type. a.takesAbstractSuper(b); - // Test assignability of an inline type to an interface. + // Test assignability of a value type to an interface. a.takesInterface(b); } } diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/VTMonitor.java b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/VTMonitor.java similarity index 83% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/VTMonitor.java rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/VTMonitor.java index 585d57717f70..8543e2a863c8 100644 --- a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/VTMonitor.java +++ b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/VTMonitor.java @@ -24,13 +24,13 @@ /* * @test * @bug 8227373 - * @summary Test that verifier allows monitor operations on inline types. + * @summary Test that verifier allows monitor operations on value types. * @enablePreview * @compile VTMonitor.java - * @run main/othervm -Xverify:remote runtime.valhalla.inlinetypes.verifier.VTMonitor + * @run main/othervm -Xverify:remote runtime.valhalla.valuetypes.verifier.VTMonitor */ -package runtime.valhalla.inlinetypes.verifier; +package runtime.valhalla.valuetypes.verifier; public value final class VTMonitor { final int x; @@ -45,7 +45,7 @@ public static void main(String[] args) { Object a = new VTMonitor(3, 4); try { synchronized(a) { - throw new RuntimeException("Synchronization on inline type should fail"); + throw new RuntimeException("Synchronization on value type should fail"); } } catch (java.lang.IdentityException e) { // Expected diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/WriteAfterReadRefl.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/WriteAfterReadRefl.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/WriteAfterReadRefl.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/WriteAfterReadRefl.jasm diff --git a/test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/strictFields.jasm b/test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/strictFields.jasm similarity index 100% rename from test/hotspot/jtreg/runtime/valhalla/inlinetypes/verifier/strictFields.jasm rename to test/hotspot/jtreg/runtime/valhalla/valuetypes/verifier/strictFields.jasm diff --git a/test/hotspot/jtreg/serviceability/jvmti/ForceEarlyReturn/ForceEarlyReturnStrictInitFields.java b/test/hotspot/jtreg/serviceability/jvmti/ForceEarlyReturn/ForceEarlyReturnStrictInitFields.java new file mode 100644 index 000000000000..de0a1d9d28fe --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/ForceEarlyReturn/ForceEarlyReturnStrictInitFields.java @@ -0,0 +1,674 @@ +/* + * Copyright (c) 2026, 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 8387648 + * @summary Test ForceEarlyReturnVoid when the target thread's top frame is the class + * initializer, constructor or method of a class with strictly-initialized fields. + * @enablePreview + * @library /test/lib + * @build ${test.main.class} + * @run driver jdk.test.lib.helpers.StrictProcessor + * ForceEarlyReturnStrictInitFields$ConstructorBeforeAndAfterSuper1$TestClass + * ForceEarlyReturnStrictInitFields$ConstructorBeforeAndAfterSuper2$SuperClass + * ForceEarlyReturnStrictInitFields$ConstructorBeforeAndAfterSuper3$TestClass + * ForceEarlyReturnStrictInitFields$ConstructorBeforeAndAfterThis$TestClass + * ForceEarlyReturnStrictInitFields$MethodAfterSuper$TestClass + * ForceEarlyReturnStrictInitFields$MethodAfterInit$TestClass + * ForceEarlyReturnStrictInitFields$ClassInitializerBeforeSet$TestClass + * ForceEarlyReturnStrictInitFields$ClassInitializerAfterSet$TestClass + * @run junit/othervm/native --enable-native-access=ALL-UNNAMED -agentlib:ForceEarlyReturnStrictInitFields ${test.main.class} + */ + +import java.lang.invoke.MethodHandles; +import jdk.test.lib.helpers.StrictInit; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; +import static org.junit.jupiter.api.Assertions.*; + +class ForceEarlyReturnStrictInitFields { + + private static final int JVMTI_ERROR_NONE = 0; + private static final int JVMTI_ERROR_OPAQUE_FRAME = 32; + + /** + * Base class to test ForceEarlyReturnVoid. + */ + abstract class ForceEarlyReturnTest { + volatile boolean ready; + volatile boolean canContinue; + volatile Throwable exception; + + /** + * Starts a thread to execute the given action. The action is expected to spin + * at the given class/method. Once spinning, the thread is suspended and + * ForceEarlyReturnVoid is invoked to attempt to force it to return early. + * @return the return from ForceEarlyReturnVoid + */ + int test(Executable action, Class targetClass, String targetMethod) throws Exception { + assertFalse(ready, "Test already executed"); + Thread thread = Thread.ofPlatform().start(() -> { + try { + action.execute(); + } catch (Throwable ex) { + exception = ex; + } + }); + int err; + boolean suspended = false; + try { + // wait for target thread to spin + while (!ready) { + Thread.sleep(10); + } + assertEquals(JVMTI_ERROR_NONE, suspendThread(thread)); + suspended = true; + assertTopFrame(thread, targetClass, targetMethod); + err = forceEarlyReturnVoid(thread); + } finally { + canContinue = true; + if (suspended) resumeThread(thread); + thread.join(); + } + assertNull(exception, "target thread threw exception"); + return err; + } + } + + /** + * Test ForceEarlyReturnVoid when the target thread's top frame is the + * constructor of a class with a strictly-initialized instance field. + */ + @Nested + class ConstructorBeforeAndAfterSuper1 extends ForceEarlyReturnTest { + class TestClass { + @StrictInit + private int x; + + TestClass(ForceEarlyReturnTest test, int where) { + x = 100; + + // before super + if (where == 1) { + test.ready = true; + while (!test.canContinue) {} + } + + super(); + + // after super + if (where == 2) { + test.ready = true; + while (!test.canContinue) {} + } + } + } + + @Test + void testBeforeSuper() throws Exception { + int err = test(() -> new TestClass(this, 1), TestClass.class, ""); + assertEquals(JVMTI_ERROR_OPAQUE_FRAME, err); + } + + @Test + void testAfterSuper() throws Exception { + int err = test(() -> new TestClass(this, 2), TestClass.class, ""); + assertEquals(JVMTI_ERROR_OPAQUE_FRAME, err); + } + } + + /** + * Test ForceEarlyReturnVoid when the target thread's top frame is the + * constructor or super-constructor of a class with a strictly-initialized + * instance field. The strict field is declared in the super class. + */ + @Nested + class ConstructorBeforeAndAfterSuper2 extends ForceEarlyReturnTest { + class SuperClass { + @StrictInit + private int x; + + SuperClass(ForceEarlyReturnTest test, int where) { + x = 100; + + // before super + if (where == 1) { + test.ready = true; + while (!test.canContinue) {} + } + + super(); + + // after super + if (where == 2) { + test.ready = true; + while (!test.canContinue) {} + } + } + } + + class TestClass extends SuperClass { + TestClass(ForceEarlyReturnTest test, int where) { + // before super + if (where == 3) { + test.ready = true; + while (!test.canContinue) {} + } + + super(test, where); + + // after super + if (where == 4) { + test.ready = true; + while (!test.canContinue) {} + } + } + } + + @Test + void testBeforeSuperSuper() throws Exception { + int err = test(() -> new TestClass(this, 1), SuperClass.class, ""); + assertEquals(JVMTI_ERROR_OPAQUE_FRAME, err); + } + + @Test + void testAfterSuperSuper() throws Exception { + int err = test(() -> new TestClass(this, 2), SuperClass.class, ""); + assertEquals(JVMTI_ERROR_OPAQUE_FRAME, err); + } + + @Test + void testBeforeSuper() throws Exception { + int err = test(() -> new TestClass(this, 3), TestClass.class, ""); + assertEquals(JVMTI_ERROR_OPAQUE_FRAME, err); + } + + @Test + void testAfterSuper() throws Exception { + int err = test(() -> new TestClass(this, 4), TestClass.class, ""); + assertEquals(JVMTI_ERROR_OPAQUE_FRAME, err); + } + } + + /** + * Test ForceEarlyReturnVoid when the target thread's top frame is the + * constructor or super-constructor of a class with a strictly-initialized + * instance field. The strict field is declared in the sub class. + */ + @Nested + class ConstructorBeforeAndAfterSuper3 extends ForceEarlyReturnTest { + class SuperClass { + SuperClass(ForceEarlyReturnTest test, int where) { + // before super + if (where == 1) { + test.ready = true; + while (!test.canContinue) {} + } + + super(); + + // after super + if (where == 2) { + test.ready = true; + while (!test.canContinue) {} + } + } + } + + class TestClass extends SuperClass { + @StrictInit + private int x; + + TestClass(ForceEarlyReturnTest test, int where) { + x = 100; + + // before super + if (where == 3) { + test.ready = true; + while (!test.canContinue) {} + } + + super(test, where); + + // after super + if (where == 4) { + test.ready = true; + while (!test.canContinue) {} + } + } + } + + @Test + void testBeforeSuperSuper() throws Exception { + // no strict fields in SuperClass or its superclasses + int err = test(() -> new TestClass(this, 1), SuperClass.class, ""); + assertEquals(JVMTI_ERROR_NONE, err); + } + + @Test + void testAfterSuperSuper() throws Exception { + // no strict fields in SuperClass or its superclasses + int err = test(() -> new TestClass(this, 2), SuperClass.class, ""); + assertEquals(JVMTI_ERROR_NONE, err); + } + + @Test + void testBeforeSuper() throws Exception { + int err = test(() -> new TestClass(this, 3), TestClass.class, ""); + assertEquals(JVMTI_ERROR_OPAQUE_FRAME, err); + } + + @Test + void testAfterSuper() throws Exception { + int err = test(() -> new TestClass(this, 4), TestClass.class, ""); + assertEquals(JVMTI_ERROR_OPAQUE_FRAME, err); + } + } + + /** + * Test ForceEarlyReturnVoid when the target thread's top frame is the + * constructor of a class with a strictly-initialized instance field + * before it chains to another constructor to set the field. + */ + @Nested + class ConstructorBeforeAndAfterThis extends ForceEarlyReturnTest { + class TestClass { + @StrictInit + private int x; + + TestClass() { + x = 100; + super(); + } + + TestClass(ForceEarlyReturnTest test, int where) { + // before this + if (where == 1) { + test.ready = true; + while (!test.canContinue) {} + } + + this(); + + // after this + if (where == 2) { + test.ready = true; + while (!test.canContinue) {} + } + } + } + + @Test + void testBeforeThis() throws Exception { + int err = test(() -> new TestClass(this, 1), TestClass.class, ""); + assertEquals(JVMTI_ERROR_OPAQUE_FRAME, err); + } + + @Test + void testAfterThis() throws Exception { + int err = test(() -> new TestClass(this, 2), TestClass.class, ""); + assertEquals(JVMTI_ERROR_OPAQUE_FRAME, err); + } + } + + /** + * Test ForceEarlyReturnVoid when the target thread's top frame is the + * constructor of a value class with an instance field. Value classes + * rely upon strict field initialization. + */ + @Nested + class ValueClassConstructor1 extends ForceEarlyReturnTest { + value class TestClass { + private int x; + + TestClass(ForceEarlyReturnTest test, int where) { + x = 100; + + // before super + if (where == 1) { + test.ready = true; + while (!test.canContinue) {} + } + + super(); + + // after super + if (where == 2) { + test.ready = true; + while (!test.canContinue) {} + } + } + } + + @BeforeAll() + static void verifyPreconditions() throws Exception { + assertTrue(TestClass.class.getDeclaredField("x").isStrictInit(), + "expected to be strict field"); + } + + @Test + void testBeforeSuper() throws Exception { + int err = test(() -> new TestClass(this, 1), TestClass.class, ""); + assertEquals(JVMTI_ERROR_OPAQUE_FRAME, err); + } + + @Test + void testAfterSuper() throws Exception { + int err = test(() -> new TestClass(this, 2), TestClass.class, ""); + assertEquals(JVMTI_ERROR_OPAQUE_FRAME, err); + } + } + + /** + * Test ForceEarlyReturnVoid when the target thread's top frame is the + * constructor of a value class with no instance fields. + */ + @Nested + class ValueClassConstructor2 extends ForceEarlyReturnTest { + value class TestClass { + TestClass(ForceEarlyReturnTest test, int where) { + // before super + if (where == 1) { + test.ready = true; + while (!test.canContinue) {} + } + + super(); + + // after super + if (where == 2) { + test.ready = true; + while (!test.canContinue) {} + } + } + } + + @Test + void testBeforeSuper() throws Exception { + // no strict fields + int err = test(() -> new TestClass(this, 1), TestClass.class, ""); + assertEquals(JVMTI_ERROR_NONE, err); + } + + @Test + void testAfterSuper() throws Exception { + // no strict fields + int err = test(() -> new TestClass(this, 2), TestClass.class, ""); + assertEquals(JVMTI_ERROR_NONE, err); + } + } + + /** + * Test ForceEarlyReturnVoid when the target thread's top frame is the + * constructor of a record with an instance field. Record fields are strict + * fields when compiled with preview features enabled. + */ + @Nested + class RecordConstructor extends ForceEarlyReturnTest { + record TestClass(int x) { + TestClass(ForceEarlyReturnTest test, int where, int x) { + // before this + if (where == 1) { + test.ready = true; + while (!test.canContinue) {} + } + + this(x); + + // after this + if (where == 2) { + test.ready = true; + while (!test.canContinue) {} + } + } + } + + @BeforeAll() + static void verifyPreconditions() throws Exception { + assertTrue(TestClass.class.getDeclaredField("x").isStrictInit(), + "expected to be strict field"); + } + + @Test + void testBeforeThis() throws Exception { + int err = test(() -> new TestClass(this, 1, 100), TestClass.class, ""); + assertEquals(JVMTI_ERROR_OPAQUE_FRAME, err); + } + + @Test + void testAfterThis() throws Exception { + int err = test(() -> new TestClass(this, 2, 100), TestClass.class, ""); + assertEquals(JVMTI_ERROR_OPAQUE_FRAME, err); + } + } + + /** + * Test ForceEarlyReturnVoid when the target thread's top frame is a method + * invoked by the constructor of a class with a strictly-initialized instance + * field after super() is invoked. This test exercises the implementation for the + * case that the caller of the method that returns early is a constructor of a + * class with strictly-initialized fields. + */ + @Nested + class MethodAfterSuper extends ForceEarlyReturnTest { + static volatile boolean postInitFinished; + static volatile boolean initFinished; + + class TestClass { + @StrictInit + private int x; + + TestClass(MethodAfterSuper test) { + x = 100; + super(); + postInit(test); + initFinished = true; + } + + void postInit(MethodAfterSuper test) { + // spin here until ForceEarlyReturnVoid executes + test.ready = true; + while (!test.canContinue) {} + + // should not get here + postInitFinished = true; + } + } + + @Test + void test() throws Exception { + int err = test(() -> new TestClass(this), TestClass.class, "postInit"); + assertEquals(JVMTI_ERROR_NONE, err); + assertFalse(postInitFinished, "postInit method should have returned early"); + assertTrue(initFinished, " did not finish"); + } + } + + /** + * Test ForceEarlyReturnVoid when the target thread's top frame is a method of a + * class with a strictly-initialized instance field. This test ensures that force + * early is allowed when the top frame is a method of a class with + * strictly-initialized fields. + */ + @Nested + class MethodAfterInit extends ForceEarlyReturnTest { + static volatile boolean runFinished; + + class TestClass { + @StrictInit + private int x; + + TestClass() { + x = 100; + super(); + } + + void run(MethodAfterInit test) { + // spin here until ForceEarlyReturnVoid executes + test.ready = true; + while (!test.canContinue) {} + + // should not get here + runFinished = true; + } + } + + @Test + void test() throws Exception { + var obj = new TestClass(); + int err = test(() -> obj.run(this), TestClass.class, "run"); + assertEquals(JVMTI_ERROR_NONE, err); + assertFalse(runFinished, "run method should have returned early"); + } + } + + /** + * Test ForceEarlyReturnVoid when the target thread's top frame is the class + * initializer of a class with a strictly-initialized static field before + * the field is set. + */ + @Nested + class ClassInitializerBeforeSet { + static volatile boolean ready; + static volatile boolean canContinue; + static volatile boolean finished; + static volatile Throwable exception; + + class TestClass { + @StrictInit + private static int x; + + static { + // before strict field is initialized + ready = true; + while (!canContinue) {} + + x = 100; + finished = true; + } + } + + @Test + void test() throws Exception { + Thread thread = Thread.ofPlatform().start(() -> { + try { + MethodHandles.lookup().ensureInitialized(TestClass.class); + } catch (Throwable ex) { + exception = ex; + } + }); + boolean suspended = false; + try { + // wait for target thread to spin in class initializer + while (!ready) { + Thread.sleep(10); + } + assertEquals(JVMTI_ERROR_NONE, suspendThread(thread)); + suspended = true; + assertTopFrame(thread, TestClass.class, ""); + assertEquals(JVMTI_ERROR_OPAQUE_FRAME, forceEarlyReturnVoid(thread)); + } finally { + canContinue = true; + if (suspended) resumeThread(thread); + thread.join(); + } + assertTrue(finished, " should have completed"); + assertNull(exception, "no exception expected"); + assertEquals(100, TestClass.x); + } + } + + /** + * Test ForceEarlyReturnVoid when the target thread's top frame is the class + * initializer of a class with a strictly-initialized static field after + * the field is set. + */ + @Nested + class ClassInitializerAfterSet { + static volatile boolean ready; + static volatile boolean canContinue; + static volatile boolean finished; + static volatile Throwable exception; + + class TestClass { + @StrictInit + private static int x; + + static { + x = 100; + + // after strict field is initialized + ready = true; + while (!canContinue) {} + + finished = true; + } + } + + @Test + void test() throws Exception { + Thread thread = Thread.ofPlatform().start(() -> { + try { + MethodHandles.lookup().ensureInitialized(TestClass.class); + } catch (Throwable ex) { + exception = ex; + } + }); + boolean suspended = false; + try { + // wait for target thread to spin in class initializer + while (!ready) { + Thread.sleep(10); + } + assertEquals(JVMTI_ERROR_NONE, suspendThread(thread)); + suspended = true; + assertTopFrame(thread, TestClass.class, ""); + assertEquals(JVMTI_ERROR_OPAQUE_FRAME, forceEarlyReturnVoid(thread)); + } finally { + canContinue = true; + if (suspended) resumeThread(thread); + thread.join(); + } + assertTrue(finished, " should have completed"); + assertNull(exception, "no exception expected"); + assertEquals(100, TestClass.x); + } + } + + /** + * Asserts that the given thread's top frame is the expected class/method. + */ + static void assertTopFrame(Thread thread, Class clazz, String methodName) { + StackTraceElement[] stack = thread.getStackTrace(); + assertTrue(stack.length > 0); + assertEquals(clazz.getName(), stack[0].getClassName()); + assertEquals(methodName, stack[0].getMethodName()); + } + + static native int suspendThread(Thread thread); + static native int resumeThread(Thread thread); + static native int forceEarlyReturnVoid(Thread thread); +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/ForceEarlyReturn/ForceEarlyReturnValueClass.java b/test/hotspot/jtreg/serviceability/jvmti/ForceEarlyReturn/ForceEarlyReturnValueClass.java deleted file mode 100644 index 47c0e6a81661..000000000000 --- a/test/hotspot/jtreg/serviceability/jvmti/ForceEarlyReturn/ForceEarlyReturnValueClass.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @summary Test ForceEarlyReturnVoid when the target thread's top frame is a value class - * constructor, method or class initializer. - * @enablePreview - * @run junit/othervm/native --enable-native-access=ALL-UNNAMED -agentlib:ForceEarlyReturnValueClass ${test.main.class} - */ - -import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - -class ForceEarlyReturnValueClass { - - private static final int JVMTI_ERROR_NONE = 0; - private static final int JVMTI_ERROR_OPAQUE_FRAME = 32; - - /** - * Test that ForceEarlyReturnVoid fails with JVMTI_ERROR_OPAQUE_FRAME when the - * target thread's top frame is a value class constructor before super. - */ - @Test - void testForceEarlyReturnBeforeSuper() throws Exception { - class TestCase { - static volatile boolean initStarted; - static volatile boolean initFinished; - static volatile boolean stop; - static value class ValueClass { - ValueClass() { - TestCase.initStarted = true; - while (!TestCase.stop) {} - super(); - TestCase.initFinished = true; - } - } - } - Thread thread = Thread.ofPlatform().start(TestCase.ValueClass::new); - boolean suspended = false; - try { - // wait for target thread to start executing constructor - while (!TestCase.initStarted) { - Thread.sleep(10); - } - assertEquals(JVMTI_ERROR_NONE, suspendThread(thread)); - suspended = true; - assertTopFrame(thread, TestCase.ValueClass.class, ""); - assertEquals(JVMTI_ERROR_OPAQUE_FRAME, forceEarlyReturnVoid(thread)); - } finally { - TestCase.stop = true; - if (suspended) resumeThread(thread); - thread.join(); - } - assertTrue(TestCase.initFinished); // constructor should have run to end - } - - /** - * Test that ForceEarlyReturnVoid fails with JVMTI_ERROR_OPAQUE_FRAME when the - * target thread's top frame is a value class constructor after super. - * (This case may be allowed to succeed in the future) - */ - @Test - void testForceEarlyReturnAfterSuper() throws Exception { - class TestCase { - static volatile boolean afterSuperStarted; - static volatile boolean initFinished; - static volatile boolean stop; - static value class ValueClass { - ValueClass() { - super(); - TestCase.afterSuperStarted = true; - while (!TestCase.stop) {} - TestCase.initFinished = true; - } - } - } - Thread thread = Thread.ofPlatform().start(TestCase.ValueClass::new); - boolean suspended = false; - try { - // wait for target thread to start executing code after super - while (!TestCase.afterSuperStarted) { - Thread.sleep(10); - } - assertEquals(JVMTI_ERROR_NONE, suspendThread(thread)); - suspended = true; - assertTopFrame(thread, TestCase.ValueClass.class, ""); - assertEquals(JVMTI_ERROR_OPAQUE_FRAME, forceEarlyReturnVoid(thread)); - } finally { - TestCase.stop = true; - if (suspended) resumeThread(thread); - thread.join(); - } - assertTrue(TestCase.initFinished); // constructor should have run to end - } - - /** - * Test that ForceEarlyReturnVoid succeeds with the target thread's top frame is a - * method invoked from the constructor after super. - */ - @Test - void testForceEarlyReturnPostInit() throws Exception { - class TestCase { - static volatile boolean initFinished; - static volatile boolean postInitStarted; - static volatile boolean postInitFinished; - static volatile boolean stop; - static value class ValueClass { - ValueClass() { - super(); - postInit(); - TestCase.initFinished = true; - } - void postInit() { - TestCase.postInitStarted = true; - while (!TestCase.stop) {} - TestCase.postInitFinished = true; - } - } - } - Thread thread = Thread.ofPlatform().start(TestCase.ValueClass::new); - boolean suspended = false; - try { - // wait for target thread to start executing postInit method - while (!TestCase.postInitStarted) { - Thread.sleep(10); - } - assertEquals(JVMTI_ERROR_NONE, suspendThread(thread)); - assertTopFrame(thread, TestCase.ValueClass.class, "postInit"); - suspended = true; - assertEquals(JVMTI_ERROR_NONE, forceEarlyReturnVoid(thread)); - } finally { - TestCase.stop = true; - if (suspended) resumeThread(thread); - thread.join(); - } - assertFalse(TestCase.postInitFinished); // postInit should not have run to the end - assertTrue(TestCase.initFinished); // constructor should have run to end - } - - /** - * Test that ForceEarlyReturnVoid succeeds with the target thread's top frame is a - * value class method. - */ - @Test - void testForceEarlyReturnMethod() throws Exception { - class TestCase { - static volatile boolean runStarted; - static volatile boolean runFinished; - static volatile boolean stop; - static value class ValueClass { - void run() { - TestCase.runStarted = true; - while (!TestCase.stop) {} - TestCase.runFinished = true; // should not get there - } - } - } - var valueObj = new TestCase.ValueClass(); - Thread thread = Thread.ofPlatform().start(valueObj::run); - boolean suspended = false; - try { - // wait for target thread to start executing method - while (!TestCase.runStarted) { - Thread.sleep(10); - } - assertEquals(JVMTI_ERROR_NONE, suspendThread(thread)); - suspended = true; - assertTopFrame(thread, TestCase.ValueClass.class, "run"); - assertEquals(JVMTI_ERROR_NONE, forceEarlyReturnVoid(thread)); - } finally { - TestCase.stop = true; - if (suspended) resumeThread(thread); - thread.join(); - } - assertFalse(TestCase.runFinished); // should not have run to the end - } - - /** - * Test that ForceEarlyReturnVoid succeeds with the target thread's top frame is a - * value class clinit. - */ - @Test - void testForceEarlyReturnClassInitializer() throws Exception { - class TestCase { - static volatile boolean clinitStarted; - static volatile boolean stop; - static value class ValueClass { - static final boolean initialized; - static { - TestCase.clinitStarted = true; - while (!TestCase.stop) {} - initialized = true; // should not get there - } - } - } - Thread thread = Thread.ofPlatform().start(TestCase.ValueClass::new); - boolean suspended = false; - try { - // wait for target thread to start executing class initializer - while (!TestCase.clinitStarted) { - Thread.sleep(10); - } - assertEquals(JVMTI_ERROR_NONE, suspendThread(thread)); - suspended = true; - assertTopFrame(thread, TestCase.ValueClass.class, ""); - assertEquals(JVMTI_ERROR_NONE, forceEarlyReturnVoid(thread)); - } finally { - TestCase.stop = true; - if (suspended) resumeThread(thread); - thread.join(); - } - assertFalse(TestCase.ValueClass.initialized); // should not have run to the end - } - - /** - * Asserts that the given thread's top frame is the expected class/method. - */ - private void assertTopFrame(Thread thread, Class clazz, String methodName) { - StackTraceElement[] stack = thread.getStackTrace(); - assertTrue(stack.length > 0); - assertEquals(clazz.getName(), stack[0].getClassName()); - assertEquals(methodName, stack[0].getMethodName()); - } - - private static native int suspendThread(Thread thread); - private static native int resumeThread(Thread thread); - private static native int forceEarlyReturnVoid(Thread thread); - private static native int forceEarlyReturnObject(Thread thread, Object retObject); -} diff --git a/test/hotspot/jtreg/serviceability/jvmti/ForceEarlyReturn/libForceEarlyReturnValueClass.cpp b/test/hotspot/jtreg/serviceability/jvmti/ForceEarlyReturn/libForceEarlyReturnStrictInitFields.cpp similarity index 83% rename from test/hotspot/jtreg/serviceability/jvmti/ForceEarlyReturn/libForceEarlyReturnValueClass.cpp rename to test/hotspot/jtreg/serviceability/jvmti/ForceEarlyReturn/libForceEarlyReturnStrictInitFields.cpp index f160a896e058..700de48e4103 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/ForceEarlyReturn/libForceEarlyReturnValueClass.cpp +++ b/test/hotspot/jtreg/serviceability/jvmti/ForceEarlyReturn/libForceEarlyReturnStrictInitFields.cpp @@ -49,15 +49,15 @@ Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { return JNI_OK; } -JNIEXPORT jint Java_ForceEarlyReturnValueClass_suspendThread(JNIEnv *env, jclass ignore, jthread target) { +JNIEXPORT jint Java_ForceEarlyReturnStrictInitFields_suspendThread(JNIEnv *env, jclass ignore, jthread target) { return (jint) jvmti->SuspendThread(target); } -JNIEXPORT jint Java_ForceEarlyReturnValueClass_resumeThread(JNIEnv *env, jclass ignore, jthread target) { +JNIEXPORT jint Java_ForceEarlyReturnStrictInitFields_resumeThread(JNIEnv *env, jclass ignore, jthread target) { return (jint) jvmti->ResumeThread(target); } -JNIEXPORT jint Java_ForceEarlyReturnValueClass_forceEarlyReturnVoid(JNIEnv *env, jclass ignore, jthread target) { +JNIEXPORT jint Java_ForceEarlyReturnStrictInitFields_forceEarlyReturnVoid(JNIEnv *env, jclass ignore, jthread target) { return (jint) jvmti->ForceEarlyReturnVoid(target); } diff --git a/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetObjectHashCode/ValueGetObjectHashCodeTest.java b/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetObjectHashCode/ValueGetObjectHashCodeTest.java index 358329fdbf95..7cd506099da9 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetObjectHashCode/ValueGetObjectHashCodeTest.java +++ b/test/hotspot/jtreg/serviceability/jvmti/valhalla/GetObjectHashCode/ValueGetObjectHashCodeTest.java @@ -29,7 +29,7 @@ * @modules java.base/jdk.internal.vm.annotation * @enablePreview * @run main/othervm/native -agentlib:ValueGetObjectHashCodeTest - * -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlineLayout + * -XX:+UnlockDiagnosticVMOptions -XX:+PrintValueLayout * ValueGetObjectHashCodeTest */ diff --git a/test/hotspot/jtreg/serviceability/jvmti/valhalla/HeapDump/HeapDump.java b/test/hotspot/jtreg/serviceability/jvmti/valhalla/HeapDump/HeapDump.java index b69c72745252..821d626c73f1 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/valhalla/HeapDump/HeapDump.java +++ b/test/hotspot/jtreg/serviceability/jvmti/valhalla/HeapDump/HeapDump.java @@ -150,9 +150,9 @@ public static void main(String[] args) throws Throwable { try { theApp = new HeapDumpTarg(); - // -XX:+PrintInlineLayout is debug-only arg + // -XX:+PrintValueLayout is debug-only arg LingeredApp.startApp(theApp, "--enable-preview", "-XX:+UnlockDiagnosticVMOptions", - "-XX:+PrintInlineLayout", "-XX:+PrintFlatArrayLayout", + "-XX:+PrintValueLayout", "-XX:+PrintFlatArrayLayout", "--add-modules=java.base", "--add-exports=java.base/jdk.internal.value=ALL-UNNAMED"); diff --git a/test/hotspot/jtreg/serviceability/jvmti/valhalla/Heapwalking/ValueHeapwalkingTest.java b/test/hotspot/jtreg/serviceability/jvmti/valhalla/Heapwalking/ValueHeapwalkingTest.java index 6b7da750afa5..8a37814bec9d 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/valhalla/Heapwalking/ValueHeapwalkingTest.java +++ b/test/hotspot/jtreg/serviceability/jvmti/valhalla/Heapwalking/ValueHeapwalkingTest.java @@ -34,7 +34,7 @@ * -XX:+UseFieldFlattening * -XX:+UseNullFreeAtomicValueFlattening * -XX:+UseNullableAtomicValueFlattening - * -XX:+PrintInlineLayout + * -XX:+PrintValueLayout * -XX:+PrintFlatArrayLayout * -Xlog:jvmti+table * ValueHeapwalkingTest diff --git a/test/hotspot/jtreg/serviceability/jvmti/valhalla/SetTag/ValueTagMapTest.java b/test/hotspot/jtreg/serviceability/jvmti/valhalla/SetTag/ValueTagMapTest.java index 932bc2b08e68..2f897c162477 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/valhalla/SetTag/ValueTagMapTest.java +++ b/test/hotspot/jtreg/serviceability/jvmti/valhalla/SetTag/ValueTagMapTest.java @@ -29,7 +29,7 @@ * @enablePreview * @run main/othervm/native -agentlib:ValueTagMapTest * -XX:+UnlockDiagnosticVMOptions - * -XX:+PrintInlineLayout + * -XX:+PrintValueLayout * -XX:+PrintFlatArrayLayout * -Xlog:jvmti+table * ValueTagMapTest diff --git a/test/hotspot/jtreg/serviceability/sa/sadebugd/DebugdConnectTest.java b/test/hotspot/jtreg/serviceability/sa/sadebugd/DebugdConnectTest.java index 7576aa54bf0c..b22c9ba7f78d 100644 --- a/test/hotspot/jtreg/serviceability/sa/sadebugd/DebugdConnectTest.java +++ b/test/hotspot/jtreg/serviceability/sa/sadebugd/DebugdConnectTest.java @@ -65,14 +65,15 @@ private static OutputAnalyzer runJHSDB(String command, String serverID) throws I System.out.println(out.getStdout()); System.err.println(out.getStderr()); - return out; + return new OutputAnalyzer(out.getStdout(), + out.getStderrNoDeprecatedWarnings(), out.getExitValue()); } private static void runJSTACK(String serverID) throws IOException, InterruptedException { OutputAnalyzer out = runJHSDB("jstack", serverID); out.shouldContain("LingeredApp"); - out.stderrShouldBeEmptyIgnoreDeprecatedWarnings(); + out.stderrShouldBeEmptyIgnoreVMWarnings(); out.shouldHaveExitValue(0); } @@ -80,7 +81,7 @@ private static void runJMAP(String serverID) throws IOException, InterruptedExce OutputAnalyzer out = runJHSDB("jmap", serverID); out.shouldContain("JVM version is"); - out.stderrShouldBeEmptyIgnoreDeprecatedWarnings(); + out.stderrShouldBeEmptyIgnoreVMWarnings(); out.shouldHaveExitValue(0); } @@ -88,7 +89,7 @@ private static void runJINFO(String serverID) throws IOException, InterruptedExc OutputAnalyzer out = runJHSDB("jinfo", serverID); out.shouldContain("Java System Properties:"); - out.stderrShouldBeEmptyIgnoreDeprecatedWarnings(); + out.stderrShouldBeEmptyIgnoreVMWarnings(); out.shouldHaveExitValue(0); } @@ -96,7 +97,7 @@ private static void runJSNAP(String serverID) throws IOException, InterruptedExc OutputAnalyzer out = runJHSDB("jsnap", serverID); out.shouldContain("java.vm.name="); - out.stderrShouldBeEmptyIgnoreDeprecatedWarnings(); + out.stderrShouldBeEmptyIgnoreVMWarnings(); out.shouldHaveExitValue(0); } diff --git a/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java b/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java index 6c81db9e0ab8..d9facb130789 100644 --- a/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java +++ b/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java @@ -323,7 +323,6 @@ private String[] cmd(long classStart, long classStop) { "-XX:+StressMacroExpansion", "-XX:+StressMacroElimination", "-XX:+StressIncrementalInlining", - "-XX:+StressVerifyMeetJoin", // StressSeed is uint "-XX:StressSeed=" + rng.nextInt(Integer.MAX_VALUE), // Do not fail on huge methods where StressGCM makes register diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage007.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage007.java index c87542ddf702..812ffc405ede 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage007.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage007.java @@ -31,7 +31,7 @@ * DESCRIPTION * The test exercises JVMTI function GetObjectMonitorUsage. * COMMENTS - * This test checks that GetObjectMonitorUsage works with inline types and always + * This test checks that GetObjectMonitorUsage works with value types and always * returns information consistent with a never locked monitor * * @enablePreview diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 86cdbc4c8258..d6c6a3b2247a 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -224,9 +224,8 @@ sun/java2d/SunGraphics2D/SimplePrimQuality.java 6992007 generic-all sun/java2d/SunGraphics2D/SourceClippingBlitTest/SourceClippingBlitTest.java 8196185 generic-all java/awt/FullScreen/DisplayChangeVITest/DisplayChangeVITest.java 8169469,8273617 windows-all,macosx-aarch64 +java/awt/FullScreen/SetFSWindow/FSFrame.java#default 8390445 macosx-aarch64 java/awt/FullScreen/UninitializedDisplayModeChangeTest/UninitializedDisplayModeChangeTest.java 8273617 macosx-all -java/awt/print/PrinterJob/PSQuestionMark.java 7003378 generic-all -java/awt/print/PrinterJob/GlyphPositions.java 7003378 generic-all java/awt/Component/GetScreenLocTest/GetScreenLocTest.java 4753654 generic-all java/awt/Component/SetEnabledPerformance/SetEnabledPerformance.java 8165863 macosx-all java/awt/Clipboard/PasteNullToTextComponentsTest.java 8234140 macosx-all,windows-all @@ -318,7 +317,6 @@ java/awt/Modal/ToBack/ToBackNonModal3Test.java 8196441 linux-all java/awt/Modal/ToBack/ToBackNonModal4Test.java 8196441 linux-all javax/print/PrintSEUmlauts/PrintSEUmlauts.java 8135174 generic-all java/awt/font/Rotate/RotatedTextTest.java 8219641 linux-all -java/awt/font/TextLayout/LigatureCaretTest.java 8266312 generic-all java/awt/image/VolatileImage/CustomCompositeTest.java 8199002 windows-all,linux-all java/awt/image/VolatileImage/GradientPaints.java 8199003 linux-all java/awt/JAWT/JAWT.sh 8197798 windows-all,linux-all @@ -538,7 +536,6 @@ javax/swing/JTree/4633594/JTreeFocusTest.java 7105441 macosx-all javax/swing/AbstractButton/6711682/bug6711682.java 8060765 windows-all,macosx-all javax/swing/JFileChooser/6396844/TwentyThousandTest.java 8198003 generic-all javax/swing/JFileChooser/8194044/FileSystemRootTest.java 8327236 windows-all -javax/swing/JPopupMenu/6800513/bug6800513.java 7184956 macosx-all javax/swing/SwingUtilities/TestBadBreak/TestBadBreak.java 8160720 generic-all javax/swing/JFileChooser/bug6798062.java 8146446 windows-all javax/swing/JPopupMenu/4870644/bug4870644.java 8194130 macosx-all,linux-all @@ -647,7 +644,6 @@ javax/swing/JInternalFrame/bug4134077.java 8184985 windows-all java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_1.java 7131438,8022539 generic-all java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_2.java 7131438,8022539 generic-all java/awt/Modal/WsDisabledStyle/CloseBlocker/CloseBlocker.java 7187741 linux-all,macosx-all -java/awt/xembed/server/TestXEmbedServerJava.java 8001150,8004031 generic-all java/awt/image/VolatileImage/VolatileImageConfigurationTest.java 8171069 macosx-all,linux-all java/awt/Modal/InvisibleParentTest/InvisibleParentTest.java 8172245 linux-all java/awt/Frame/FrameStateTest/FrameStateTest.java 8203920 macosx-all,linux-all diff --git a/test/jdk/java/awt/xembed/server/TestXEmbedServerJava.java b/test/jdk/java/awt/xembed/server/TestXEmbedServerJava.java index 8a953c3acf71..3d35af96bcb6 100644 --- a/test/jdk/java/awt/xembed/server/TestXEmbedServerJava.java +++ b/test/jdk/java/awt/xembed/server/TestXEmbedServerJava.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, 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 4931668 + * @bug 4931668 8001150 * @summary Tests XEmbed server/client functionality * @author denis mikhalkin: area=awt.xembed * @requires (!(os.family=="mac") & !(os.family=="windows")) @@ -48,16 +48,28 @@ public static void main(String[] args) { "You may start XEmbed client by pressing 'Add client' button.\n" + "Check that focus transfer with mouse works, that focus traversal with Tab/Shift-Tab works.\n" + "Check that XEmbed server client's growing and shrinking.\n" + - "Check that Drag&Drop works in all combinations.\n" + - "Check the keyboard input works in both text fields.\n"; + " - Click the Increase size button in the embedded client and verify the client area grows.\n" + + " - Click the Decrease size button in the embedded client and verify the client area shrinks.\n" + + " - Repeat the grow and shrink actions a few times and verify the embedded client resizes correctly each time.\n" + + "Check the keyboard input works in both text fields.\n" + + " - Input some sample text into the server text field.\n" + + " - Drag the entire text in the server text field and verify it is dropped to the right of the existing text within the same text field.\n" + + " - Input some sample text into the client text field.\n" + + " - Drag the entire text in the client text field and verify it is dropped to the right of the existing text within the same text field.\n" + + " - Drag the text from the client text field to the server text field and verify it is dropped to the right of the existing text.\n" + + " - Drag the text from the server text field to the client text field and verify it is dropped to the right of the existing text.\n"; Frame f = new Frame("Instructions"); + TextArea instructionArea = new TextArea(instruction, 16, 104); + instructionArea.setEditable(false); f.setLayout(new BorderLayout()); - f.add(new TextArea(instruction), BorderLayout.CENTER); + f.add(instructionArea, BorderLayout.CENTER); f.pack(); - f.setLocation(0, 400); + f.setLocation(120, 60); f.setVisible(true); TestXEmbedServerJava lock = new TestXEmbedServerJava(); + lock.f.setLocation(f.getX() + f.getWidth() + 20, + f.getY() + f.getHeight() + 40); try { synchronized(lock) { lock.wait(); diff --git a/test/jdk/java/foreign/TestConfinedSegmentPool.java b/test/jdk/java/foreign/TestConfinedSegmentPool.java new file mode 100644 index 000000000000..f9013c7212e3 --- /dev/null +++ b/test/jdk/java/foreign/TestConfinedSegmentPool.java @@ -0,0 +1,616 @@ +/* + * Copyright (c) 2026, 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 + * @modules java.base/jdk.internal.foreign:+open java.base/jdk.internal.access java.base/jdk.internal.misc java.base/jdk.internal.util + * @library /test/lib + * @build TestConfinedSegmentPoolUtils + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=-1 TestConfinedSegmentPool + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=0 TestConfinedSegmentPool + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=1 TestConfinedSegmentPool + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=2 TestConfinedSegmentPool + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=3 TestConfinedSegmentPool + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=4 TestConfinedSegmentPool + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=5 TestConfinedSegmentPool + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=6 TestConfinedSegmentPool + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=7 TestConfinedSegmentPool + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=20 TestConfinedSegmentPool + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.count=0 TestConfinedSegmentPool + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.count=1 TestConfinedSegmentPool + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.count=3 TestConfinedSegmentPool + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.count=-1 TestConfinedSegmentPool + */ + +import jdk.internal.foreign.ConfinedSegmentPool; +import jdk.internal.misc.Unsafe; +import jdk.internal.util.Architecture; +import jdk.internal.util.OperatingSystem; +import jdk.test.lib.thread.VThreadRunner; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.lang.IllegalStateException; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import java.lang.ref.Cleaner; +import java.lang.ref.Reference; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; +import java.util.stream.LongStream; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +final class TestConfinedSegmentPool { + + static final long POOLED_MEMORY_SIZE = TestConfinedSegmentPoolUtils.POOLED_MEMORY_SIZE; + static final int THREAD_POOL_COUNT = TestConfinedSegmentPoolUtils.THREAD_POOL_COUNT; + + static final boolean POOL_ACCOMMODATES_TWO_LONGS = + TestConfinedSegmentPoolUtils.isPoolEnabled() && POOLED_MEMORY_SIZE >= Long.BYTES * 2; + + @ParameterizedTest + @MethodSource("threadFactories") + void basic(String name, Thread.Builder threadBuilder) throws Throwable { + AtomicReference threadPools = new AtomicReference<>(); + Thread thread = TestConfinedSegmentPoolUtils.runOn(threadBuilder, () -> { + // Virtual threads are using the underlying carrier thread's pool so + // there might already be a pool there. + if (!Thread.currentThread().isVirtual()) { + assertEquals(0, TestConfinedSegmentPoolUtils.currentPool()); + } + + long firstAddress; + try (Arena arena = Arena.ofConfined()) { + long allocator = TestConfinedSegmentPoolUtils.currentPool(); + if (!Thread.currentThread().isVirtual()) { + assertEquals(0, allocator); + } + + MemorySegment firstSegment = arena.allocate(ValueLayout.JAVA_LONG); + MemorySegment secondSegment = arena.allocate(ValueLayout.JAVA_LONG); + firstAddress = firstSegment.address(); + if (POOL_ACCOMMODATES_TWO_LONGS) { + assertEquals(firstAddress + ValueLayout.JAVA_LONG.byteSize(), secondSegment.address()); + } + firstSegment.set(ValueLayout.JAVA_LONG, 0, -1L); + secondSegment.set(ValueLayout.JAVA_LONG, 0, -1L); + } + + try (Arena arena = Arena.ofConfined()) { + MemorySegment firstSegment = arena.allocate(ValueLayout.JAVA_LONG); + MemorySegment secondSegment = arena.allocate(ValueLayout.JAVA_LONG); + if (POOL_ACCOMMODATES_TWO_LONGS) { + assertEquals(firstAddress, firstSegment.address()); + assertEquals(firstAddress + ValueLayout.JAVA_LONG.byteSize(), secondSegment.address()); + } + assertEquals(0L, firstSegment.get(ValueLayout.JAVA_LONG, 0)); + assertEquals(0L, secondSegment.get(ValueLayout.JAVA_LONG, 0)); + } + + if (!Thread.currentThread().isVirtual()) { + threadPools.set(TestConfinedSegmentPoolUtils.confinedMemoryPools(Thread.currentThread())); + } + }); + + if (!thread.isVirtual()) { + long[] pools = threadPools.get(); + if (TestConfinedSegmentPoolUtils.isPoolEnabled()) { + assertNotNull(pools); + // Thread-exit cleanup must clear every cache entry. + assertArrayEquals(new long[THREAD_POOL_COUNT], pools); + // Thread-exit cleanup must clear the array reference + assertNull(TestConfinedSegmentPoolUtils.confinedMemoryPools(thread)); + } else { + // No pool array was ever allocated + assertNull(pools); + } + } + } + + static Stream threadFactories() { + return Stream.of( + Arguments.of("platform", Thread.ofPlatform()), + Arguments.of("virtual", Thread.ofVirtual())); + } + + @Test + void cachedSegmentScope() { + try (Arena arena = Arena.ofConfined()) { + MemorySegment segment = arena.allocate(ValueLayout.JAVA_LONG); + assertSame(arena.scope(), segment.scope()); + } + } + + @Test + void cachedSegmentScopeVt() { + VThreadRunner.run(this::cachedSegmentScope); + } + + @Test + void cachedSegmentIsClosedWithArena() { + Arena arena = Arena.ofConfined(); + MemorySegment segment = arena.allocate(ValueLayout.JAVA_LONG); + segment.set(ValueLayout.JAVA_LONG, 0, 42L); + + arena.close(); + + assertFalse(segment.scope().isAlive()); + assertThrows(IllegalStateException.class, + () -> segment.get(ValueLayout.JAVA_LONG, 0)); + assertThrows(IllegalStateException.class, + () -> segment.set(ValueLayout.JAVA_LONG, 0, -1L)); + } + + @Test + void cachedSegmentIsClosedWithArenaVt() { + VThreadRunner.run(this::cachedSegmentIsClosedWithArena); + } + + @Test + void closedCachedSegmentCannotAccessReusedSlot() { + if (POOL_ACCOMMODATES_TWO_LONGS) { + MemorySegment firstSegment; + long firstAddress; + try (Arena firstArena = Arena.ofConfined()) { + firstSegment = firstArena.allocate(ValueLayout.JAVA_LONG); + firstAddress = firstSegment.address(); + firstSegment.set(ValueLayout.JAVA_LONG, 0, 42L); + } + + try (Arena secondArena = Arena.ofConfined()) { + MemorySegment secondSegment = secondArena.allocate(ValueLayout.JAVA_LONG); + assertEquals(firstAddress, secondSegment.address()); + secondSegment.set(ValueLayout.JAVA_LONG, 0, -1L); + assertThrows(IllegalStateException.class, + () -> firstSegment.get(ValueLayout.JAVA_LONG, 0)); + assertThrows(IllegalStateException.class, + () -> firstSegment.set(ValueLayout.JAVA_LONG, 0, 0L)); + } + } + } + + @Test + void closedCachedSegmentCannotAccessReusedSlotVt() { + VThreadRunner.run(this::closedCachedSegmentCannotAccessReusedSlot); + } + + @Test + void outOfOrderClose() { + Arena firstArena = Arena.ofConfined(); + MemorySegment firstSegment = firstArena.allocate(ValueLayout.JAVA_LONG); + long firstAddress = firstSegment.address(); + firstSegment.set(ValueLayout.JAVA_LONG, 0, -1L); + + Arena secondArena = Arena.ofConfined(); + MemorySegment secondSegment = secondArena.allocate(ValueLayout.JAVA_LONG); + secondSegment.set(ValueLayout.JAVA_LONG, 0, 42L); + + firstArena.close(); + + try (Arena thirdArena = Arena.ofConfined()) { + MemorySegment thirdSegment = thirdArena.allocate(ValueLayout.JAVA_LONG); + if (POOL_ACCOMMODATES_TWO_LONGS) { + assertEquals(firstAddress, thirdSegment.address()); + } + assertEquals(0L, thirdSegment.get(ValueLayout.JAVA_LONG, 0)); + assertEquals(42L, secondSegment.get(ValueLayout.JAVA_LONG, 0)); + } + + secondArena.close(); + } + + @Test + void outOfOrderCloseVt() { + VThreadRunner.run(this::outOfOrderClose); + } + + @Test + void scopesAreUnique() { + Arena firstArena = Arena.ofConfined(); + Arena secondArena = Arena.ofConfined(); + firstArena.close(); + try (Arena thirdArena = Arena.ofConfined()) { + var scopes = Stream.of(firstArena, secondArena, thirdArena) + .map(Arena::scope) + .collect(Collectors.toSet()); + assertEquals(3, scopes.size()); + } + secondArena.close(); + } + + @Test + void scopesAreUniqueVt() { + VThreadRunner.run(this::scopesAreUnique); + } + + @Test + void zeroing() { + assumeTrue(TestConfinedSegmentPoolUtils.isPoolEnabled()); + MemorySegment zeroes = MemorySegment.ofArray(new byte[Math.toIntExact(POOLED_MEMORY_SIZE)]); + for (long size : zeroingSizes()) { + try (Arena thirdArena = Arena.ofConfined()) { + MemorySegment segment = thirdArena.allocate(ValueLayout.JAVA_BYTE, size); + segment.fill((byte) 0xAA); + } + try (Arena thirdArena = Arena.ofConfined()) { + MemorySegment segment = thirdArena.allocate(ValueLayout.JAVA_BYTE, POOLED_MEMORY_SIZE); + assertEquals(-1L, segment.mismatch(zeroes), "used size: " + size); + } + } + } + + @Test + void zeroingVt() { + VThreadRunner.run(this::zeroing); + } + + @Test + void cleanerThreadCannotCloseCachedArena() throws Exception { + AtomicReference cleanerThreadRef = new AtomicReference<>(); + Cleaner cleaner = Cleaner.create(runnable -> { + Thread cleanerThread = new Thread(runnable, "TestConfinedSegmentPool-Cleaner"); + cleanerThread.setDaemon(true); + cleanerThreadRef.set(cleanerThread); + return cleanerThread; + }); + CountDownLatch cleanupLatch = new CountDownLatch(1); + AtomicReference cleanupThreadRef = new AtomicReference<>(); + AtomicReference failureRef = new AtomicReference<>(); + + Arena arena = Arena.ofConfined(); + MemorySegment segment = arena.allocate(ValueLayout.JAVA_LONG); + segment.set(ValueLayout.JAVA_LONG, 0, 42L); + + try { + Cleaner.Cleanable cleanable = registerCleaner(cleaner, () -> { + cleanupThreadRef.set(Thread.currentThread()); + try { + arena.close(); + } catch (Throwable ex) { + failureRef.set(ex); + } finally { + cleanupLatch.countDown(); + } + }); + + awaitCleaner(cleanupLatch); + + assertSame(cleanerThreadRef.get(), cleanupThreadRef.get()); + assertNotNull(failureRef.get()); + assertEquals(WrongThreadException.class, failureRef.get().getClass()); + assertTrue(arena.scope().isAlive()); + assertEquals(42L, segment.get(ValueLayout.JAVA_LONG, 0)); + + Reference.reachabilityFence(cleanable); + } finally { + if (arena.scope().isAlive()) { + arena.close(); + } + } + } + + @Test + void cleanerThreadCannotCloseCachedArenaVt() throws Exception { + VThreadRunner.run(this::cleanerThreadCannotCloseCachedArena); + } + + @Test + void noPoolAllocated() { + assumeTrue(TestConfinedSegmentPoolUtils.isPoolEnabled()); + long pool; + try (Arena arena = Arena.ofConfined()) { + pool = arena.allocate(1).address(); + } + assertEquals(pool, TestConfinedSegmentPoolUtils.currentPool()); + } + + @Test + void noPoolAllocatedVt() { + VThreadRunner.run(this::noPoolAllocated); + } + + @Test + void fallbackAfterAcquirePool() { + assumeTrue(TestConfinedSegmentPoolUtils.isPoolEnabled()); + try (Arena arena = Arena.ofConfined()) { + assertEquals(0L, confinedSessionSp(arena)); + // From the pool + arena.allocate(1); + assertEquals(1L, confinedSessionSp(arena)); + // The full-size allocation no longer fits after consuming one byte and + // must use the regular allocator. + arena.allocate(POOLED_MEMORY_SIZE, 1); + assertEquals(1L, confinedSessionSp(arena)); + } + } + + @Test + void fallbackAfterAcquirePoolVt() { + VThreadRunner.run(this::fallbackAfterAcquirePool); + } + + @Test + void uniqueZeroAddresses() { + assumeTrue(TestConfinedSegmentPoolUtils.isPoolEnabled()); + try (Arena arena = Arena.ofConfined()) { + MemorySegment first = arena.allocate(0, 1); + MemorySegment second = arena.allocate(0, 1); + assertEquals(0, first.byteSize()); + assertEquals(0, second.byteSize()); + assertNotEquals(first.address(), second.address()); + } + } + + @Test + void uniqueZeroAddressesVt() { + VThreadRunner.run(this::uniqueZeroAddresses); + } + + @Test + void availablePoolsAreCleanedUpOnThreadExit() throws Throwable { + assumeTrue(TestConfinedSegmentPoolUtils.isPoolEnabled()); + + AtomicReference failure = new AtomicReference<>(); + AtomicReference threadPools = new AtomicReference<>(); + + Thread thread = Thread.ofPlatform().unstarted(() -> { + Arena[] cached = new Arena[THREAD_POOL_COUNT]; + + try { + allocateOneByte(cached); + closeAll(cached); // One non-zero entry for each configured cache slot + + long[] pools = TestConfinedSegmentPoolUtils.confinedMemoryPools(Thread.currentThread()); + assertNotNull(pools); + threadPools.set(pools); + assertEquals(THREAD_POOL_COUNT, Arrays.stream(pools).filter(p -> p != 0).count()); + } catch (Throwable ex) { + failure.set(ex); + } + }); + + thread.start(); + thread.join(TimeUnit.SECONDS.toMillis(10)); + + assertFalse(thread.isAlive(), "platform thread did not terminate"); + if (failure.get() != null) { + throw failure.get(); + } + + // Thread-exit cleanup must clear every cache entry. + assertArrayEquals(new long[THREAD_POOL_COUNT], threadPools.get()); + // Thread-exit cleanup must clear the array reference + assertNull(TestConfinedSegmentPoolUtils.confinedMemoryPools(thread)); + } + + @Test + void threadExitCleanupDoesNotFreeAcquiredPool() throws Throwable { + assumeTrue(TestConfinedSegmentPoolUtils.isPoolEnabled()); + + AtomicReference failure = new AtomicReference<>(); + Thread thread = Thread.ofPlatform().unstarted(() -> { + try { + long pool; + try (Arena scratch = Arena.ofConfined()) { + pool = scratch.allocate(1).address(); + } + assertEquals(pool, TestConfinedSegmentPoolUtils.currentPool()); + + try (Arena arena = Arena.ofConfined()) { + MemorySegment segment = arena.allocate(ValueLayout.JAVA_BYTE); + assertEquals(pool, segment.address()); + assertEquals(0, TestConfinedSegmentPoolUtils.currentPool()); + segment.set(ValueLayout.JAVA_BYTE, 0, (byte) 42); + + // Simulate thread-exit cleanup while the pool is detached and + // exclusively owned by this still-open arena. + ConfinedSegmentPool.threadTerminated(TestConfinedSegmentPoolUtils.confinedMemoryPools(Thread.currentThread())); + assertEquals((byte) 42, segment.get(ValueLayout.JAVA_BYTE, 0)); + } + assertEquals(pool, TestConfinedSegmentPoolUtils.currentPool()); + } catch (Throwable ex) { + failure.set(ex); + } + }); + + thread.start(); + thread.join(TimeUnit.SECONDS.toMillis(10)); + + assertFalse(thread.isAlive(), "platform thread did not terminate"); + if (failure.get() != null) { + throw failure.get(); + } + } + + @Test + void cacheSaturation() { + assumeTrue(TestConfinedSegmentPoolUtils.isPoolEnabled()); + testCacheSaturation(); + } + + @Test + void cacheSaturationVt() { + assumeTrue(TestConfinedSegmentPoolUtils.isPoolEnabled()); + VThreadRunner.run(this::testCacheSaturation); + } + + // This test can only be run on certain platforms and we are using an + // address alias to simulate negative values in order to test the inner workings + // of a confined arena using such an address. + @Test + void negativeAddress() throws Throwable { + assumeTrue(TestConfinedSegmentPoolUtils.isPoolEnabled()); + // Tagged memory can only be used on Aarch64 + assumeTrue(Architecture.isAARCH64()); + // Top Byte Ignore (TBI) is only guaranteed on these OSes + assumeTrue(OperatingSystem.isLinux() || OperatingSystem.isMacOS()); + + // Run on a fresh platform thread so that we can manipulate the cache + // freely and isolated from the main thread. + TestConfinedSegmentPoolUtils.runOn(Thread.ofPlatform(), () -> { + final Unsafe u = Unsafe.getUnsafe(); + + long originalAddress = 0; + long negativeAliasAddress = 0; + long[] pools = null; + + try { + originalAddress = u.allocateMemory(POOLED_MEMORY_SIZE); + negativeAliasAddress = originalAddress | Long.MIN_VALUE; + pools = TestConfinedSegmentPoolUtils.getOrCreateConfinedMemoryPools( + Thread.currentThread(), THREAD_POOL_COUNT); + + u.setMemory(originalAddress, POOLED_MEMORY_SIZE, (byte) 0); + pools[0] = negativeAliasAddress; + + try (Arena arena = Arena.ofConfined()) { + MemorySegment segment = arena.allocate(1, 1); + assertEquals(negativeAliasAddress, segment.address()); + segment.set(ValueLayout.JAVA_BYTE, 0, (byte) 42); + assertEquals((byte) 42, u.getByte(originalAddress)); + } + + assertEquals(negativeAliasAddress, pools[0]); + assertEquals((byte) 0, u.getByte(originalAddress)); + } finally { + // Prevent thread-exit cleanup from freeing the alias as we cannot + // directly free memory using a tagged address. + if (pools != null) { + Arrays.fill(pools, 0); + } + if (originalAddress != 0) { + u.freeMemory(originalAddress); + } + } + }); + } + + private void testCacheSaturation() { + Arena[] initial = new Arena[THREAD_POOL_COUNT + 1]; + Arena[] verification = new Arena[THREAD_POOL_COUNT]; + + try { + long[] addresses = allocateOneByte(initial); + + // The first releases fill every configured cache slot. + for (int i = 0; i < THREAD_POOL_COUNT; i++) { + initial[i].close(); + } + + // One further release must free its pool. + initial[THREAD_POOL_COUNT].close(); + + // All cached pools must remain reusable. + long[] expected = Arrays.copyOf(addresses, THREAD_POOL_COUNT); + long[] actual = allocateOneByte(verification); + Arrays.sort(expected); + Arrays.sort(actual); + assertArrayEquals(expected, actual); + } finally { + closeAll(initial); + closeAll(verification); + } + } + + static long[] allocateOneByte(Arena[] arenas) { + long[] addresses = new long[arenas.length]; + for (int i = 0; i < arenas.length; i++) { + arenas[i] = Arena.ofConfined(); + addresses[i] = arenas[i].allocate(ValueLayout.JAVA_BYTE).address(); + } + return addresses; + } + + static void closeAll(Arena[] arenas) { + for (Arena arena : arenas) { + if (arena != null && arena.scope().isAlive()) { + arena.close(); + } + } + } + + static long confinedSessionSp(Arena arena) { + + final class Holder { + + private static Field poolSpField; + + static Field getOrSet(Arena arena) { + Field poolSpField = Holder.poolSpField; + if (poolSpField == null) { + try { + Holder.poolSpField = poolSpField = arena.getClass().getDeclaredField("poolSp"); + poolSpField.setAccessible(true); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + return poolSpField; + } + } + + try { + return Holder.getOrSet(arena).getLong(arena); + } catch (ReflectiveOperationException e) { + throw new AssertionError(e); + } + } + + private static long[] zeroingSizes() { + return LongStream.of(0, 1, 7, 8, 9, 15, 16, 17, + 31, 32, 33, 63, 64, 65, + POOLED_MEMORY_SIZE / 2, + POOLED_MEMORY_SIZE - 1, + POOLED_MEMORY_SIZE) + .filter(size -> size >= 0 && size <= POOLED_MEMORY_SIZE) + .distinct() + .toArray(); + } + + static void awaitCleaner(CountDownLatch latch) throws InterruptedException { + long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(10); + do { + System.gc(); + if (latch.await(10, TimeUnit.MILLISECONDS)) { + return; + } + Thread.onSpinWait(); + } while (System.nanoTime() < deadline); + fail("Cleaner did not run"); + } + + static Cleaner.Cleanable registerCleaner(Cleaner cleaner, Runnable action) { + return cleaner.register(new Object(), action); + } + +} diff --git a/test/jdk/java/foreign/TestConfinedSegmentPoolCleanup.java b/test/jdk/java/foreign/TestConfinedSegmentPoolCleanup.java new file mode 100644 index 000000000000..bfa325d8f8e6 --- /dev/null +++ b/test/jdk/java/foreign/TestConfinedSegmentPoolCleanup.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Cleanup actions must run before a confined arena releases its pool + * @modules java.base/jdk.internal.foreign java.base/jdk.internal.access + * @build TestConfinedSegmentPoolUtils + * @run junit/othervm --enable-native-access=ALL-UNNAMED TestConfinedSegmentPoolCleanup + */ + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; + +final class TestConfinedSegmentPoolCleanup { + + // A random value + private static final long MARKER = 0xF25C214F82C1422FL; + + @ParameterizedTest(name = "{0}, throwableType={2}") + @MethodSource("configurations") + void cleanupRunsBeforePoolRelease(String name, Thread.Builder builder, Class throwableType) throws Throwable { + // It does not matter if a VT is running on a previously-used carrier thread. + TestConfinedSegmentPoolUtils.runOn(builder, () -> testCleanup(throwableType)); + } + + private static void testCleanup(Class throwableType) { + Arena arena = Arena.ofConfined(); + long address; + try { + MemorySegment segment = arena.allocate(ValueLayout.JAVA_LONG); + address = segment.address(); + segment.reinterpret(Long.BYTES, arena, cleanupSegment -> { + cleanupSegment.set(ValueLayout.JAVA_LONG, 0, MARKER); + switch (throwableType) { + case Class c when ExpectedCleanupException.class.equals(c) -> throw new ExpectedCleanupException(); + case Class c when ExpectedCleanupError.class.equals(c) -> throw new ExpectedCleanupError(); + case null, default -> { } // Do nothing + } + }); + + if (throwableType != null) { + assertThrows(throwableType, arena::close); + } else { + arena.close(); + } + assertFalse(arena.scope().isAlive()); + } finally { + // Tidy up if something failed + if (arena.scope().isAlive()) { + arena.close(); + } + } + + try (Arena verificationArena = Arena.ofConfined()) { + MemorySegment segment = verificationArena.allocate(ValueLayout.JAVA_LONG); + assertEquals(address, segment.address(), "pool was not reused"); + assertEquals(0L, segment.get(ValueLayout.JAVA_LONG, 0), "cleanup action contaminated the released pool"); + } + } + + private static Stream configurations() { + return Stream.of( + Arguments.of("platform", Thread.ofPlatform(), null), + Arguments.of("platform", Thread.ofPlatform(), ExpectedCleanupException.class), + Arguments.of("platform", Thread.ofPlatform(), ExpectedCleanupError.class), + Arguments.of("virtual", Thread.ofVirtual(), null), + Arguments.of("virtual", Thread.ofVirtual(), ExpectedCleanupException.class), + Arguments.of("virtual", Thread.ofVirtual(), ExpectedCleanupError.class)); + } + + private sealed interface ExpectedCleanupThrowable{}; + private static final class ExpectedCleanupException extends RuntimeException implements ExpectedCleanupThrowable {} + private static final class ExpectedCleanupError extends Error implements ExpectedCleanupThrowable {} +} diff --git a/test/jdk/java/foreign/TestConfinedSegmentPoolConfig.java b/test/jdk/java/foreign/TestConfinedSegmentPoolConfig.java new file mode 100644 index 000000000000..52f56025460b --- /dev/null +++ b/test/jdk/java/foreign/TestConfinedSegmentPoolConfig.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2026, 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 + * @modules java.base/jdk.internal.foreign java.base/jdk.internal.access + * @build TestConfinedSegmentPoolUtils + * @run junit TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=0 TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=1 TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=2 TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=3 TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=4 TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=5 TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=6 TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=7 TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=20 TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=21 TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=24 TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=-1 TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=23847682736221 TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=TEXT TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.count=0 TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.count=1 TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.count=2 TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.count=3 TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.count=4 TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.count=-1 TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.count=23847682736221 TestConfinedSegmentPoolConfig + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.count=TEXT TestConfinedSegmentPoolConfig + * @run junit/othervm -Dsun.nio.PageAlignDirectMemory=true + * -Djdk.internal.foreign.native.confined.pool.power.size=PAGE_ALIGN + * -Djdk.internal.foreign.native.confined.pool.power.count=PAGE_ALIGN + * TestConfinedSegmentPoolConfig + */ + +import jdk.internal.foreign.ConfinedSegmentPool; +import org.junit.jupiter.api.Test; + +import java.lang.foreign.Arena; +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.jupiter.api.Assertions.*; + +final class TestConfinedSegmentPoolConfig { + + static final int DISABLED = TestConfinedSegmentPoolUtils.DISABLED; + static final String POOLED_MEMORY_SIZE_PROPERTY = TestConfinedSegmentPoolUtils.POOLED_MEMORY_SIZE_PROPERTY; + static final String THREAD_POOL_COUNT_PROPERTY = TestConfinedSegmentPoolUtils.THREAD_POOL_COUNT_PROPERTY; + + @Test + void configuration() throws Throwable { + boolean pageAligned = "PAGE_ALIGN".equals(System.getProperty(POOLED_MEMORY_SIZE_PROPERTY)); + long configuredSize = pageAligned + ? DISABLED + : TestConfinedSegmentPoolUtils.configuredPowerOfTwo(POOLED_MEMORY_SIZE_PROPERTY, 3, 20, 6); + int expectedCount = pageAligned + ? DISABLED + : TestConfinedSegmentPoolUtils.configuredPowerOfTwo(THREAD_POOL_COUNT_PROPERTY, 0, 3, 2); + long expectedSize = configuredSize > 0 && expectedCount > 0 + ? configuredSize + : DISABLED; + + assertEquals(expectedSize, ConfinedSegmentPool.pooledMemorySize()); + + AtomicReference threadPools = new AtomicReference<>(); + + Thread thread = TestConfinedSegmentPoolUtils.runOn(Thread.ofPlatform(), () -> { + try (Arena arena = Arena.ofConfined()) { + arena.allocate(1); + } + + long[] pools = TestConfinedSegmentPoolUtils.confinedMemoryPools(Thread.currentThread()); + threadPools.set(pools); + if (expectedSize > 0 && expectedCount > 0) { + assertNotNull(pools); + assertEquals(expectedCount, pools.length); + assertEquals(1, Arrays.stream(pools).filter(pool -> pool != 0).count()); + } else { + assertNull(pools); + } + }); + + long[] pools = threadPools.get(); + if (expectedSize > 0 && expectedCount > 0) { + assertArrayEquals(new long[expectedCount], pools); + } else { + assertNull(pools); + } + } + +} diff --git a/test/jdk/java/foreign/TestConfinedSegmentPoolDefensiveRelease.java b/test/jdk/java/foreign/TestConfinedSegmentPoolDefensiveRelease.java new file mode 100644 index 000000000000..9878bb9ddf47 --- /dev/null +++ b/test/jdk/java/foreign/TestConfinedSegmentPoolDefensiveRelease.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2026, 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 + * @requires vm.continuations + * @modules java.base/jdk.internal.foreign:+open java.base/java.lang:+open java.base/jdk.internal.access + * @library /test/lib + * @build TestConfinedSegmentPoolUtils + * @run junit TestConfinedSegmentPoolDefensiveRelease + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=0 TestConfinedSegmentPoolDefensiveRelease + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=1 TestConfinedSegmentPoolDefensiveRelease + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=2 TestConfinedSegmentPoolDefensiveRelease + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=3 TestConfinedSegmentPoolDefensiveRelease + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=4 TestConfinedSegmentPoolDefensiveRelease + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=5 TestConfinedSegmentPoolDefensiveRelease + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=6 TestConfinedSegmentPoolDefensiveRelease + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=7 TestConfinedSegmentPoolDefensiveRelease + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=-1 TestConfinedSegmentPoolDefensiveRelease + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=23847682736221 TestConfinedSegmentPoolDefensiveRelease + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=TEXT TestConfinedSegmentPoolDefensiveRelease + * @run junit/othervm -Dsun.nio.PageAlignDirectMemory=true + * -Djdk.internal.foreign.native.confined.pool.power.size=PAGE_ALIGN + * TestConfinedSegmentPoolDefensiveRelease + */ + +import jdk.internal.foreign.ConfinedSegmentPool; +import jdk.test.lib.thread.VThreadScheduler; +import org.junit.jupiter.api.Test; + +import java.lang.IllegalStateException; +import java.lang.foreign.Arena; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.LongConsumer; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +final class TestConfinedSegmentPoolDefensiveRelease { + + static final Method RELEASE = releaseMethod(); + + @Test + void releaseWithNoPreviousAcquire() throws Throwable { + TestConfinedSegmentPoolUtils.runOn(Thread.ofPlatform(), () -> + assertThrows(IllegalStateException.class, () -> release(0, 1))); + } + + @Test + void releaseWithNoPreviousAcquireVt() throws Throwable { + testOnVirtualThreadWithUntouchedCarrierThread(() -> { + assertThrows(IllegalStateException.class, () -> release(0, 1)); + }); + } + + @Test + void releaseAfterRelease() throws Throwable { + testOnUntouchedThread(pool -> assertThrows(IllegalStateException.class, () -> release(pool, 1))); + } + + @Test + void releaseAfterReleaseVt() throws Throwable { + assumeTrue(ConfinedSegmentPool.pooledMemorySize() > 0); + testOnVirtualThreadWithUntouchedCarrierThread(() -> { + long pool; + try (Arena arena = Arena.ofConfined()) { + pool = arena.allocate(1).address(); + } + + // The first allocation starts at the pool base, and closing the + // arena returns that pool to the dedicated carrier. + assertEquals(pool, TestConfinedSegmentPoolUtils.currentPool()); + + assertThrows(IllegalStateException.class, + () -> release(pool, 1)); + }); + } + + @Test + void releaseIllegalSize() throws Throwable { + // Only test with pooling enabled + assumeTrue(ConfinedSegmentPool.pooledMemorySize() > 0); + testOnUntouchedThread(pool -> { + try (Arena arena = Arena.ofConfined()) { + arena.allocate(1); + assertThrows(IllegalStateException.class, () -> release(pool, ConfinedSegmentPool.pooledMemorySize() + 1)); + assertThrows(IllegalStateException.class, () -> release(pool, -1)); + assertEquals(0 /* acquired and detached */, + TestConfinedSegmentPoolUtils.currentPool()); + } + assertEquals(pool /* released */, TestConfinedSegmentPoolUtils.currentPool()); + }); + } + + @Test + void releaseIllegalSizeVt() throws Throwable { + assumeTrue(ConfinedSegmentPool.pooledMemorySize() > 0); + testOnVirtualThreadWithUntouchedCarrierThread(() -> { + long pool; + try (Arena scratch = Arena.ofConfined()) { + pool = scratch.allocate(1).address(); + } + assertEquals(pool, TestConfinedSegmentPoolUtils.currentPool()); + + try (Arena arena = Arena.ofConfined()) { + assertEquals(pool, arena.allocate(1).address()); + assertThrows(IllegalStateException.class, () -> release(pool, ConfinedSegmentPool.pooledMemorySize() + 1)); + assertThrows(IllegalStateException.class, () -> release(pool, -1)); + assertEquals(0 /* acquired but not remembered */, + TestConfinedSegmentPoolUtils.currentPool()); + } + assertEquals(pool /* released */, TestConfinedSegmentPoolUtils.currentPool()); + }); + } + + static void testOnUntouchedThread(LongConsumer c) throws Throwable { + // Only test with pooling enabled + assumeTrue(ConfinedSegmentPool.pooledMemorySize() > 0); + TestConfinedSegmentPoolUtils.runOn(Thread.ofPlatform(), () -> { + try (Arena arena = Arena.ofConfined()) { + arena.allocate(1); + } + long pool = TestConfinedSegmentPoolUtils.currentPool(); + assertNotEquals(0L, pool, "Pool was not allocated"); + c.accept(pool); + }); + } + + static void testOnVirtualThreadWithUntouchedCarrierThread(Runnable action) + throws Throwable { + AtomicReference failure = new AtomicReference<>(); + + ThreadFactory carrierFactory = task -> Thread.ofPlatform() + .name("TestConfinedSegmentPool-carrier") + .unstarted(task); + + try (ExecutorService scheduler = Executors.newSingleThreadExecutor(carrierFactory)) { + Thread thread = VThreadScheduler.virtualThreadFactory(scheduler) + .newThread(() -> { + try { + action.run(); + } catch (Throwable throwable) { + failure.set(throwable); + } + }); + + thread.start(); + try { + thread.join(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + TestConfinedSegmentPoolUtils.rethrowIfFailed(failure.get()); + } + + static void release(long pool, long size) throws Throwable { + try { + RELEASE.invoke(null, pool, size); + } catch (InvocationTargetException ex) { + throw ex.getCause(); + } + } + + static Method releaseMethod() { + try { + Method method = ConfinedSegmentPool.class.getDeclaredMethod("release", long.class, long.class); + method.setAccessible(true); + return method; + } catch (ReflectiveOperationException ex) { + throw new ExceptionInInitializerError(ex); + } + } + +} diff --git a/test/jdk/java/foreign/TestConfinedSegmentPoolUtils.java b/test/jdk/java/foreign/TestConfinedSegmentPoolUtils.java new file mode 100644 index 000000000000..7ff06fcbff05 --- /dev/null +++ b/test/jdk/java/foreign/TestConfinedSegmentPoolUtils.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2026, 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.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; +import jdk.internal.foreign.ConfinedSegmentPool; + +import java.util.concurrent.atomic.AtomicReference; + +final class TestConfinedSegmentPoolUtils { + + static final int DISABLED = -1; + static final String POOLED_MEMORY_SIZE_PROPERTY = "jdk.internal.foreign.native.confined.pool.power.size"; + static final String THREAD_POOL_COUNT_PROPERTY = "jdk.internal.foreign.native.confined.pool.power.count"; + + static final long POOLED_MEMORY_SIZE = ConfinedSegmentPool.pooledMemorySize(); + static final int THREAD_POOL_COUNT = configuredPowerOfTwo(THREAD_POOL_COUNT_PROPERTY, 0, 3, 2); + + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + + private TestConfinedSegmentPoolUtils() { + } + + static boolean isPoolEnabled() { + return POOLED_MEMORY_SIZE > 0 && THREAD_POOL_COUNT > 0; + } + + static int configuredPowerOfTwo(String property, int minPower, + int maxPower, int defaultPower) { + int power = Integer.getInteger(property, defaultPower); + return power < 0 + ? DISABLED + : 1 << Math.clamp(power, minPower, maxPower); + } + + static long currentPool() { + if (!isPoolEnabled()) { + return 0; + } + return currentPlatformPool(JLA.currentCarrierThread()); + } + + static long currentPlatformPool(Thread thread) { + long[] pools = confinedMemoryPools(thread); + if (pools != null) { + for (long pool : pools) { + if (pool != 0) { + return pool; + } + } + } + return 0; + } + + static long[] confinedMemoryPools(Thread thread) { + return JLA.getConfinedMemoryPools(thread); + } + + static long[] getOrCreateConfinedMemoryPools(Thread thread, int poolCount) { + return JLA.getOrCreateConfinedMemoryPools(thread, poolCount); + } + + static Thread runOn(Thread.Builder builder, ThrowingRunnable action) + throws Throwable { + AtomicReference failure = new AtomicReference<>(); + Thread thread = builder.start(() -> { + try { + action.run(); + } catch (Throwable ex) { + failure.set(ex); + } + }); + thread.join(); + rethrowIfFailed(failure.get()); + return thread; + } + + static void rethrowIfFailed(Throwable failure) throws Throwable { + if (failure != null) { + throw failure; + } + } + + @FunctionalInterface + interface ThrowingRunnable { + void run() throws Throwable; + } +} diff --git a/test/jdk/java/foreign/TestConfinedSegmentVtMigration.java b/test/jdk/java/foreign/TestConfinedSegmentVtMigration.java new file mode 100644 index 000000000000..7e0861c4d66a --- /dev/null +++ b/test/jdk/java/foreign/TestConfinedSegmentVtMigration.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2026, 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 + * @modules java.base/jdk.internal.foreign java.base/java.lang:+open java.base/jdk.internal.access + * @library /test/lib + * @build TestConfinedSegmentPoolUtils + * @run junit TestConfinedSegmentVtMigration + */ + +import jdk.internal.foreign.ConfinedSegmentPool; +import jdk.test.lib.thread.VThreadScheduler; +import org.junit.jupiter.api.Test; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.LockSupport; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +final class TestConfinedSegmentVtMigration { + + private static final long TIMEOUT_SECONDS = 10; + + @Test + void poolSurvivesCarrierMigration() throws Throwable { + assumeTrue(VThreadScheduler.supportsCustomScheduler()); + assumeTrue(ConfinedSegmentPool.pooledMemorySize() > 0); + + AtomicInteger submissions = new AtomicInteger(); + AtomicReference runningCarrier = new AtomicReference<>(); + AtomicReference initialCarrier = new AtomicReference<>(); + AtomicReference resumedCarrier = new AtomicReference<>(); + AtomicReference failure = new AtomicReference<>(); + AtomicBoolean resume = new AtomicBoolean(); + CountDownLatch readyToPark = new CountDownLatch(1); + + ThreadFactory carrierFactoryA = Thread.ofPlatform() + .name("TestConfinedSegmentVtMigration-A") + .factory(); + ThreadFactory carrierFactoryB = Thread.ofPlatform() + .name("TestConfinedSegmentVtMigration-B") + .factory(); + + try (ExecutorService executorA = Executors.newSingleThreadExecutor(carrierFactoryA); + ExecutorService executorB = Executors.newSingleThreadExecutor(carrierFactoryB)) { + Executor scheduler = task -> { + ExecutorService executor = submissions.getAndIncrement() == 0 + ? executorA + : executorB; + executor.execute(() -> { + runningCarrier.set(Thread.currentThread()); + task.run(); + }); + }; + + Thread vthread = VThreadScheduler.virtualThreadFactory(scheduler) + .newThread(() -> { + Arena arena = null; + try { + // Here, we run on carrier thread A + Thread carrier = runningCarrier.get(); + initialCarrier.set(carrier); + + long pool; + try (Arena scratch = Arena.ofConfined()) { + pool = scratch.allocate(ValueLayout.JAVA_BYTE).address(); + } + assertEquals(pool, TestConfinedSegmentPoolUtils.currentPool()); + + // Keep this arena alive while the virtual thread migrates from carrier A + // to carrier B. + arena = Arena.ofConfined(); + MemorySegment segment = arena.allocate(ValueLayout.JAVA_BYTE); + assertEquals(pool, segment.address()); + assertEquals(0, TestConfinedSegmentPoolUtils.currentPool()); + segment.set(ValueLayout.JAVA_BYTE, 0, (byte) 42); + + // Wait until the test thread terminates carrier A and allows this + // continuation to resume on carrier B. + readyToPark.countDown(); + while (!resume.get()) { + LockSupport.park(); + } + + // The continuation is now running on carrier B. + resumedCarrier.set(runningCarrier.get()); + assertNotSame(initialCarrier.get(), resumedCarrier.get()); + assertEquals((byte) 42, segment.get(ValueLayout.JAVA_BYTE, 0)); + + arena.close(); + arena = null; + assertEquals(pool, TestConfinedSegmentPoolUtils.currentPool()); + + try (Arena verify = Arena.ofConfined()) { + MemorySegment verifySegment = + verify.allocate(ValueLayout.JAVA_BYTE); + assertEquals(pool, verifySegment.address()); + // The released pool must be zeroed before reuse. + assertEquals((byte) 0, verifySegment.get(ValueLayout.JAVA_BYTE, 0)); + } + } catch (Throwable ex) { + failure.set(ex); + } finally { + readyToPark.countDown(); + if (arena != null && arena.scope().isAlive()) { + try { + arena.close(); + } catch (Throwable ex) { + failure.compareAndSet(null, ex); + } + } + } + }); + + vthread.start(); + try { + assertTrue(readyToPark.await(TIMEOUT_SECONDS, TimeUnit.SECONDS), + "virtual thread did not reach the park point"); + TestConfinedSegmentPoolUtils.rethrowIfFailed(failure.get()); + awaitState(vthread, Thread.State.WAITING); + + executorA.shutdown(); + assertTrue(executorA.awaitTermination(TIMEOUT_SECONDS, TimeUnit.SECONDS), + "initial carrier executor did not terminate"); + Thread carrier = initialCarrier.get(); + carrier.join(TimeUnit.SECONDS.toMillis(TIMEOUT_SECONDS)); + assertFalse(carrier.isAlive(), "initial carrier did not terminate"); + } finally { + resume.set(true); + LockSupport.unpark(vthread); + vthread.join(TimeUnit.SECONDS.toMillis(TIMEOUT_SECONDS)); + } + assertFalse(vthread.isAlive(), "virtual thread did not terminate"); + TestConfinedSegmentPoolUtils.rethrowIfFailed(failure.get()); + assertNotSame(initialCarrier.get(), resumedCarrier.get()); + } + } + + private static void awaitState(Thread thread, Thread.State expected) + throws InterruptedException { + long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(TIMEOUT_SECONDS); + while (thread.getState() != expected) { + if (thread.getState() == Thread.State.TERMINATED) { + fail("virtual thread terminated before reaching " + expected); + } + if (System.nanoTime() >= deadline) { + fail("timed out waiting for virtual thread state " + expected + + ", current state: " + thread.getState()); + } + Thread.sleep(10); + } + } + +} diff --git a/test/jdk/java/foreign/TestLayouts.java b/test/jdk/java/foreign/TestLayouts.java index 730d26fedc06..b4d98fcd754e 100644 --- a/test/jdk/java/foreign/TestLayouts.java +++ b/test/jdk/java/foreign/TestLayouts.java @@ -237,6 +237,31 @@ public void testSequenceOverflow() { () -> MemoryLayout.sequenceLayout(Long.MAX_VALUE/3, JAVA_LONG)); assertThrows(IllegalArgumentException.class, // flip back to positive () -> MemoryLayout.sequenceLayout(0, JAVA_LONG).withElementCount(Long.MAX_VALUE)); + assertThrows(IllegalArgumentException.class, () -> { + SequenceLayout oneByte = MemoryLayout.sequenceLayout(1, ValueLayout.JAVA_BYTE); + // 2^32 + long n = 1L << 32; + // n * n -> overflow -> zero + oneByte.reshape(-1, n, n); + }); + + } + + @Test + public void testSequenceLayoutFlattenOverflowBeforeZero() { + SequenceLayout zero = MemoryLayout.sequenceLayout(0, JAVA_BYTE); + SequenceLayout innerLayout = MemoryLayout.sequenceLayout(Long.MAX_VALUE, zero); + SequenceLayout layout = MemoryLayout.sequenceLayout(2, innerLayout); + assertEquals(layout.flatten(), zero); + } + + @Test + public void testSequenceLayoutFlattenOverflow() { + MemoryLayout empty = MemoryLayout.structLayout(); // byteSize() == 0 + long n = 1L << 32; // n * n overflows and wraps to zero which might be a corner case + SequenceLayout innerLayout = MemoryLayout.sequenceLayout(n, empty); + SequenceLayout layout = MemoryLayout.sequenceLayout(n, innerLayout); + assertThrows(UnsupportedOperationException.class, layout::flatten); } @Test diff --git a/test/jdk/java/foreign/TestMappedSegmentKeepAlive.java b/test/jdk/java/foreign/TestMappedSegmentKeepAlive.java new file mode 100644 index 000000000000..e8d3d00de7bb --- /dev/null +++ b/test/jdk/java/foreign/TestMappedSegmentKeepAlive.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2026, 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 + * @run junit TestMappedSegmentKeepAlive + */ + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.File; +import java.io.IOException; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.nio.*; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.*; +import java.util.stream.Stream; + +import static org.junit.jupiter.params.provider.Arguments.arguments; +import static org.junit.jupiter.api.Assertions.*; + +public class TestMappedSegmentKeepAlive { + + static final Path tempPath; + + static { + try { + File file = File.createTempFile("buffer", "txt"); + file.deleteOnExit(); + tempPath = file.toPath(); + Files.write(file.toPath(), new byte[256], StandardOpenOption.WRITE); + + } catch (IOException ex) { + throw new ExceptionInInitializerError(ex); + } + } + + @ParameterizedTest + @MethodSource("mappedOps") + public void testExceptionOnAcquire(Consumer op) throws Throwable { + try (Arena arena = Arena.ofConfined(); + FileChannel fileChannel = FileChannel.open(tempPath, StandardOpenOption.READ, StandardOpenOption.WRITE)) { + MemorySegment segment = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0L, 8L, arena); + AtomicReference throwableRef = new AtomicReference<>(); + Thread t = Thread.ofPlatform() + .uncaughtExceptionHandler((_, throwable) -> throwableRef.set(throwable)) + .start(() -> { + // Provoke a WrongThreadException when acquiring the session + // Make sure we properly release the session again + assertThrows(WrongThreadException.class, () -> op.accept(segment)); + }); + t.join(); + // propagate any exceptions from the nested thread + if (throwableRef.get() != null) { + throw throwableRef.get(); + } + } // close should succeed + } + + public static Stream mappedOps() { + return Stream.of( + arguments((Consumer) MemorySegment::force), + arguments((Consumer) MemorySegment::load), + arguments((Consumer) MemorySegment::unload), + arguments((Consumer) MemorySegment::isLoaded) + ); + } +} diff --git a/test/jdk/java/foreign/TestMismatch.java b/test/jdk/java/foreign/TestMismatch.java index fc8854d74920..15896937aa93 100644 --- a/test/jdk/java/foreign/TestMismatch.java +++ b/test/jdk/java/foreign/TestMismatch.java @@ -326,6 +326,17 @@ public void testClosed() { assertThrows(ISE, () -> s2.mismatch(s1)); } + @Test + public void testClosedEmptyRange() { + MemorySegment closed; + try (Arena arena = Arena.ofConfined()) { + closed = arena.allocate(4, 1); + } + var alive = MemorySegment.ofArray(new byte[4]); + assertThrows(ISE, () -> MemorySegment.mismatch(closed, 0, 0, alive, 0, 0)); + assertThrows(ISE, () -> MemorySegment.mismatch(alive, 0, 0, closed, 0, 0)); + } + @Test public void testThreadAccess() throws Exception { try (Arena arena = Arena.ofConfined()) { diff --git a/test/jdk/java/foreign/TestSegmentAllocators.java b/test/jdk/java/foreign/TestSegmentAllocators.java index 63ecfce4d861..eb23ce9ffc25 100644 --- a/test/jdk/java/foreign/TestSegmentAllocators.java +++ b/test/jdk/java/foreign/TestSegmentAllocators.java @@ -25,14 +25,21 @@ /* * @test * @modules java.base/jdk.internal.foreign - * @run junit/othervm TestSegmentAllocators + * @library /test/lib + * @run junit/othervm TestSegmentAllocators + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=-1 TestSegmentAllocators + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=3 TestSegmentAllocators + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=4 TestSegmentAllocators + * @run junit/othervm -Djdk.internal.foreign.native.confined.pool.power.size=5 TestSegmentAllocators */ import java.lang.foreign.*; +import jdk.test.lib.thread.VThreadRunner; import java.lang.foreign.Arena; import java.lang.invoke.VarHandle; +import java.lang.reflect.Method; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.CharBuffer; @@ -52,14 +59,32 @@ import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.InvocationInterceptor; +import org.junit.jupiter.api.extension.ReflectiveInvocationContext; +import org.junit.jupiter.params.Parameter; +import org.junit.jupiter.params.ParameterizedClass; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.params.provider.MethodSource; @TestInstance(TestInstance.Lifecycle.PER_CLASS) +@ParameterizedClass +@EnumSource(TestSegmentAllocators.ThreadMode.class) +@ExtendWith(TestSegmentAllocators.ThreadModeInterceptor.class) public class TestSegmentAllocators { final static int ELEMS = 128; + @Parameter(0) + private ThreadMode threadMode; + + enum ThreadMode { + PLATFORM, + VIRTUAL + } + @SuppressWarnings("unchecked") @ParameterizedTest @MethodSource("scalarAllocations") @@ -669,4 +694,31 @@ static Object[][] allocators() { { SegmentAllocator.prefixAllocator(Arena.global().allocate(10, 1)) }, }; } + + public static final class ThreadModeInterceptor implements InvocationInterceptor { + + @Override + public void interceptTestMethod(Invocation invocation, + ReflectiveInvocationContext invocationContext, + ExtensionContext extensionContext) throws Throwable { + proceed(invocation, extensionContext); + } + + @Override + public void interceptTestTemplateMethod(Invocation invocation, + ReflectiveInvocationContext invocationContext, + ExtensionContext extensionContext) throws Throwable { + proceed(invocation, extensionContext); + } + + private static void proceed(Invocation invocation, + ExtensionContext extensionContext) throws Throwable { + TestSegmentAllocators test = (TestSegmentAllocators) extensionContext.getRequiredTestInstance(); + if (test.threadMode == ThreadMode.VIRTUAL) { + VThreadRunner.run(invocation::proceed); + } else { + invocation.proceed(); + } + } + } } diff --git a/test/jdk/java/foreign/TestSegmentCopy.java b/test/jdk/java/foreign/TestSegmentCopy.java index 53e0d0d10dfd..c20bd858dfb1 100644 --- a/test/jdk/java/foreign/TestSegmentCopy.java +++ b/test/jdk/java/foreign/TestSegmentCopy.java @@ -185,6 +185,17 @@ public void testReadOnlyCopy(SegmentKind kind1, SegmentKind kind2) { }); } + @Test + public void testClosedZeroLengthCopy() { + MemorySegment closed; + try (Arena arena = Arena.ofConfined()) { + closed = arena.allocate(4, 1); + } + var alive = MemorySegment.ofArray(new byte[4]); + assertThrows(IllegalStateException.class, () -> MemorySegment.copy(closed, 0, alive, 0, 0)); + assertThrows(IllegalStateException.class, () -> MemorySegment.copy(alive, 0, closed, 0, 0)); + } + @Test public void badCopy6Arg() { try (Arena scope = Arena.ofConfined()) { diff --git a/test/jdk/java/foreign/TestSegmentOverlap.java b/test/jdk/java/foreign/TestSegmentOverlap.java index bbade2fc4fff..1d4c1e87e62c 100644 --- a/test/jdk/java/foreign/TestSegmentOverlap.java +++ b/test/jdk/java/foreign/TestSegmentOverlap.java @@ -135,6 +135,17 @@ public void testSlices(Supplier segmentSupplier) { } } + @ParameterizedTest + @MethodSource("segmentFactories") + public void testContainedSlice(Supplier segmentSupplier) { + MemorySegment segment = segmentSupplier.get(); + // Select an inner slice whose end precedes the end of the enclosing segment. + MemorySegment slice = segment.asSlice(1, 2); + + // The overlap is limited by both segment ends, so it must not extend past the slice. + assertEquals(slice.byteSize(), segment.asOverlappingSlice(slice).orElseThrow().byteSize()); + } + enum OtherSegmentFactory { NATIVE(() -> Arena.ofAuto().allocate(16, 1)), HEAP(() -> MemorySegment.ofArray(new byte[]{16})); diff --git a/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccess.java b/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccess.java index 43d6e747935b..aca798c888ef 100644 --- a/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccess.java +++ b/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, 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 @@ -86,6 +86,7 @@ public Object[][] succeedCases() { { "panama_no_unnamed_module_native_access", UNNAMED, successWithWarning("ALL-UNNAMED"), new String[]{} }, { "panama_all_unnamed_module_native_access", UNNAMED, successNoWarning(), new String[]{"--enable-native-access=ALL-UNNAMED"} }, { "panama_allow_unnamed_module_native_access", UNNAMED, successNoWarning(), new String[]{"--illegal-native-access=allow"} }, + { "panama_allow_unnamed_module_native_access", UNNAMED, successNoWarning(), new String[]{"--illegal-native-access", "allow"} }, }; } @@ -141,7 +142,8 @@ public void testRepeatedOption() throws Exception { } /** - * Specifies bad value to --enable-native-access. + * Tests invalid values for --enable-native-access and invalid or missing + * values for --illegal-native-access. */ @Test public void testBadValue() throws Exception { @@ -163,6 +165,17 @@ public void testBadValue() throws Exception { run("panama_deny_no_module_jni", PANAMA_JNI, failWithError("module panama_jni_load_module"), "--illegal-native-access=deny"); + run("panama_deny_no_module_jni", PANAMA_JNI, + failWithError("module panama_jni_load_module"), + "--illegal-native-access", "deny"); + // Missing value. + run("panama_enable_native_access", PANAMA_MAIN, + failWithError("Value specified to --illegal-native-access not recognized"), + "--illegal-native-access"); + // Invalid value. + run("panama_enable_native_access", PANAMA_MAIN, + failWithError("Value specified to --illegal-native-access not recognized"), + "--illegal-native-access", "bad"); } @Test diff --git a/test/jdk/java/lang/Object/FinalizationOption.java b/test/jdk/java/lang/Object/FinalizationOption.java index 7d50412e26f0..bcd340209caa 100644 --- a/test/jdk/java/lang/Object/FinalizationOption.java +++ b/test/jdk/java/lang/Object/FinalizationOption.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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,12 +23,18 @@ /* * @test - * @bug 8276422 + * @bug 8276422 8387729 * @summary add command-line option to disable finalization - * @run main/othervm FinalizationOption yes - * @run main/othervm --finalization=enabled FinalizationOption yes - * @run main/othervm --finalization=disabled FinalizationOption no + * @library /test/lib + * @run main FinalizationOption enabled default + * @run main FinalizationOption enabled equals + * @run main FinalizationOption enabled whitespace + * @run main FinalizationOption disabled equals + * @run main FinalizationOption disabled whitespace */ + +import jdk.test.lib.process.ProcessTools; + public class FinalizationOption { static volatile boolean finalizerWasCalled = false; @@ -104,13 +110,54 @@ static boolean checkFinalizerCalled(boolean expected) { return passed; } - public static void main(String[] args) { - boolean finalizationEnabled = switch (args[0]) { - case "yes" -> true; - case "no" -> false; - default -> { - throw new AssertionError("usage: FinalizationOption yes|no"); - } + /* + * Each @run invocation enters main() twice: + * + * 1. jtreg invokes main() with two arguments. This calls launch() + * to start a test process. + * + * 2. The launched test process invokes main() with one argument and + * performs the actual test. + */ + public static void main(String[] args) throws Exception { + switch (args.length) { + case 2: + launch(args[0], args[1]); + return; + case 1: + test(args[0]); + return; + default: + throw new AssertionError( + "expected one or two arguments"); + } + } + + /** + * Launch a test process with the given command-line option form. + */ + static void launch(String option, String form) throws Exception { + String[] javaArgs = switch (form) { + case "default" -> new String[] {"FinalizationOption", option}; + case "equals" -> new String[] {"--finalization=" + option, + "FinalizationOption", option}; + case "whitespace" -> new String[] {"--finalization", option, + "FinalizationOption", option}; + default -> throw new AssertionError("Unexpected option form: " + form); + }; + + ProcessTools.executeTestJava(javaArgs).shouldHaveExitValue(0); + } + + /** + * Perform the actual finalization test. + */ + static void test(String option) throws Exception { + boolean finalizationEnabled = switch (option) { + case "enabled" -> true; + case "disabled" -> false; + default -> throw new AssertionError( + "usage: FinalizationOption enabled|disabled"); }; boolean threadPass = checkFinalizerThread(finalizationEnabled); diff --git a/test/jdk/java/lang/Object/InvalidFinalizationOption.java b/test/jdk/java/lang/Object/InvalidFinalizationOption.java index f87ecfe9045b..8dcaf153368b 100644 --- a/test/jdk/java/lang/Object/InvalidFinalizationOption.java +++ b/test/jdk/java/lang/Object/InvalidFinalizationOption.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 8276422 + * @bug 8276422 8387729 * @summary Invalid/missing values for the finalization option should be rejected * @library /test/lib * @run driver InvalidFinalizationOption @@ -34,12 +34,17 @@ public class InvalidFinalizationOption { public static void main(String[] args) throws Exception { - record TestData(String arg, String expected) { } + record TestData(String[] arg, String expected) { } TestData[] testData = { - new TestData("--finalization", "Unrecognized option"), - new TestData("--finalization=", "Invalid finalization value"), - new TestData("--finalization=azerty", "Invalid finalization value") + new TestData(new String[] { "--finalization" }, + "Invalid finalization value"), + new TestData(new String[] { "--finalization=" }, + "Invalid finalization value"), + new TestData(new String[] { "--finalization=azerty" }, + "Invalid finalization value"), + new TestData(new String[] { "--finalization", "azerty" }, + "Invalid finalization value") }; for (var data : testData) { diff --git a/test/jdk/java/lang/reflect/Field/mutateFinals/cli/CommandLineTest.java b/test/jdk/java/lang/reflect/Field/mutateFinals/cli/CommandLineTest.java index 34f9bb2bd5b0..00a854f06baa 100644 --- a/test/jdk/java/lang/reflect/Field/mutateFinals/cli/CommandLineTest.java +++ b/test/jdk/java/lang/reflect/Field/mutateFinals/cli/CommandLineTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 8353835 + * @bug 8353835 8387729 * @summary Test the command line option --enable-final-field-mutation * @library /test/lib * @build CommandLineTestHelper @@ -84,18 +84,27 @@ void testDefault() throws Exception { */ @Test void testAllow() throws Exception { - test("testFieldSetInt", "--illegal-final-field-mutation=allow") - .shouldNotContain(WARNING_LINE1) - .shouldNotContain(WARNING_MUTATED) - .shouldHaveExitValue(0); + for (String[] opt : optionForms("--illegal-final-field-mutation", "allow")) { + test("testFieldSetInt", opt) + .shouldNotContain(WARNING_LINE1) + .shouldNotContain(WARNING_MUTATED) + .shouldHaveExitValue(0); + } + + for (String[] opt : optionForms("--enable-final-field-mutation", "ALL-UNNAMED")) { + test("testFieldSetInt", opt) + .shouldNotContain(WARNING_LINE1) + .shouldNotContain(WARNING_MUTATED) + .shouldHaveExitValue(0); + } - test("testFieldSetInt", "--enable-final-field-mutation=ALL-UNNAMED") + // allow ALL-UNNAMED, deny by default + test("testFieldSetInt", "--enable-final-field-mutation=ALL-UNNAMED", "--illegal-final-field-mutation=deny") .shouldNotContain(WARNING_LINE1) .shouldNotContain(WARNING_MUTATED) .shouldHaveExitValue(0); - // allow ALL-UNNAMED, deny by default - test("testFieldSetInt", "--enable-final-field-mutation=ALL-UNNAMED", "--illegal-final-field-mutation=deny") + test("testFieldSetInt", "--enable-final-field-mutation", "ALL-UNNAMED", "--illegal-final-field-mutation", "deny") .shouldNotContain(WARNING_LINE1) .shouldNotContain(WARNING_MUTATED) .shouldHaveExitValue(0); @@ -122,12 +131,14 @@ void testAllow() throws Exception { */ @Test void testWarn() throws Exception { - test("testFieldSetInt", "--illegal-final-field-mutation=warn") - .shouldContain(WARNING_LINE1) - .shouldContain(WARNING_MUTATED) - .shouldContain(WARNING_LINE3) - .shouldContain(WARNING_LINE4) - .shouldHaveExitValue(0); + for (String[] opt : optionForms("--illegal-final-field-mutation", "warn")) { + test("testFieldSetInt", opt) + .shouldContain(WARNING_LINE1) + .shouldContain(WARNING_MUTATED) + .shouldContain(WARNING_LINE3) + .shouldContain(WARNING_LINE4) + .shouldHaveExitValue(0); + } test("testUnreflectSetter", "--illegal-final-field-mutation=warn") .shouldContain(WARNING_LINE1) @@ -162,13 +173,15 @@ void testWarn() throws Exception { */ @Test void testDebug() throws Exception { - test("testFieldSetInt+testUnreflectSetter", "--illegal-final-field-mutation=debug") - .shouldContain("Final field value in class " + HELPER) - .shouldContain(WARNING_MUTATED) - .shouldContain("java.lang.reflect.Field.setInt") - .shouldContain(WARNING_UNREFLECTED) - .shouldContain("java.lang.invoke.MethodHandles$Lookup.unreflectSetter") - .shouldHaveExitValue(0); + for (String[] opt : optionForms("--illegal-final-field-mutation", "debug")) { + test("testFieldSetInt+testUnreflectSetter", opt) + .shouldContain("Final field value in class " + HELPER) + .shouldContain(WARNING_MUTATED) + .shouldContain("java.lang.reflect.Field.setInt") + .shouldContain(WARNING_UNREFLECTED) + .shouldContain("java.lang.invoke.MethodHandles$Lookup.unreflectSetter") + .shouldHaveExitValue(0); + } test("testUnreflectSetter+testFieldSetInt", "--illegal-final-field-mutation=debug") .shouldContain("Final field value in class " + HELPER) @@ -184,11 +197,13 @@ void testDebug() throws Exception { */ @Test void testDeny() throws Exception { - test("testFieldSetInt", "--illegal-final-field-mutation=deny") - .shouldNotContain(WARNING_LINE1) - .shouldNotContain(WARNING_MUTATED) - .shouldContain("java.lang.IllegalAccessException") - .shouldNotHaveExitValue(0); + for (String[] opt : optionForms("--illegal-final-field-mutation", "deny")) { + test("testFieldSetInt", opt) + .shouldNotContain(WARNING_LINE1) + .shouldNotContain(WARNING_MUTATED) + .shouldContain("java.lang.IllegalAccessException") + .shouldNotHaveExitValue(0); + } test("testUnreflectSetter", "--illegal-final-field-mutation=deny") .shouldNotContain(WARNING_LINE1) @@ -202,7 +217,17 @@ void testDeny() throws Exception { */ @Test void testLastOneWins() throws Exception { - test("testFieldSetInt", "--illegal-final-field-mutation=allow", "--illegal-final-field-mutation=deny") + test("testFieldSetInt", + "--illegal-final-field-mutation=allow", + "--illegal-final-field-mutation=deny") + .shouldNotContain(WARNING_LINE1) + .shouldNotContain(WARNING_MUTATED) + .shouldContain("java.lang.IllegalAccessException") + .shouldNotHaveExitValue(0); + + test("testFieldSetInt", + "--illegal-final-field-mutation", "allow", + "--illegal-final-field-mutation", "deny") .shouldNotContain(WARNING_LINE1) .shouldNotContain(WARNING_MUTATED) .shouldContain("java.lang.IllegalAccessException") @@ -220,9 +245,11 @@ void testLastOneWins() throws Exception { @ParameterizedTest @ValueSource(strings = { "", "bad" }) void testInvalidValues(String value) throws Exception { - test("testFieldSetInt", "--illegal-final-field-mutation=" + value) - .shouldContain("Value specified to --illegal-final-field-mutation not recognized") - .shouldNotHaveExitValue(0); + for (String[] opt : optionForms("--illegal-final-field-mutation", value)) { + test("testFieldSetInt", opt) + .shouldContain("Value specified to --illegal-final-field-mutation not recognized") + .shouldNotHaveExitValue(0); + } } /** @@ -291,4 +318,14 @@ private OutputAnalyzer test(String action, String... vmopts) throws Exception { private int countStrings(String input, String substring) { return input.split(Pattern.quote(substring)).length - 1; } + + /** + * Returns the given option in both supported argument forms. + */ + private String[][] optionForms(String option, String value) { + return new String[][] { + { option + "=" + value }, + { option, value } + }; + } } diff --git a/test/jdk/java/net/httpclient/IdleConnectionTimeoutReuseTest.java b/test/jdk/java/net/httpclient/IdleConnectionTimeoutReuseTest.java index a99115717c00..e38eadfee101 100644 --- a/test/jdk/java/net/httpclient/IdleConnectionTimeoutReuseTest.java +++ b/test/jdk/java/net/httpclient/IdleConnectionTimeoutReuseTest.java @@ -87,7 +87,7 @@ * carrier thread pool (i.e., FJP) requires `parallelism <= maxPoolSize` * and having 1 thread in the pool is easier to make it starve. * - * @requires os.family != "windows" + * @requires os.family != "windows" & test.thread.factory != "Virtual" * * @run junit/othervm * -Djdk.httpclient.keepalive.timeout=1 diff --git a/test/jdk/javax/swing/JPopupMenu/6800513/bug6800513.java b/test/jdk/javax/swing/JPopupMenu/6800513/bug6800513.java index f7d78f9e41d8..436addc753e1 100644 --- a/test/jdk/javax/swing/JPopupMenu/6800513/bug6800513.java +++ b/test/jdk/javax/swing/JPopupMenu/6800513/bug6800513.java @@ -1,6 +1,6 @@ /* * Copyright 2012 Red Hat, Inc. All Rights Reserved. - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, 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,8 @@ public static void main(String[] args) throws Exception { robot = new Robot(); testFrame(false, "javax.swing.PopupFactory$HeavyWeightPopup"); - testFrame(true, "javax.swing.PopupFactory$LightWeightPopup"); + if (!((UIManager.getLookAndFeel().getID()).equals("Aqua"))) { + testFrame(true, "javax.swing.PopupFactory$LightWeightPopup"); + } } } diff --git a/test/jdk/jdk/incubator/json/TestAccess.java b/test/jdk/jdk/incubator/json/TestAccess.java new file mode 100644 index 000000000000..488dee5f75c4 --- /dev/null +++ b/test/jdk/jdk/incubator/json/TestAccess.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2025, 2026, 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 8381976 + * @summary Unit tests for access methods. + * @modules jdk.incubator.json + * @run junit TestAccess + */ + +import jdk.incubator.json.Json; +import jdk.incubator.json.JsonArray; +import jdk.incubator.json.JsonNumber; +import jdk.incubator.json.JsonValueException; +import jdk.incubator.json.JsonNull; +import jdk.incubator.json.JsonString; +import jdk.incubator.json.JsonValue; + +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +public class TestAccess { + + private static final JsonValue JSON_ROOT_ARRAY = Json.parse( + """ + [ + { "name": "John", + "age": 42 + }, + { + "name": "Mary", + "age": 31 + } + ] + """); + + private static final JsonValue JSON_ROOT_OBJECT = Json.parse( + """ + { + "id" : 1, + "values" : [ "value", null ], "valuesWithCommas" : [ "v[a]lu}\\"e", "va,,,[lue,", "value,,", 15], + "foo" : { "bar" : "baz" }, + "qux" : [ [true], { "in" : { } } ], + "ba\\"zz" : ["Key with escape"], + "obj" : { "1" : "{", "z" : 2} + } + """); + + private static final JsonValue JSON_NESTED_ARRAY = + // Don't use the API we are testing (get(String)) + JSON_ROOT_OBJECT.asMap().get("values"); + + @Test + void basicAccessTest() { + JSON_ROOT_OBJECT.get("id"); + assertEquals("value", JSON_ROOT_OBJECT.get("values").get(0).asString()); + assertTrue(JSON_ROOT_OBJECT.get("values").get(1) instanceof JsonNull); + assertTrue(JSON_ROOT_OBJECT.get("qux").get(0).get(0).asBoolean()); + } + + @Test + void boolAndNullFailureTest() { + var json = Json.parse("{ \"foo\" : null, \"bar\" : false, \"baz\" : true }"); + assertThrows(JsonValueException.class, () -> json.get("foo").tryGet("_")); + assertThrows(JsonValueException.class, () -> json.get("bar").tryGet("_")); + assertThrows(JsonValueException.class, () -> json.get("baz").tryGet("_")); + } + + @Test + void basicAccessAbsenceTest() { + var json = Json.parse("{ \"foo\" : null, \"bar\" : \"words\" }"); + assertEquals(Optional.empty(), json.tryGet("baz")); + assertNull(json.tryGet("baz").map(JsonValue::asString).orElse(null)); + assertEquals("words", json.tryGet("bar").map(JsonValue::asString).orElse(null)); + assertThrows(JsonValueException.class, () -> json.get("foo").tryGet("baz")); + } + + @Test + void basicAccessNullTest() { + var json = Json.parse("{ \"foo\" : null, \"bar\" : \"words\" }"); + assertEquals(Optional.empty(), json.get("foo").tryValue()); + assertNull(json.get("foo").tryValue().map(JsonValue::asString).orElse(null)); + assertEquals("words", json.get("bar").tryValue().map(JsonValue::asString).orElse(null)); + } + + // Ensure that syntactical chars w/in JsonString do not affect path building + @Test + void stringTest() { + assertEquals("JsonNumber is not a JsonString. Path: \"{valuesWithCommas[3\". Location: line 2, position 96.", + assertThrows(JsonValueException.class, + () -> JSON_ROOT_OBJECT.get("valuesWithCommas").get(3).asString()).getMessage()); + assertEquals("JsonNumber is not a JsonBoolean. Path: \"{obj{z\". Location: line 6, position 31.", + assertThrows(JsonValueException.class, + () -> JSON_ROOT_OBJECT.get("obj").get("z").asBoolean()).getMessage()); + } + + @Test + void leafExceptionTest() { + assertEquals("JsonNumber is not a JsonString. Path: \"[1{age\". Location: line 6, position 11.", + assertThrows(JsonValueException.class, + () -> JSON_ROOT_ARRAY.get(1).get("age").asString()).getMessage()); + } + + @Test + void rootArrayTest() { + assertEquals("JsonObject member \"asge\" does not exist. Path: \"[1\". Location: line 4, position 2.", + assertThrows(JsonValueException.class, + () -> JSON_ROOT_ARRAY.get(1).get("asge").asLong()).getMessage()); + } + + // Ensure member name with escapes works + @Test + void escapedKeyTest() { + assertEquals("JsonArray index 1 out of bounds for length 1. Path: \"{ba\\\"zz\". Location: line 5, position 15.", + assertThrows(JsonValueException.class, + () -> JSON_ROOT_OBJECT.get("ba\"zz").get(1)).getMessage()); + } + + @Test + void multiNestedTest() { + assertEquals("JsonObject member \"zap\" does not exist. Path: \"{qux[1{in\". Location: line 4, position 31.", + assertThrows(JsonValueException.class, + () -> JSON_ROOT_OBJECT.get("qux").get(1).get("in").get("zap")).getMessage()); + } + + // Check array path building behavior for first element, expects '['. + @Test + void firstArrayElementTest() { + assertEquals("JsonArray index 5 out of bounds for length 1. Path: \"{qux[0\". Location: line 4, position 14.", + assertThrows(JsonValueException.class, + () -> JSON_ROOT_OBJECT.get("qux").get(0).get(5)).getMessage()); + } + + // Operations on JsonObject + @Test + void failObjectAccessTest() { + // Points to the start of the root object -> { ... + assertEquals("JsonObject is not a JsonArray. Path: \"\". Location: line 0, position 3.", + assertThrows(JsonValueException.class, () -> JSON_ROOT_OBJECT.get(0)).getMessage()); + assertEquals("JsonObject member \"car\" does not exist. Path: \"\". Location: line 0, position 3.", + assertThrows(JsonValueException.class, () -> JSON_ROOT_OBJECT.get("car")).getMessage()); + } + + // Operations on JsonArray + @Test + void failArrayAccessTest() { + // Points to the JsonArray value of "values"; starts at -> [ "value", null ] ... + assertEquals("JsonArray is not a JsonObject. Path: \"{values\". Location: line 2, position 15.", + assertThrows(JsonValueException.class, () -> JSON_NESTED_ARRAY.get("foo")).getMessage()); + assertEquals("JsonArray index 3 out of bounds for length 2. Path: \"{values\". Location: line 2, position 15.", + assertThrows(JsonValueException.class, () -> JSON_NESTED_ARRAY.get(3)).getMessage()); + } + + @Test + void failNPETest() { + // NPE at JsonObject + assertThrows(NullPointerException.class, () -> JSON_ROOT_OBJECT.get(null)); + // NPE at JsonValue + assertThrows(NullPointerException.class, () -> JSON_NESTED_ARRAY.get(null)); + } + + // Access on factory created JSON number/string should not have a path + @Test + void factoryPathTest() { + assertFalse(assertThrows(JsonValueException.class, () -> JsonArray.of( + List.of(JsonNumber.of(1.5))).get(0).asLong()).getMessage().contains("Path")); + assertFalse(assertThrows(JsonValueException.class, () -> JsonArray.of( + List.of(JsonNumber.of(1))).get(0).asBoolean()).getMessage().contains("Path")); + assertFalse(assertThrows(JsonValueException.class, () -> JsonArray.of( + List.of(JsonNumber.of(1L))).get(0).asBoolean()).getMessage().contains("Path")); + assertFalse(assertThrows(JsonValueException.class, () -> JsonArray.of( + List.of(JsonNumber.of("1.5"))).get(0).asBoolean()).getMessage().contains("Path")); + assertFalse(assertThrows(JsonValueException.class, () -> JsonArray.of( + List.of(JsonString.of("foo"))).get(0).asBoolean()).getMessage().contains("Path")); + } +} diff --git a/test/jdk/jdk/incubator/json/TestGenerate.java b/test/jdk/jdk/incubator/json/TestGenerate.java new file mode 100644 index 000000000000..85d04999814f --- /dev/null +++ b/test/jdk/jdk/incubator/json/TestGenerate.java @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2025, 2026, 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 8381976 + * @summary Tests methods that generate JSON texts + * @modules jdk.incubator.json + * @run junit TestGenerate + */ + +import java.util.List; +import jdk.incubator.json.Json; +import jdk.incubator.json.JsonArray; +import jdk.incubator.json.JsonNumber; +import jdk.incubator.json.JsonString; +import jdk.incubator.json.JsonValue; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.FieldSource; + +import static org.junit.jupiter.api.Assertions.*; + +public class TestGenerate { + + private static final String SRC = + """ + [ + { "name": "John", "age": 30, "city": "New-York" }, + { "name": "Jane", "age": 20, "city": "Boston" }, + true, + false, + null, + [ "array", "inside", {"inner-obj": true, "top-level": false}], + "foo", + 42 + ] + """; + + @Test + void testToString() { + var jv = Json.parse(SRC); + var result = jv.toString(); + var expected = SRC.replaceAll("[\n ]", ""); + assertEquals(expected, result); + } + + @Test + void testToDisplayString_NullIndent() { + assertThrows(NullPointerException.class, + () -> Json.toDisplayString(JsonString.of("foo"), null)); + } + + @Test + void testToDisplayString_InvalidIndent() { + assertThrows(IllegalArgumentException.class, + () -> Json.toDisplayString(JsonString.of("foo"), "abc")); + } + + private static final List DISPLAYSTRING = List.of( + Arguments.of("", + """ + [ + { + "name": "John", + "age": 30, + "city": "New-York" + }, + { + "name": "Jane", + "age": 20, + "city": "Boston" + }, + true, + false, + null, + [ + "array", + "inside", + { + "inner-obj": true, + "top-level": false + } + ], + "foo", + 42 + ]"""), + Arguments.of(" ", + """ + [ + { + "name": "John", + "age": 30, + "city": "New-York" + }, + { + "name": "Jane", + "age": 20, + "city": "Boston" + }, + true, + false, + null, + [ + "array", + "inside", + { + "inner-obj": true, + "top-level": false + } + ], + "foo", + 42 + ]"""), + Arguments.of(" ", + """ + [ + { + "name": "John", + "age": 30, + "city": "New-York" + }, + { + "name": "Jane", + "age": 20, + "city": "Boston" + }, + true, + false, + null, + [ + "array", + "inside", + { + "inner-obj": true, + "top-level": false + } + ], + "foo", + 42 + ]"""), + Arguments.of("\t\r\n\u0020 ", + """ + [ + \t\r\n\u0020 { + \t\r\n\u0020 \t\r\n\u0020 "name": "John", + \t\r\n\u0020 \t\r\n\u0020 "age": 30, + \t\r\n\u0020 \t\r\n\u0020 "city": "New-York" + \t\r\n\u0020 }, + \t\r\n\u0020 { + \t\r\n\u0020 \t\r\n\u0020 "name": "Jane", + \t\r\n\u0020 \t\r\n\u0020 "age": 20, + \t\r\n\u0020 \t\r\n\u0020 "city": "Boston" + \t\r\n\u0020 }, + \t\r\n\u0020 true, + \t\r\n\u0020 false, + \t\r\n\u0020 null, + \t\r\n\u0020 [ + \t\r\n\u0020 \t\r\n\u0020 "array", + \t\r\n\u0020 \t\r\n\u0020 "inside", + \t\r\n\u0020 \t\r\n\u0020 { + \t\r\n\u0020 \t\r\n\u0020 \t\r\n\u0020 "inner-obj": true, + \t\r\n\u0020 \t\r\n\u0020 \t\r\n\u0020 "top-level": false + \t\r\n\u0020 \t\r\n\u0020 } + \t\r\n\u0020 ], + \t\r\n\u0020 "foo", + \t\r\n\u0020 42 + ]""") + ); + + @ParameterizedTest + @FieldSource("DISPLAYSTRING") + void testDisplayString(String indent, String expected) { + assertEquals(expected, Json.toDisplayString(Json.parse(SRC), indent)); + } + + @Test + void testEscapesMemberNames() { + var json = Json.parse("{ \"a\\\"b\" : null }"); + var display = Json.toDisplayString(json, " "); + + assertEquals(""" + { + "a\\\"b": null + }""", display); + + assertDoesNotThrow(() -> Json.parse(display)); + } + + @Test + void testDeepNestingToString() { + assertDoesNotThrow(() -> deepNest().toString()); + } + + @Test + void testDeepNestingToDisplayString() { + assertDoesNotThrow(() -> Json.toDisplayString(deepNest(), "")); + } + + private static JsonValue deepNest() { + int depth = 10_000; + JsonValue jv = JsonNumber.of(0); + for (int i = 0; i < depth; i++) { + jv = JsonArray.of(List.of(jv)); + } + return jv; + } +} diff --git a/test/jdk/jdk/incubator/json/TestJsonArray.java b/test/jdk/jdk/incubator/json/TestJsonArray.java new file mode 100644 index 000000000000..f610e967e412 --- /dev/null +++ b/test/jdk/jdk/incubator/json/TestJsonArray.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2025, 2026, 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 8381976 + * @summary Unit tests for JsonArray + * @modules jdk.incubator.json + * @run junit TestJsonArray + */ + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.FieldSource; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import jdk.incubator.json.Json; +import jdk.incubator.json.JsonArray; +import jdk.incubator.json.JsonBoolean; +import jdk.incubator.json.JsonNull; +import jdk.incubator.json.JsonNumber; +import jdk.incubator.json.JsonObject; +import jdk.incubator.json.JsonParseException; +import jdk.incubator.json.JsonString; +import jdk.incubator.json.JsonValue; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class TestJsonArray { + + @Nested + class TestParse { + + // Some basic malformed JSON arrays and expected error message + static List BASIC_FAIL = List.of( + Arguments.of("[ \"foo\" ", + "JSON Array is not closed with a bracket. Path: \"[\". Location: line 0, position 9."), + Arguments.of("[ \"foo\", ", + "Expected a JSON Object, Array, String, Number, Boolean, or Null. Path: \"[1\". Location: line 0, position 10."), + Arguments.of("[ ", + "JSON Array is not closed with a bracket. Path: \"[\". Location: line 0, position 2."), + Arguments.of("null ]", + "Additional value(s) were found after the JSON Value. Path: \"\". Location: line 0, position 5."), + Arguments.of("[ [ [ 0, 1, two ] ] ]", + "Unexpected value. Expected a JSON Object, Array, String, Number, Boolean, or Null. Path: \"[0[0[2\". Location: line 0, position 13.")); + + @ParameterizedTest + @FieldSource("BASIC_FAIL") + void basicFailParse(String json, String expected) { + var e = assertThrows(JsonParseException.class, () -> Json.parse(json), + "String parse did not fail for %s".formatted(json)); + assertEquals(expected, e.getMessage()); + e = assertThrows(JsonParseException.class, () -> Json.parse(json.toCharArray()), + "Char parse did not fail for %s".formatted(json)); + assertEquals(expected, e.getMessage()); + } + } + + @Nested + class TestFactory { + + // Ensure equivalence of JsonArray created from parse vs of factory + @Test + void testFactory() { + + var doc = Json.parse( + """ + [1, "two", false, null, {"name": 42}, [1]] + """); + + var expected = JsonArray.of( + List.of( + JsonNumber.of(1), + JsonString.of("two"), + JsonBoolean.of(Boolean.FALSE), + JsonNull.of(), + JsonObject.of(Map.of("name", JsonNumber.of(42))), + JsonArray.of(List.of(JsonNumber.of(1))) + ) + ).asList(); + if (doc instanceof JsonArray ja) { + //only compare types + compareTypes(expected, ja.asList()); + } else { + throw new RuntimeException("JsonArray expected"); + } + } + + private static void compareTypes(List expected, List actual) { + assertEquals(expected.size(), actual.size()); + for (int index = 0; index < expected.size(); index++) { + assertEquals(expected.get(index).getClass(), actual.get(index).getClass()); + } + } + + @Test + void immutabilityOfTest() { + var list = new ArrayList(); + list.add(JsonString.of("foo")); + var ja = JsonArray.of(list); + assertEquals(1, ja.asList().size()); + // Modifications to backed list should not change JsonArray + list.add(JsonString.of("foo")); + assertEquals(1, ja.asList().size()); + // Modifications to JsonArray asList() should throw + assertThrows(UnsupportedOperationException.class, + () -> ja.asList().add(JsonNull.of()), + "Array values able to be modified"); + } + + @Test + void nullTest() { + // null list to of factory + assertThrows(NullPointerException.class, () -> JsonArray.of(null)); + List list = new ArrayList<>(); + list.add(null); + // JsonArray.of() should throw as typed to JsonValue + assertThrows(NullPointerException.class, () -> JsonArray.of(list)); + } + } +} diff --git a/test/jdk/jdk/incubator/json/TestJsonLiteral.java b/test/jdk/jdk/incubator/json/TestJsonLiteral.java new file mode 100644 index 000000000000..01c74d225e59 --- /dev/null +++ b/test/jdk/jdk/incubator/json/TestJsonLiteral.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2025, 2026, 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 8381976 + * @summary Unit tests for JsonBoolean and JsonNull + * @modules jdk.incubator.json + * @run junit TestJsonLiteral + */ + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.FieldSource; + +import java.util.List; +import jdk.incubator.json.Json; +import jdk.incubator.json.JsonBoolean; +import jdk.incubator.json.JsonNull; +import jdk.incubator.json.JsonParseException; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class TestJsonLiteral { + + void conversionTest() { + assertTrue(JsonBoolean.of(true).asBoolean()); + assertFalse(JsonBoolean.of(false).asBoolean()); + } + + @Nested + class TestParse { + + @ParameterizedTest + @FieldSource("BASIC_VALID") + void basicValidParse(String json) { + assertDoesNotThrow(() -> Json.parse(json), + "String parse failed for %s".formatted(json)); + assertDoesNotThrow(() -> Json.parse(json.toCharArray()), + "Char parse failed for %s".formatted(json)); + } + + // Basic JSON primitives + static List BASIC_VALID = + Stream.of("%s", " %s", "%s ", " %s ", "[%s]", "{\"foo\":%s}") + .flatMap(s -> Stream.of("true", "false", "null").map(s::formatted)).toList(); + + @ParameterizedTest + @FieldSource("BASIC_FAIL") + void basicFailParse(String json) { + assertThrows(JsonParseException.class, () -> Json.parse(json), + "String parse did not fail for %s".formatted(json)); + assertThrows(JsonParseException.class, () -> Json.parse(json.toCharArray()), + "Char parse did not fail for %s".formatted(json)); + } + + // Basic JSON primitives and expected parse exception message + static List BASIC_FAIL = + List.of( + // Null + Arguments.of("nul", "Expected null"), + Arguments.of("n", "Expected null"), + // Boolean + Arguments.of("fals", "Expected false"), + Arguments.of("f", "Expected false"), + Arguments.of("tru", "Expected true"), + Arguments.of("t", "Expected true") + ); + } + + @Nested + class TestFactory { + + @Test + void booleanOfTest() { + assertTrue(JsonBoolean.of(true).asBoolean()); + assertFalse(JsonBoolean.of(false).asBoolean()); + } + + @Test + void nullOfTest() { + assertTrue(JsonNull.of() instanceof JsonNull); + } + } +} diff --git a/test/jdk/jdk/incubator/json/TestJsonNumber.java b/test/jdk/jdk/incubator/json/TestJsonNumber.java new file mode 100644 index 000000000000..9e39340eae92 --- /dev/null +++ b/test/jdk/jdk/incubator/json/TestJsonNumber.java @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2025, 2026, 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 8381976 + * @summary Unit tests for JsonNumber + * @modules jdk.incubator.json + * @enablePreview + * @run junit TestJsonNumber + */ + +import java.util.List; +import jdk.incubator.json.Json; +import jdk.incubator.json.JsonValueException; +import jdk.incubator.json.JsonNumber; +import jdk.incubator.json.JsonParseException; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.FieldSource; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class TestJsonNumber { + + @Nested + class TestValue { + + @ParameterizedTest + @MethodSource + void testUniformRepresentations(String str, double db, long l, int i) { + var json = Json.parse(str); + assertEquals(db, json.asDouble()); + assertEquals(l, json.asLong()); + assertEquals(i, json.asInt()); + json = Json.parse("-" + str); + assertEquals(-db, json.asDouble()); + assertEquals(-l, json.asLong()); + assertEquals(-i, json.asInt()); + } + + private static Stream testUniformRepresentations() { + return Stream.of( + Arguments.of("5", 5d, 5L, 5), + Arguments.of("5.0", 5d, 5L, 5), + Arguments.of("5.00", 5d, 5L, 5), + Arguments.of("5e0", 5d, 5L, 5), + Arguments.of("5e+0", 5d, 5L, 5), + Arguments.of("5e-0", 5d, 5L, 5), + Arguments.of("5e3", 5e3, 5000L, 5000), + Arguments.of("50e-1", 50e-1, 5L, 5), + Arguments.of("50.0e-1", 50.0e-1, 5L, 5), + Arguments.of("555.5e5", 555.5e5, 55550000L, 55550000), + Arguments.of("555.5e1", 555.5e1, 5555L, 5555), + Arguments.of("0e999999999999", 0d, 0L, 0), + Arguments.of("0.0e-999999999999", 0d, 0L, 0) + ); + } + + @ParameterizedTest + @MethodSource + void testDoubleRepresentation(String str, double d) { + var json = Json.parse(str); + assertEquals(d, json.asDouble()); + assertThrows(JsonValueException.class, json::asLong); + json = Json.parse("-" + str); + assertEquals(-d, json.asDouble()); + assertThrows(JsonValueException.class, json::asLong); + } + + private static Stream testDoubleRepresentation() { + return Stream.of( + Arguments.of("0.01", 0.01), + Arguments.of("0.3232e-3", 0.3232e-3), + Arguments.of("0.55", 0.55), + Arguments.of("55.55", 55.55), + Arguments.of("5e-5", 5e-5), + Arguments.of("5.55e-5", 5.55e-5), + Arguments.of("5.00e-5", 5.00e-5), + Arguments.of("5e100", 5e100), + Arguments.of("55.55e1", 55.55e1), + Arguments.of("55.55e+1", 55.55e1), + Arguments.of("1.7976931348623157E308", 1.7976931348623157E308), + Arguments.of("9223372036854775999", 9223372036854775999d), + Arguments.of("9223372036854775999e0", 9223372036854775999d), + Arguments.of("5e-100", 5e-100), + Arguments.of("5.000e-100", 5e-100), + Arguments.of("1e-999999999999", 0.0) + ); + } + + @ParameterizedTest + @MethodSource + void testLongRepresentation(String str, long l) { + var json = Json.parse(str); + assertEquals(l, json.asLong()); + assertDoesNotThrow(json::asDouble); + json = Json.parse("-" + str); + assertEquals(-l, json.asLong()); + assertDoesNotThrow(json::asDouble); + } + + private static Stream testLongRepresentation() { + return Stream.of( + Arguments.of("9007199254740993", 9007199254740993L), + Arguments.of("9007199254740993.0", 9007199254740993L), + Arguments.of("9007199254740993.0e0", 9007199254740993L), + Arguments.of("9223372036854775807", 9223372036854775807L), + Arguments.of("9223372036854775807.0", 9223372036854775807L), + Arguments.of("9223372036854775807.0e0", 9223372036854775807L), + Arguments.of("9223372036854775807.0e-0", 9223372036854775807L), + Arguments.of("92233720368547758070.0e-1", 9223372036854775807L), + Arguments.of("922337203685477580700.0e-2", 9223372036854775807L) + ); + } + + @ParameterizedTest + @MethodSource + void testIntRepresentation(String str, int i) { + var json = Json.parse(str); + assertEquals(i, json.asInt()); + assertDoesNotThrow(json::asLong); + assertDoesNotThrow(json::asDouble); + json = Json.parse("-" + str); + assertEquals(-i, json.asInt()); + assertDoesNotThrow(json::asLong); + assertDoesNotThrow(json::asDouble); + } + + private static Stream testIntRepresentation() { + return Stream.of( + Arguments.of("2147483647", Integer.MAX_VALUE), + Arguments.of("2147483647.0", Integer.MAX_VALUE), + Arguments.of("2147483647.0e0", Integer.MAX_VALUE) + ); + } + + @ParameterizedTest + @MethodSource + void testDoubleOutOfRange(String str) { + var json = Json.parse(str); + assertThrows(JsonValueException.class, json::asDouble); + } + + private static Stream testDoubleOutOfRange() { + return Stream.of( + Arguments.of("9e111111111111"), + Arguments.of("-9e111111111111"), + Arguments.of("1.7976931348623159E308"), + Arguments.of("-1.7976931348623159E308") + ); + } + + @ParameterizedTest + @MethodSource + void testLongOutOfRange(String str) { + var json = Json.parse(str); + assertThrows(JsonValueException.class, json::asLong); + } + + private static Stream testLongOutOfRange() { + return Stream.of( + Arguments.of("9e111111111111"), + Arguments.of("-9e111111111111"), + Arguments.of("9223372036854775808"), + Arguments.of("-9223372036854775809") + ); + } + + @ParameterizedTest + @MethodSource + void testIntOutOfRange(String str) { + var json = Json.parse(str); + assertThrows(JsonValueException.class, json::asInt); + } + + private static Stream testIntOutOfRange() { + return Stream.of( + Arguments.of("2147483648"), + Arguments.of("-2147483649") + ); + } + } + + @Nested + class TestParse { + + @ParameterizedTest + @MethodSource("parseCases") + void testToString_Parsed(String src) { + // assert their toString() returns the original text + assertEquals(src, Json.parse(src).toString()); + } + + private static Stream parseCases() { + return Stream.of( + Arguments.of("1"), + Arguments.of("0"), + Arguments.of("9223372036854775807"), + Arguments.of("-9223372036854775808"), + Arguments.of("1.0"), + Arguments.of("9223372036854775807.0"), + Arguments.of("-9223372036854775808.0"), + Arguments.of("9223372036854775807e0"), + Arguments.of("-9223372036854775807e0"), + Arguments.of("1e0"), + Arguments.of("1e-0"), + Arguments.of("0.0"), + Arguments.of("-0.0"), + Arguments.of("0e0"), + Arguments.of("0e1"), + Arguments.of("0e-0"), + Arguments.of("0e-1"), + Arguments.of("5.5e1"), + Arguments.of("1.0e1"), + Arguments.of("1.0"), + Arguments.of("1.000"), + Arguments.of("0.001e3"), + Arguments.of("5.5"), + Arguments.of("4.9999999"), + Arguments.of("4.999999999999999999999999999999999999"), + Arguments.of("9007199254740989.5"), + Arguments.of("9007199254740990.999999999999"), + Arguments.of("0.0000123E-0000000045"), + Arguments.of("5."+"5".repeat(17)), + Arguments.of("55.55e1"), + Arguments.of("1e-1"), + Arguments.of("9223372036854775806.5"), + Arguments.of("-9223372036854775807.5"), + Arguments.of("4.9E-324"), + Arguments.of("9223372036854775807.5e0"), + Arguments.of("9223372036854775808e0"), + Arguments.of("1.7976931348623157E308") + ); + } + + private static Stream testToStringEquality() { + return Stream.of( + Arguments.of("3", "3"), + Arguments.of("3", " 3 "), + Arguments.of("3.0", "3.0"), + Arguments.of("3e0", "3E0"), + Arguments.of("3.141592653589793238462643383279", "3.141592653589793238462643383279"), + Arguments.of("3", "3.0"), + Arguments.of("3.0", "3.000"), + Arguments.of("3", "3e0"), + Arguments.of("0.0", "-0.0"), + Arguments.of("3", "4"), + Arguments.of("3.0", "3.1"), + Arguments.of("3", "3.1"), + Arguments.of("3.0", "3.001"), + Arguments.of("3", "3e1"), + Arguments.of("3.141592653589793238462643383279", "3.141592653589793238462643383278") + ); + } + + @ParameterizedTest + @MethodSource + void testToStringEquality(String arg1, String arg2) { + var jv1 = Json.parse(arg1); + var jv2 = Json.parse(arg2); + + // assert their toString() returns the original text (w/o leading/trailing spaces) + var a1 = arg1.trim(); + var a2 = arg2.trim(); + assertEquals(a1, jv1.toString()); + assertEquals(a2, jv2.toString()); + } + + private static final List INVALID_NUMBER = List.of( + Arguments.of("00", "Invalid position of '0' within JSON Number. Path: \"\". Location: line 0, position 1."), + Arguments.of("-00", "Invalid position of '0' within JSON Number. Path: \"\". Location: line 0, position 2."), + Arguments.of("01", "Invalid position of '0' within JSON Number. Path: \"\". Location: line 0, position 1."), + Arguments.of("5e-2+2", "Invalid position of '+' within JSON Number. Path: \"\". Location: line 0, position 4."), + Arguments.of("+5", "Invalid position of '+' within JSON Number. Path: \"\". Location: line 0, position 0."), + Arguments.of("5e+2-2", "Invalid position of '-' within JSON Number. Path: \"\". Location: line 0, position 4."), + Arguments.of("5e2+", "Invalid position of '+' within JSON Number. Path: \"\". Location: line 0, position 3."), + Arguments.of("5e2+2", "Invalid position of '+' within JSON Number. Path: \"\". Location: line 0, position 3."), + Arguments.of("5e2-", "Invalid position of '-' within JSON Number. Path: \"\". Location: line 0, position 3."), + Arguments.of("5e2-2", "Invalid position of '-' within JSON Number. Path: \"\". Location: line 0, position 3."), + Arguments.of(".5", "Invalid position of '.' within JSON Number. Path: \"\". Location: line 0, position 0."), + Arguments.of("5e.2", "Invalid position of '.' within JSON Number. Path: \"\". Location: line 0, position 2."), + Arguments.of("5.5.5", "Invalid position of '.' within JSON Number. Path: \"\". Location: line 0, position 3."), + Arguments.of("5e3e", "Invalid position of 'e' within JSON Number. Path: \"\". Location: line 0, position 3."), + Arguments.of("e2", "Invalid position of 'e' within JSON Number. Path: \"\". Location: line 0, position 0."), + Arguments.of("e", "Invalid position of 'e' within JSON Number. Path: \"\". Location: line 0, position 0."), + Arguments.of("5.", "Input expected after '[.|e|E]'. Path: \"\". Location: line 0, position 2."), + Arguments.of("5e", "Input expected after '[.|e|E]'. Path: \"\". Location: line 0, position 2."), + Arguments.of("5e5.5", "Invalid position of '.' within JSON Number. Path: \"\". Location: line 0, position 3."), + Arguments.of("5.5e5.5", "Invalid position of '.' within JSON Number. Path: \"\". Location: line 0, position 5.") + ); + + @ParameterizedTest + @FieldSource("INVALID_NUMBER") + void testMessages(String json, String err) { + Exception e = assertThrows(JsonParseException.class, () -> Json.parse(json)); + assertEquals(err, e.getMessage()); + } + } + + @Nested + class TestFactory { + + @Test + void testInfinity() { + assertThrows(IllegalArgumentException.class, () -> JsonNumber.of(Double.POSITIVE_INFINITY)); + assertThrows(IllegalArgumentException.class, () -> JsonNumber.of(Double.NEGATIVE_INFINITY)); + } + + @Test + void testNan() { + assertThrows(IllegalArgumentException.class, () -> JsonNumber.of(Double.NaN)); + // parse test not required for Nan, cannot parse "NaN" + } + + @Test + void testToString_factory() { + assertEquals("42", JsonNumber.of((byte)42).toString()); + assertEquals("42", JsonNumber.of((short)42).toString()); + assertEquals("42", JsonNumber.of(42).toString()); + assertEquals("42", JsonNumber.of(42L).toString()); + assertEquals(JsonNumber.of(Integer.MAX_VALUE).toString(), Integer.valueOf(Integer.MAX_VALUE).toString()); + assertEquals(JsonNumber.of(Long.MAX_VALUE).toString(), Long.valueOf(Long.MAX_VALUE).toString()); + assertEquals(JsonNumber.of(0.1f).toString(), Double.valueOf(0.1f).toString()); + assertEquals("0.1", JsonNumber.of(0.1d).toString()); + assertEquals("42.0", JsonNumber.of(42.0d).toString()); + assertEquals("42.0", JsonNumber.of(420e-1).toString()); + assertEquals("4.2E7", JsonNumber.of(42e6).toString()); + assertEquals(JsonNumber.of(Double.MAX_VALUE).toString(), Double.valueOf(Double.MAX_VALUE).toString()); + assertThrows(IllegalArgumentException.class, () -> JsonNumber.of("foo")); + assertThrows(IllegalArgumentException.class, () -> JsonNumber.of("true")); + assertThrows(IllegalArgumentException.class, () -> JsonNumber.of("\"foo\"")); + assertThrows(IllegalArgumentException.class, () -> JsonNumber.of("null")); + assertThrows(IllegalArgumentException.class, () -> JsonNumber.of("[1, 2]")); + assertThrows(IllegalArgumentException.class, () -> JsonNumber.of("{\"foo\": 42}")); + } + + @Test + void testRoundTrip() { + // factories + + // int + assertEquals(42, JsonNumber.of((byte)42).asInt()); + assertEquals(42, JsonNumber.of((short)42).asInt()); + assertEquals(42, JsonNumber.of(42).asInt()); + assertEquals(42, JsonNumber.of(42L).asInt()); + assertEquals(42, JsonNumber.of(42.0d).asInt()); + assertEquals(42, JsonNumber.of(420e-1).asInt()); + assertEquals(42_000_000, JsonNumber.of(42e6).asInt()); + assertEquals(42, JsonNumber.of("42").asInt()); + assertEquals(Integer.MAX_VALUE, JsonNumber.of(Integer.MAX_VALUE).asInt()); + assertEquals(Integer.MAX_VALUE, JsonNumber.of("2147483647").asInt()); + + // long + assertEquals(42L, JsonNumber.of((byte)42).asLong()); + assertEquals(42L, JsonNumber.of((short)42).asLong()); + assertEquals(42L, JsonNumber.of(42).asLong()); + assertEquals(42L, JsonNumber.of(42L).asLong()); + assertEquals(42L, JsonNumber.of(42.0d).asLong()); + assertEquals(42L, JsonNumber.of(420e-1).asLong()); + assertEquals(42_000_000L, JsonNumber.of(42e6).asLong()); + assertEquals(42L, JsonNumber.of("42").asLong()); + assertEquals(Long.MAX_VALUE, JsonNumber.of("9223372036854775807").asLong()); + assertEquals(Long.MAX_VALUE, JsonNumber.of(Long.MAX_VALUE).asLong()); + + // double + assertEquals((double)0.1f, JsonNumber.of(0.1f).asDouble()); + assertEquals(0.1d, JsonNumber.of(0.1d).asDouble()); + assertEquals(1d, JsonNumber.of(1e0).asDouble()); + assertEquals(Double.MAX_VALUE, JsonNumber.of(Double.MAX_VALUE).asDouble()); + assertEquals(0.1d, JsonNumber.of("0.1").asDouble()); + assertEquals(1d, JsonNumber.of("1e0").asDouble()); + assertEquals(Double.MAX_VALUE, JsonNumber.of("1.7976931348623157E308").asDouble()); + } + + @ParameterizedTest + @MethodSource + void factoryTest(Number n) { + var str = switch (n) { + case byte b -> JsonNumber.of(b).toString(); + case short s -> JsonNumber.of(s).toString(); + case int i -> JsonNumber.of(i).toString(); + case long l -> JsonNumber.of(l).toString(); + case float f -> JsonNumber.of(f).toString(); + case double d -> JsonNumber.of(d).toString(); + default -> throw new IllegalArgumentException("incorrect test argument"); + }; + var expected = switch (n) { + case byte b -> Long.toString(b); + case short s -> Long.toString(s); + case int i -> Long.toString(i); + case long l -> Long.toString(l); + case float f -> Double.toString(f); + case double d -> Double.toString(d); + default -> throw new IllegalArgumentException("incorrect test argument"); + }; + assertEquals(str, expected); + } + + private static Stream factoryTest() { + return Stream.of( + Arguments.of((byte)1), + Arguments.of((short)1), + Arguments.of((int)1), + Arguments.of(1L), + Arguments.of(1.0000000596046448f), // 1.0000001f -> 1.0000001192092896d + Arguments.of(1.0000000596046448d) + ); + } + } +} diff --git a/test/jdk/jdk/incubator/json/TestJsonObject.java b/test/jdk/jdk/incubator/json/TestJsonObject.java new file mode 100644 index 000000000000..12c963afa603 --- /dev/null +++ b/test/jdk/jdk/incubator/json/TestJsonObject.java @@ -0,0 +1,407 @@ +/* + * Copyright (c) 2025, 2026, 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 8381976 + * @summary Unit tests for JsonObject + * @modules jdk.incubator.json + * @run junit TestJsonObject + */ + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.FieldSource; + +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import jdk.incubator.json.Json; +import jdk.incubator.json.JsonArray; +import jdk.incubator.json.JsonBoolean; +import jdk.incubator.json.JsonNull; +import jdk.incubator.json.JsonNumber; +import jdk.incubator.json.JsonObject; +import jdk.incubator.json.JsonParseException; +import jdk.incubator.json.JsonString; +import jdk.incubator.json.JsonValue; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class TestJsonObject { + + private static final String JSON_WITH_SPACES = + """ + [ + { "name": "John", "age": 30, "city": "New York" }, + { "name": "Jane", "age": 20, "city": "Boston" }, + true, + false, + null, + [ "array", "inside", {"inner obj": true, "top-level": false}], + "foo", + 42 + ] + """; + + private static final String JSON_NO_NEWLINE = + """ + [{"name":"John","age":30,"city":"New York"},{"name":"Jane","age":20,"city":"Boston"},true,false,null,["array","inside",{"inner obj":true,"top-level":false}],"foo",42]"""; + + @Nested + class TestParse { + + // Ensure storage is done with the unescaped version + @Test + void retrievalTest() { + // parse + var jo = (JsonObject) Json.parse("{ \"foo\\t\" : false}"); + assertFalse(jo.asMap().get("foo\t").asBoolean()); + jo = (JsonObject) Json.parse("{ \"foo\\u0009\" : false}"); + assertFalse(jo.asMap().get("foo\t").asBoolean()); + // jo factory + jo = JsonObject.of(Map.of("foo\t", JsonBoolean.of(false))); + assertFalse(jo.asMap().get("foo\t").asBoolean()); + } + + @Test + void toStringTest() { + // 2 char sequence first + var key = "\" \\t \\u0021 \\u0022 \\u005c \\u0008 test \""; + var map = "{" + key + ":null}"; + assertEquals("{\" \\t ! \\\" \\\\ \\b test \":null}", Json.parse(map).toString()); + // Unicode escape sequence first + var key2 = "\" \\u0021 \\t \\u0022 \\u005c \\u0008 test \""; + var map2 = "{" + key2 + ":null}"; + assertEquals("{\" ! \\t \\\" \\\\ \\b test \":null}", Json.parse(map2).toString()); + } + + // Check for basic duplicate name + @Test + void testDuplicateKeys() { + var json = + """ + { "clone": "bob", "clone": "foo" } + """; + assertThrows(JsonParseException.class, () -> Json.parse(json)); + } + + // https://datatracker.ietf.org/doc/html/rfc8259#section-8.3 + // Check for equality via unescaped value + @Test + void testDuplicateKeyEqualityUnescaped() { + var json = + """ + { "clone": "bob", "clon\\u0065": "foo" } + """; + assertThrows(JsonParseException.class, () -> Json.parse(json)); + } + + @Test + void testDuplicateKeyEqualityMultipleUnescaped() { + var json = + """ + { "clonee": "bob", "clon\\u0065\\u0065": "foo" } + """; + assertThrows(JsonParseException.class, () -> Json.parse(json)); + } + + @Test + void testDuplicateKeyEqualityUnescapedVariant() { + var json = + """ + { "c\\b": "bob", "c\b": "foo" } + """; + assertThrows(JsonParseException.class, () -> Json.parse(json)); + } + + private static final List INVALID_OBJECTS = List.of( + "{ :name\": \"Brian\"}", + "{ \"name:: \"Brian\"}", + "{ \"name\": :Brian\"}", + "{ \"name\": \"Brian:}", + "{ \"name\": ,Brian\"}", + "{ foo \"name\": \"Brian\"}", // Garbage before name + "{ \"name\" foo : \"Brian\"}", // Garbage after name, but before colon + // Garbage in second name/val + "{ \"name\": \"Brian\" , \"name2\": \"Brian\" 5}", + "{ \"name\": \"Brian\" 5}", // Garbage next to closing bracket + "{ \"name\": \"Brian\"5 }", // Garbage next to value + "{ \"name\": \"Brian\" 5 }", // Garbage with ws + // Other cases, where non index based JsonValue occurs first + "{ \"name\": 5 \"Brian\" }", + "{ \"name\": 5 null }", + // Garbage after JsonValue in the form of index based JsonValue + "{ \"name\": \"Brian\" { \"name2\": \"another String\"} }", + "{ \"name\": \"Brian\" [\"another String\"] }", + "{ \"name\": \"Brian\" \"another String\"}"); + + @ParameterizedTest + @FieldSource("INVALID_OBJECTS") + void malformedObjectParseTest(String badJson) { + assertThrows(JsonParseException.class, () -> Json.parse(badJson)); + } + + private static final List INVALID_OBJECTS_MESSAGES = List.of( + Arguments.of("{ \"foo\" : ", "Expected a JSON Object, Array, String, Number, Boolean, or Null. Path: \"{foo\". Location: line 0, position 10."), + Arguments.of("{ \"foo\" ", "Expected a colon after the member name. Path: \"{\". Location: line 0, position 8."), + Arguments.of("{ \"foo\" : \"bar\" ", "JSON Object is not closed with a brace. Path: \"{\". Location: line 0, position 16."), + Arguments.of("{ \"foo\" : \"bar\", ", "JSON Object is not closed with a brace. Path: \"{\". Location: line 0, position 18."), + Arguments.of("{ \"foo\" : 1, \"foo\" : 1 ", "Duplicate member name: \"foo\" was already parsed. Path: \"{\". Location: line 0, position 13."), + Arguments.of("{ foo : \"bar\" ", "Expecting a JSON Object member name. Path: \"{\". Location: line 0, position 2."), + Arguments.of("{ \"foo : ", "JSON Object member name is not closed with a quotation mark. Path: \"{\". Location: line 0, position 9."), + Arguments.of("{ ", "JSON Object is not closed with a brace. Path: \"{\". Location: line 0, position 2."), + + // Escaped names + Arguments.of("{ \"foo\" : null, \"\\u0066oo\" : null ", "Duplicate member name: \"foo\" was already parsed. Path: \"{\". Location: line 0, position 16."), + Arguments.of("{ \"\\u00M\" ", "Invalid Unicode escape sequence. 'M' is not a hex digit. Path: \"{\". Location: line 0, position 7."), + Arguments.of("{ \"\\u00\f\" ", "Invalid Unicode escape sequence. '\\u000C' is not a hex digit. Path: \"{\". Location: line 0, position 7."), + Arguments.of("{ \"\\u00\u0020\" ", "Invalid Unicode escape sequence. '\\u0020' is not a hex digit. Path: \"{\". Location: line 0, position 7."), + Arguments.of("{ \"\\u00\u2028\" ", "Invalid Unicode escape sequence. '\\u2028' is not a hex digit. Path: \"{\". Location: line 0, position 7."), + Arguments.of("{ \"foo\\n\" : null, \"foo\\n\" : null ", "Duplicate member name: \"foo\\n\" was already parsed. Path: \"{\". Location: line 0, position 18."), + Arguments.of("{ \"foo\\a\" ", "Unrecognized escape sequence: \"\\a\". Path: \"{\". Location: line 0, position 7."), + Arguments.of("{ \"foo\\\f\" ", "Unrecognized escape sequence: \"\\\\u000C\". Path: \"{\". Location: line 0, position 7."), + Arguments.of("{ \"foo\\\u0020\" ", "Unrecognized escape sequence: \"\\\\u0020\". Path: \"{\". Location: line 0, position 7."), + Arguments.of("{ \"foo\\\u2028\" ", "Unrecognized escape sequence: \"\\\\u2028\". Path: \"{\". Location: line 0, position 7."), + + // multi-line duplicate member for error location validation + Arguments.of(""" + { + "a": 0, + "a": [ + ] + } + """, "Duplicate member name: \"a\" was already parsed. Path: \"{\". Location: line 2, position 4."), + Arguments.of(""" + { + "a": 0, + "a" + : 1 + } + """, "Duplicate member name: \"a\" was already parsed. Path: \"{\". Location: line 2, position 4."), + + // nested + Arguments.of("{ \"l1\": { \"l2\": [ 0, 1, two ] } }", + "Unexpected value. Expected a JSON Object, Array, String, Number, Boolean, or Null. Path: \"{l1{l2[2\". Location: line 0, position 25."), + Arguments.of("{\"ba\\\"zz\": [ invalid ]}", + "Unexpected value. Expected a JSON Object, Array, String, Number, Boolean, or Null. Path: \"{ba\\\"zz[0\". Location: line 0, position 13."), + Arguments.of("{\"\\u0061\": [ invalid ]}", + "Unexpected value. Expected a JSON Object, Array, String, Number, Boolean, or Null. Path: \"{\\u0061[0\". Location: line 0, position 13.") + ); + + @ParameterizedTest + @FieldSource("INVALID_OBJECTS_MESSAGES") + void testMessages(String json, String err) { + Exception e = assertThrows(JsonParseException.class, () -> Json.parse(json)); + assertEquals(err, e.getMessage()); + } + + private static final String JSON_EXTRA_SPACES = + """ + [ + \s + { "name" : "John", "age" : 30, "city": "New York" }, + { "name": "Jane" , "age": 20, "city": "Boston" }, + \s + \s + true, \s + false , + null, \s + [ "array" , "inside", {"inner obj": true, "top-level" : false } ] ,\s + "foo",\s + 42 + ] + \s"""; + + // White space is allowed but should have no effect + // on the underlying structure, and should not play a role during equality + @Test + void testWhiteSpaceEquality() { + var obj = Json.parse(JSON_EXTRA_SPACES); + var str = assertDoesNotThrow(() -> obj.toString()); // build the map/arr + var expStr = Json.parse(JSON_WITH_SPACES).toString(); + // Ensure equivalent Json (besides white space) generates equivalent + // toString values + assertEquals(expStr, str); + } + + @Test + void orderingParseTest() { + assertEquals(JSON_NO_NEWLINE, Json.parse(JSON_WITH_SPACES).toString()); + } + + @Test + void testToDisplayStringOrder() { + var json = """ + { + "a": 1, + "c": 2, + "b": 3 + }"""; + assertEquals(json, Json.toDisplayString(Json.parse(json), " ")); + } + + // Ensure decoded escape sequences are translated to valid JSON + // Supported 2 char escapes should be translated, otherwise U sequence + // needs to be preserved. + @Test + void controlCodeRoundTripTest() { + for (int i = 0; i < 32; i++) { + var mapWithSequence = "{ \" \\u" + String.format("%04x", i) + "\" : true }"; + Json.parse(Json.parse(mapWithSequence).toString()); + } + } + } + + @Nested + class TestFactory { + + private static final String JSON_OBJ = + """ + { "name": "Brian", "shoeSize": 10 } + """; + + private static final String SMALL_JSON_OBJ = + """ + { "shoeSize": 10 } + """; + + private static final String EMPTY_JSON_OBJ = + """ + { } + """; + + @Test + void emptyBuildTest() { + var expectedJson = Json.parse(JSON_OBJ); + var builtJson = new HashMap(); + builtJson.put("name", JsonString.of("Brian")); + builtJson.put("shoeSize", JsonNumber.of(10)); + compareValueTypes(((JsonObject)expectedJson).asMap(), JsonObject.of(builtJson).asMap()); + } + + @Test + void existingBuildTest() { + var sourceJson = Json.parse(JSON_OBJ); + var builtJson = JsonObject.of(((JsonObject)sourceJson).asMap()); + compareValueTypes(((JsonObject)sourceJson).asMap(), builtJson.asMap()); + } + + @Test + void removalTest() { + var expectedJson = Json.parse(SMALL_JSON_OBJ); + var sourceJson = Json.parse(JSON_OBJ); + var builtJson = new HashMap<>(((JsonObject) sourceJson).asMap()); + builtJson.remove("name"); + compareValueTypes(((JsonObject)expectedJson).asMap(), builtJson); + } + + @Test + void clearTest() { + var expectedJson = Json.parse(EMPTY_JSON_OBJ); + var builtJson = JsonObject.of(Map.of()); + compareValueTypes(((JsonObject)expectedJson).asMap(), builtJson.asMap()); + } + + // Basic test to check of factory for JsonObject + @Test + void ofFactoryTest() { + HashMap map = new HashMap<>(); + map.put("foo", JsonNumber.of(5)); + map.put("bar", JsonString.of("value")); + map.put("baz", JsonNull.of()); + compareValueTypes(JsonObject.of(map).asMap(), + ((JsonObject)Json.parse("{ \"foo\" : 5, \"bar\" : \"value\", \"baz\" : null}")).asMap()); + } + + private static void compareValueTypes(Map expected, Map actual) { + assertEquals(expected.size(), actual.size()); + for (var entry : expected.entrySet()) { + assertEquals(entry.getValue().getClass(), actual.get(entry.getKey()).getClass()); + } + } + + @Test + void immutabilityTest() { + var map = new HashMap(); + map.put("foo", JsonString.of("foo")); + var jo = JsonObject.of(map); + assertEquals(1, jo.asMap().size()); + // Modifications to original backed map should not change JsonObject + map.put("bar", JsonString.of("foo")); + assertEquals(1, jo.asMap().size()); + // Modifications to JsonObject asMap() should not be possible + assertThrows(UnsupportedOperationException.class, + () -> jo.asMap().put("bar", JsonNull.of()), + "Object members able to be modified"); + } + + @Test + void orderingOfTest() { + var jsonFromOf = ((JsonArray)Json.parse(JSON_WITH_SPACES)).asList(); + assertEquals(JSON_NO_NEWLINE, JsonArray.of(jsonFromOf).toString()); + } + + @Test + void nullTest() { + // null map to of factory + assertThrows(NullPointerException.class, () -> JsonObject.of(null)); + Map map = new HashMap<>(); + // Check null key + map.put(null, JsonNull.of()); + assertThrows(NullPointerException.class, () -> JsonObject.of(map)); + map.clear(); + // Check null value + map.put("foo", null); + assertThrows(NullPointerException.class, () -> JsonObject.of(map)); + } + + // Ensure decoded escape sequences are translated to valid JSON + // Supported 2 char escapes should be translated, otherwise U sequence + // needs to be preserved. + @Test + void controlCodeRoundTripTest() { + for (int i = 0; i < 32; i++) { + var sequence = Map.of("\\u" + String.format("%04x", i), JsonNull.of()); + var jo = JsonObject.of(sequence).asMap(); + JsonObject.of(jo); + } + } + + // Check IAE is thrown for duplicate map key names + @Test + void duplicateMapKeyTest() { + var map = new IdentityHashMap(); + map.put(new String("foo"), JsonString.of("foo")); + map.put(new String("foo"), JsonString.of("bar")); + var iae = assertThrows(IllegalArgumentException.class, () -> JsonObject.of(map)); + assertEquals("Duplicate member name: foo", iae.getMessage()); + } + } +} diff --git a/test/jdk/jdk/incubator/json/TestJsonParseException.java b/test/jdk/jdk/incubator/json/TestJsonParseException.java new file mode 100644 index 000000000000..ec979d970d46 --- /dev/null +++ b/test/jdk/jdk/incubator/json/TestJsonParseException.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2026, 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 8381976 + * @summary Unit tests for JsonParseException + * @modules jdk.incubator.json + * @run junit/othervm --add-opens jdk.incubator.json/jdk.incubator.json=ALL-UNNAMED + * --enable-final-field-mutation=ALL-UNNAMED TestJsonParseException + */ + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.FieldSource; +import org.junit.jupiter.params.provider.ValueSource; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.List; +import jdk.incubator.json.Json; +import jdk.incubator.json.JsonParseException; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class TestJsonParseException { + + // General exceptions not particularly tied to a sub-interface of JsonValue + private static final List INVALID_JSON = List.of( + Arguments.of("", "Expected a JSON Object, Array, String, Number, Boolean, or Null. Path: \"\". Location: line 0, position 0."), + Arguments.of(" ", "Expected a JSON Object, Array, String, Number, Boolean, or Null. Path: \"\". Location: line 0, position 1."), + Arguments.of("z", "Unexpected value. Expected a JSON Object, Array, String, Number, Boolean, or Null. Path: \"\". Location: line 0, position 0."), + Arguments.of("null, true", "Additional value(s) were found after the JSON Value. Path: \"\". Location: line 0, position 4."), + Arguments.of("null 5", "Additional value(s) were found after the JSON Value. Path: \"\". Location: line 0, position 5."), + // Test cases focused on path ----------- + // Compare this case to the one below + Arguments.of("{\"foo\": \"bar\"baz}", + "Unexpected content after JSON value. Path: \"{foo\". Location: line 0, position 13."), + // Notice how this case has a space in between the bar and baz. + // This is more an invalid structure, rather than the value being incorrect. + // In this case the error is attributed to the structure, and not the value. + // This is tricky, since paths in parsing cannot be attributed to valid values and are + // contextual/best guesses. + Arguments.of("{\"foo\": \"bar\" baz }", + "JSON Object is not closed with a brace. Path: \"{\". Location: line 0, position 14."), + Arguments.of("[1]x", + "Unexpected content after JSON value. Path: \"\". Location: line 0, position 3."), + Arguments.of("[1] x", + "Additional value(s) were found after the JSON Value. Path: \"\". Location: line 0, position 4."), + Arguments.of("[5x ]", + "Unexpected content after JSON value. Path: \"[0\". Location: line 0, position 2."), + Arguments.of("{} {}", + "Additional value(s) were found after the JSON Value. Path: \"\". Location: line 0, position 3."), + Arguments.of("[[] 1]", + "JSON Array is not closed with a bracket. Path: \"[\". Location: line 0, position 4.") + ); + + @ParameterizedTest + @FieldSource("INVALID_JSON") + void testMessages(String json, String err) { + Exception e = assertThrows(JsonParseException.class, () -> Json.parse(json)); + assertEquals(err, e.getMessage()); + } + + + // Line Position focused exceptions + + private static final String BASIC = "foobarbaz"; + + @Test + void testBasicLinePosition() { + var msg = "Location: line 0, position 1."; + JsonParseException e = assertThrows(JsonParseException.class, () -> Json.parse(BASIC)); + assertTrue(e.getMessage().contains(msg), + "Expected: " + msg + " but got line " + + e.getErrorLine() + ", position " + e.getErrorPosition()); + } + + private static final String STRUCTURAL = + """ + [ + null, foobarbaz + ] + """; + + @Test + void testStructuralLinePosition() { + var msg = "Location: line 1, position 11."; + JsonParseException e = assertThrows(JsonParseException.class, () -> Json.parse(STRUCTURAL)); + assertTrue(e.getMessage().contains(msg), + "Expected: " + msg + " but got line " + + e.getErrorLine() + ", position " + e.getErrorPosition()); + } + + private static final String STRUCTURAL_WITH_NESTED = + """ + { + "name" : + [ + "value", + null, foobarbaz + ] + } + """; + + @Test + void testStructuralWithNestedLinePosition() { + var msg = "Location: line 4, position 15."; + JsonParseException e = assertThrows(JsonParseException.class, () -> Json.parse(STRUCTURAL_WITH_NESTED)); + assertTrue(e.getMessage().contains(msg), + "Expected: " + msg + " but got line " + + e.getErrorLine() + ", position " + e.getErrorPosition()); + } + + @Test + void testConstructorIAE() { + assertThrows(IllegalArgumentException.class, () -> new JsonParseException("Foo", 1, -1)); + assertThrows(IllegalArgumentException.class, () -> new JsonParseException("Foo", -1, 1)); + } + + @ParameterizedTest + @ValueSource(strings = {"line", "pos"}) + void testMalformedLocationDeserialized(String field) throws Exception { + var jpe = new JsonParseException("message", 0, 0); + var f = JsonParseException.class.getDeclaredField(field); + f.setAccessible(true); + f.setInt(jpe, -1); + + assertThrows(InvalidObjectException.class, () -> deser(jpe)); + } + + private static Object deser(Object jpe) throws Exception { + var bytes = new ByteArrayOutputStream(); + try (var out = new ObjectOutputStream(bytes)) { + out.writeObject(jpe); + } + try (var in = new ObjectInputStream( + new ByteArrayInputStream(bytes.toByteArray()))) { + return in.readObject(); + } + } +} diff --git a/test/jdk/jdk/incubator/json/TestJsonString.java b/test/jdk/jdk/incubator/json/TestJsonString.java new file mode 100644 index 000000000000..c1ba4daab9b3 --- /dev/null +++ b/test/jdk/jdk/incubator/json/TestJsonString.java @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2025, 2026, 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 8381976 + * @summary Unit tests for JsonString + * @modules jdk.incubator.json + * @run junit TestJsonString + */ + +import java.util.Arrays; +import java.util.List; +import jdk.incubator.json.Json; +import jdk.incubator.json.JsonParseException; +import jdk.incubator.json.JsonString; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.FieldSource; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class TestJsonString { + + @Nested + class TestValue { + + @Test + void valueTest() { + var untypedStr = "\t"; + var jsonStr = "\"\\u0009\""; + // Both should compare as equals via asString() which is \t + assertEquals(JsonString.of(untypedStr).asString(), ((JsonString) Json.parse(jsonStr)).asString()); + // Factory escapes \t to \\t but parse retains the original U sequence + // (due to its lazy nature) and that is OK + assertNotEquals(JsonString.of(untypedStr).toString(), Json.parse(jsonStr).toString()); + } + + // Escape sequence tests on asString() + @ParameterizedTest + @MethodSource + void escapeTest(String src, String expected) { + assertEquals(expected, ((JsonString)Json.parse(src)).asString()); + } + private static Stream escapeTest() { + return Stream.of( + Arguments.of("\"\\\"\"", "\""), + Arguments.of("\"\\\\\"", "\\"), + Arguments.of("\"\\/\"", "/"), + Arguments.of("\"\\b\"", "\b"), + Arguments.of("\"\\f\"", "\f"), + Arguments.of("\"\\n\"", "\n"), + Arguments.of("\"\\r\"", "\r"), + Arguments.of("\"\\t\"", "\t"), + Arguments.of("\"\\uD834\\uDD1E\"", "\uD834\uDD1E") + ); + } + } + + @Nested + class TestParse { + + // All JsonString related parse failure messages + private static final List FAIL_STRING = List.of( + Arguments.of("\"\t", "Unescaped control code. Path: \"\". Location: line 0, position 1."), + Arguments.of("\"foo\\a \"", "Unrecognized escape sequence: \"\\a\". Path: \"\". Location: line 0, position 5."), + Arguments.of("\"foo\\\f \"", "Unrecognized escape sequence: \"\\\\u000C\". Path: \"\". Location: line 0, position 5."), + Arguments.of("\"foo\\\u0020 \"", "Unrecognized escape sequence: \"\\\\u0020\". Path: \"\". Location: line 0, position 5."), + Arguments.of("\"foo\\\u2028 \"", "Unrecognized escape sequence: \"\\\\u2028\". Path: \"\". Location: line 0, position 5."), + Arguments.of("\"foo\\u0\"", "Invalid Unicode escape sequence. Expected four hex digits. Path: \"\". Location: line 0, position 5."), + Arguments.of("\"foo\\uZZZZ\"", "Invalid Unicode escape sequence. 'Z' is not a hex digit. Path: \"\". Location: line 0, position 6."), + Arguments.of("\"foo\\u\f000\"", "Invalid Unicode escape sequence. '\\u000C' is not a hex digit. Path: \"\". Location: line 0, position 6."), + Arguments.of("\"foo\\u\u0020000\"", "Invalid Unicode escape sequence. '\\u0020' is not a hex digit. Path: \"\". Location: line 0, position 6."), + Arguments.of("\"foo\\u\u2028000\"", "Invalid Unicode escape sequence. '\\u2028' is not a hex digit. Path: \"\". Location: line 0, position 6."), + Arguments.of("\"foo ", "JSON String is not closed with a quotation mark. Path: \"\". Location: line 0, position 5.")); + + @ParameterizedTest + @FieldSource("FAIL_STRING") + void testMessages(String json, String err) { + Exception e = assertThrows(JsonParseException.class, () -> Json.parse(json)); + assertEquals(err, e.getMessage()); + } + + private static Stream testStringEquality() { + return Stream.of( + Arguments.of("\"afo\"", "\"afo\"", true), + Arguments.of("\"afo\"", new char[]{'"', 'a', 'f', 'o', '"'}, true), + Arguments.of("\"afo\"", new char[]{'"', '\\', 'u', '0', '0', '6', '1', 'f', 'o', '"'}, true) + ); + } + + @ParameterizedTest + @MethodSource + void testStringEquality(Object arg1, Object arg2) { + var jv1 = arg1 instanceof String s ? Json.parse(s) : + arg1 instanceof char[] ca ? Json.parse(ca) : null; + var jv2 = arg2 instanceof String s ? Json.parse(s) : + arg2 instanceof char[] ca ? Json.parse(ca) : null; + var val1 = jv1 instanceof JsonString js ? js.asString() : null; + var val2 = jv2 instanceof JsonString js ? js.asString() : null; + + // two JsonValue arguments should have the same asString() + assertEquals(val1, val2); + + // assert their toString() returns the original text + assertEquals(arg1 instanceof char[] ca ? new String(ca) : arg1, jv1.toString()); + } + + // Ensure decoded escape sequences are translated to valid JSON + // Supported 2 char escapes should be translated, otherwise U sequence + // needs to be preserved. + @Test + void controlCodeRoundTripTest() { + for (int i = 0; i < 32; i++) { + var sequence = "\\u" + String.format("%04x", i); + Json.parse(Json.parse("\"" + sequence + "\"").toString()); + } + } + } + + @Nested + class TestFactory { + + private static final List ESCAPES = List.of( + // No escape + Arguments.of("foo", "\"foo\""), + // Escape in front + Arguments.of("\" foo", "\"\\\" foo\""), + // Escape in back + Arguments.of("foo \"", "\"foo \\\"\""), + // Various escapes + Arguments.of("foo \\\\ \\ \\u0008 \t \b \u0000 \u0001 \u0008" + , "\"foo \\\\\\\\ \\\\ \\\\u0008 \\t \\b \\u0000 \\u0001 \\b\"")); + + @ParameterizedTest + @FieldSource("ESCAPES") + void escapeTest(String str, String expected) { + assertEquals(expected, JsonString.of(str).toString()); + } + + // Ensure the String passed to the factory (which requires escaping) can be + // round tripped both into a parse call and a factory call. + @Test + void controlCodeRoundTripTest() { + // 0 -> 31 Control chars + var reservedChars = Arrays.copyOf(IntStream.range(0, 32).toArray(), 34); + reservedChars[32] = 34; // Double quote + reservedChars[33] = 92; // Reverse solidus + for (int i : reservedChars) { + var js = JsonString.of(String.valueOf((char)i)); + Json.parse(js.toString()); + JsonString.of(js.asString()); + } + } + } +} diff --git a/test/jdk/jdk/incubator/json/TestOtherImpl.java b/test/jdk/jdk/incubator/json/TestOtherImpl.java new file mode 100644 index 000000000000..979423690db3 --- /dev/null +++ b/test/jdk/jdk/incubator/json/TestOtherImpl.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2025, 2026, 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 8381976 + * @summary Tests for other implementations that extend JsonValue sub-interfaces + * @modules jdk.incubator.json + * @run junit TestOtherImpl + */ + +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Map; +import jdk.incubator.json.Json; +import jdk.incubator.json.JsonArray; +import jdk.incubator.json.JsonBoolean; +import jdk.incubator.json.JsonNull; +import jdk.incubator.json.JsonNumber; +import jdk.incubator.json.JsonObject; +import jdk.incubator.json.JsonString; +import jdk.incubator.json.JsonValue; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TestOtherImpl { + + private static final JsonString STANDARD_JSON_STRING = JsonString.of("bar"); + private static final JsonString ALT_JSON_STRING = + new JsonFooString("bar".getBytes(StandardCharsets.UTF_8)); + + @Test + void equalsToStringTest() { + assertEquals(STANDARD_JSON_STRING.toString(), ALT_JSON_STRING.toString()); + } + + @Test + void displayStringTest() { + assertEquals(Json.toDisplayString(STANDARD_JSON_STRING, " "), Json.toDisplayString(ALT_JSON_STRING, " ")); + // Wrap it in a JsonObject, and check display string equality again + assertEquals(Json.toDisplayString(JsonObject.of(Map.of("foo", STANDARD_JSON_STRING)), " "), + Json.toDisplayString(JsonObject.of(Map.of("foo", ALT_JSON_STRING)), " ")); + } + + static class JsonFooString implements JsonString { + + private final String theString; + + public JsonFooString(byte[] bytes) { + theString = new String(bytes, StandardCharsets.UTF_8); + } + + @Override + public String asString() { + // For testing purposes, just return the String. + // Real implementations must adhere to un-escaping as specified. + return theString; + } + + @Override + public String toString() { + return "\""+theString+"\""; + } + } + + // These implementation classes exist to verify that each JsonValue + // sub-interface is non-sealed. No test execution is required; + // successful compilation is sufficient. + static class JsonFooArray implements JsonArray { + @Override + public List asList() { + return List.of(); + } + } + static class JsonFooBoolean implements JsonBoolean { + @Override + public boolean asBoolean() { + return false; + } + } + static class JsonFooNull implements JsonNull {} + static class JsonFooNumber implements JsonNumber { + @Override + public int asInt() { + return 0; + } + @Override + public long asLong() { + return 0; + } + @Override + public double asDouble() { + return 0; + } + } + static class JsonFooObject implements JsonObject { + @Override + public Map asMap() { + return Map.of(); + } + } +} + diff --git a/test/jdk/jdk/incubator/json/TestParse.java b/test/jdk/jdk/incubator/json/TestParse.java new file mode 100644 index 000000000000..7270588eccd5 --- /dev/null +++ b/test/jdk/jdk/incubator/json/TestParse.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2025, 2026, 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 8381976 + * @summary Checks non JSON subtype specific parse behavior + * @modules jdk.incubator.json + * @run junit TestParse + */ + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Map; +import jdk.incubator.json.Json; +import jdk.incubator.json.JsonNumber; +import jdk.incubator.json.JsonObject; +import jdk.incubator.json.JsonString; +import jdk.incubator.json.JsonValue; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TestParse { + + private static final String JSON = + """ + { "name": "Brian", "shoeSize": 10 } + """; + + // A basic parse and match example + @Test + void testBasicParseAndMatch() { + var doc = Json.parse(JSON); + if (doc instanceof JsonObject o && o.asMap() instanceof Map members + && members.get("name") instanceof JsonString js + && members.get("shoeSize") instanceof JsonNumber jn) { + assertEquals("Brian", js.asString()); + assertEquals(10, jn.asLong()); + } else { + throw new RuntimeException("Test data incorrect"); + } + } + + // Ensure modifying input char array passed to Json.parse has no impact on JsonValue + @Test + void testDefensiveCopy() { + char[] in = JSON.toCharArray(); + var doc = Json.parse(in); + + // Mutate original char array with nonsense + Arrays.fill(in, 'A'); + + if (doc instanceof JsonObject o + && o.asMap().get("name") instanceof JsonString js + && o.asMap().get("shoeSize") instanceof JsonNumber jn) { + assertEquals("Brian", js.asString()); + assertEquals(10, jn.asLong()); + } else { + throw new RuntimeException("JsonValue corrupted by input array"); + } + } + + private static final String JSON_WITH_SPACES = + """ + [ + { "name": "John", "age": 30, "city": "New York" }, + { "name": "Jane", "age": 20, "city": "Boston" }, + true, + false, + null, + [ "array", "inside", {"inner obj": true, "top-level": false}], + "foo", + 42 + ] + """; + + private static final String JSON_EXTRA_SPACES = + """ + [ + \s + { "name" : "John", "age" : 30, "city": "New York" }, + { "name": "Jane" , "age": 20, "city": "Boston" }, + \s + \s + true, \s + false , + null, \s + [ "array" , "inside", {"inner obj": true, "top-level" : false } ] ,\s + "foo",\s + 42 + ] + \s"""; + + // White space is allowed but should have no effect + // on the underlying structure, and should not play a role during equality + @Test + void testWhiteSpaceEquality() { + var obj = Json.parse(JSON_EXTRA_SPACES); + var str = assertDoesNotThrow(obj::toString); + var expStr = Json.parse(JSON_WITH_SPACES).toString(); + // Ensure equivalent Json (besides white space) generates equivalent + // toString values + assertEquals(expStr, str); + } + + @Test + void testDeepNestingParse() { + int depth = 10_000; + var json = "[".repeat(depth) + "0" + "]".repeat(depth); + var parsed = assertDoesNotThrow(() -> Json.parse(json)); + assertEquals(json, parsed.toString()); + } +} diff --git a/test/jdk/jdk/incubator/vector/VectorLanewiseOpCompatibleWithTest.java b/test/jdk/jdk/incubator/vector/VectorLanewiseOpCompatibleWithTest.java index 5c12554c643e..e0c6a31f40a8 100644 --- a/test/jdk/jdk/incubator/vector/VectorLanewiseOpCompatibleWithTest.java +++ b/test/jdk/jdk/incubator/vector/VectorLanewiseOpCompatibleWithTest.java @@ -26,6 +26,7 @@ import java.util.Arrays; import java.util.Comparator; import java.util.List; +import java.util.function.Predicate; import jdk.incubator.vector.Float16; import jdk.incubator.vector.Vector; @@ -40,7 +41,7 @@ /* * @test - * @bug 8389844 + * @bug 8389844 8391307 * @modules jdk.incubator.vector * @run testng VectorLanewiseOpCompatibleWithTest */ @@ -73,32 +74,39 @@ private static List vectorOperators() { return List.copyOf(operators); } - @DataProvider - public Object[][] unsupportedOperatorProvider() { - return operatorProvider(false); - } - - @DataProvider - public Object[][] supportedOperatorProvider() { - return operatorProvider(true); - } - - private static Object[][] operatorProvider(boolean compatible) { + private static Object[][] operatorProvider(boolean compatible, + Predicate opFilter) { return ELEMENT_TYPES.stream() .flatMap(elementType -> Arrays.stream(VectorShape.values()) .map(shape -> VectorSpecies.of(elementType, shape))) .flatMap(species -> OPERATORS.stream() - .filter(op -> op instanceof VectorOperators.Unary || - op instanceof VectorOperators.Binary || - op instanceof VectorOperators.Ternary) // These operators are more restrictive, exclude for now. .filter(op -> op != VectorOperators.COMPRESS_BITS && - op != VectorOperators.EXPAND_BITS) + op != VectorOperators.EXPAND_BITS) + .filter(opFilter) .filter(op -> op.compatibleWith(species.elementType()) == compatible) .map(op -> new Object[] {species, op})) .toArray(Object[][]::new); } + private static Object[][] operatorProvider(boolean compatible) { + return operatorProvider(compatible, + op -> op instanceof VectorOperators.Unary || + op instanceof VectorOperators.Binary || + op instanceof VectorOperators.Ternary || + op instanceof VectorOperators.Test); + } + + @DataProvider + public Object[][] unsupportedOperatorProvider() { + return operatorProvider(false); + } + + @DataProvider + public Object[][] supportedOperatorProvider() { + return operatorProvider(true); + } + @Test(dataProvider = "unsupportedOperatorProvider") public void testUnsupportedOperator(VectorSpecies species, VectorOperators.Operator op) { @@ -128,6 +136,12 @@ public void testUnsupportedOperator(VectorSpecies species, Assert.assertThrows(UnsupportedOperationException.class, () -> vector.lanewise(ternary, vector, vector, mask)); } + case VectorOperators.Test test -> { + Assert.assertThrows(UnsupportedOperationException.class, + () -> vector.test(test)); + Assert.assertThrows(UnsupportedOperationException.class, + () -> vector.test(test, mask)); + } default -> throw new AssertionError("Not a lanewise operator: " + op); } } @@ -153,6 +167,10 @@ public void testSupportedOperator(VectorSpecies species, vector.lanewise(ternary, vector, vector); vector.lanewise(ternary, vector, vector, mask); } + case VectorOperators.Test test -> { + vector.test(test); + vector.test(test, mask); + } default -> throw new AssertionError("Not a lanewise operator: " + op); } } diff --git a/test/jdk/jdk/jfr/event/security/TestTLS12HandshakeEvent.java b/test/jdk/jdk/jfr/event/security/TestTLS12HandshakeEvent.java new file mode 100644 index 000000000000..66f7064cd79d --- /dev/null +++ b/test/jdk/jdk/jfr/event/security/TestTLS12HandshakeEvent.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2026, 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.jfr.event.security; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; +import jdk.test.lib.net.SimpleSSLContext; + +/* + * @test + * @bug 8391863 + * @summary Test that TLS 1.2 handshake events are recorded properly for both + * full and abbreviated handshakes. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.event.security.TestTLS12HandshakeEvent + */ + +public class TestTLS12HandshakeEvent { + + private static final String PROTOCOL = "TLSv1.2"; + private static final int CONNECTION_COUNT = 2; + + public static void main(String[] args) throws Exception { + // Use stateful resumption for a simple resumption assertion + System.setProperty("jdk.tls.client.enableSessionTicketExtension", "false"); + System.setProperty("jdk.tls.server.enableSessionTicketExtension", "false"); + + SSLContext serverContext = SimpleSSLContext.findSSLContext(PROTOCOL); + SSLContext clientContext = SimpleSSLContext.findSSLContext(PROTOCOL); + + try (SSLServerSocket serverSocket = (SSLServerSocket) serverContext + .getServerSocketFactory().createServerSocket(0)) { + + serverSocket.setEnabledProtocols(new String[] { PROTOCOL }); + int serverPort = serverSocket.getLocalPort(); + CompletableFuture server = CompletableFuture.runAsync( + () -> serve(serverSocket)); + + try (Recording recording = new Recording()) { + recording.enable(EventNames.TLSHandshake); + recording.start(); + + SSLSession initialSession = connect(clientContext, serverPort, 0); + SSLSession resumedSession = connect(clientContext, serverPort, 1); + server.join(); + + recording.stop(); + + // Assert resumption + Asserts.assertTrue(Arrays.equals(initialSession.getId(), + resumedSession.getId()), + "The second connection did not resume the TLS session"); + + // Assert JFR events + assertEvents(Events.fromRecording(recording), serverPort); + } + } + } + + private static SSLSession connect(SSLContext context, int port, int value) + throws IOException { + try (SSLSocket socket = (SSLSocket) context.getSocketFactory() + .createSocket("localhost", port)) { + socket.setEnabledProtocols(new String[] { PROTOCOL }); + socket.getOutputStream().write(value); + socket.getOutputStream().flush(); + Asserts.assertEquals(socket.getInputStream().read(), value, + "Unexpected response from server"); + return socket.getSession(); + } + } + + private static void serve(SSLServerSocket serverSocket) { + try { + for (int i = 0; i < CONNECTION_COUNT; i++) { + try (SSLSocket socket = (SSLSocket) serverSocket.accept()) { + int value = socket.getInputStream().read(); + socket.getOutputStream().write(value); + socket.getOutputStream().flush(); + } + } + } catch (IOException e) { + throw new CompletionException(e); + } + } + + private static void assertEvents(List events, int serverPort) { + System.out.println(events); + Asserts.assertEquals(events.size(), CONNECTION_COUNT * 2, + "Expected one TLS handshake event from each peer"); + + long clientEvents = events.stream() + .filter(e -> e.getInt("peerPort") == serverPort) + .count(); + Asserts.assertEquals(clientEvents, (long) CONNECTION_COUNT, + "Incorrect number of client TLS handshake events"); + + for (RecordedEvent event : events) { + Events.assertField(event, "protocolVersion").equal(PROTOCOL); + } + } +} diff --git a/test/jdk/sun/misc/UnsafeMemoryAccessWarnings.java b/test/jdk/sun/misc/UnsafeMemoryAccessWarnings.java index 0e71dfdc1940..f6ceb95c0cb2 100644 --- a/test/jdk/sun/misc/UnsafeMemoryAccessWarnings.java +++ b/test/jdk/sun/misc/UnsafeMemoryAccessWarnings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, 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 8331670 8338383 + * @bug 8331670 8338383 8387729 * @summary Basic test for --sun-misc-unsafe-memory-access= * @library /test/lib * @compile TryUnsafeMemoryAccess.java @@ -59,16 +59,17 @@ void testDefault(String input) throws Exception { */ @Test void testAllow() throws Exception { - test("allocateMemory+freeMemory+objectFieldOffset+putLong+getLong+invokeCleaner", - "--sun-misc-unsafe-memory-access=allow") - .shouldHaveExitValue(0) - .shouldNotContain("WARNING: A terminally deprecated method in sun.misc.Unsafe has been called") - .shouldNotContain("WARNING: sun.misc.Unsafe::allocateMemory") - .shouldNotContain("WARNING: sun.misc.Unsafe::freeMemory") - .shouldNotContain("WARNING: sun.misc.Unsafe::objectFieldOffset") - .shouldNotContain("WARNING: sun.misc.Unsafe::putLong") - .shouldNotContain("WARNING: sun.misc.Unsafe::getLong") - .shouldNotContain("WARNING: sun.misc.Unsafe::invokeCleaner"); + for (String[] opt : optionForms("--sun-misc-unsafe-memory-access", "allow")) { + test("allocateMemory+freeMemory+objectFieldOffset+putLong+getLong+invokeCleaner", opt) + .shouldHaveExitValue(0) + .shouldNotContain("WARNING: A terminally deprecated method in sun.misc.Unsafe has been called") + .shouldNotContain("WARNING: sun.misc.Unsafe::allocateMemory") + .shouldNotContain("WARNING: sun.misc.Unsafe::freeMemory") + .shouldNotContain("WARNING: sun.misc.Unsafe::objectFieldOffset") + .shouldNotContain("WARNING: sun.misc.Unsafe::putLong") + .shouldNotContain("WARNING: sun.misc.Unsafe::getLong") + .shouldNotContain("WARNING: sun.misc.Unsafe::invokeCleaner"); + } } /** @@ -80,7 +81,9 @@ void testAllow() throws Exception { "objectFieldOffset+putLong+getLong" }) void testWarn(String input) throws Exception { - testOneWarning(input, "--sun-misc-unsafe-memory-access=warn"); + for (String[] opt : optionForms("--sun-misc-unsafe-memory-access", "warn")) { + testOneWarning(input, opt); + } } /** @@ -113,15 +116,16 @@ private void testOneWarning(String input, String... vmopts) throws Exception { */ @Test void testDebug() throws Exception { - test("allocateMemory+freeMemory+objectFieldOffset+putLong+getLong+invokeCleaner", - "--sun-misc-unsafe-memory-access=debug") - .shouldHaveExitValue(0) - .shouldContain("WARNING: sun.misc.Unsafe::allocateMemory called") - .shouldContain("WARNING: sun.misc.Unsafe::freeMemory called") - .shouldContain("WARNING: sun.misc.Unsafe::objectFieldOffset called") - .shouldContain("WARNING: sun.misc.Unsafe::putLong called") - .shouldContain("WARNING: sun.misc.Unsafe::getLong called") - .shouldContain("WARNING: sun.misc.Unsafe::invokeCleaner called"); + for (String[] opt : optionForms("--sun-misc-unsafe-memory-access", "debug")) { + test("allocateMemory+freeMemory+objectFieldOffset+putLong+getLong+invokeCleaner", opt) + .shouldHaveExitValue(0) + .shouldContain("WARNING: sun.misc.Unsafe::allocateMemory called") + .shouldContain("WARNING: sun.misc.Unsafe::freeMemory called") + .shouldContain("WARNING: sun.misc.Unsafe::objectFieldOffset called") + .shouldContain("WARNING: sun.misc.Unsafe::putLong called") + .shouldContain("WARNING: sun.misc.Unsafe::getLong called") + .shouldContain("WARNING: sun.misc.Unsafe::invokeCleaner called"); + } } /** @@ -129,11 +133,13 @@ void testDebug() throws Exception { */ @Test void testDeny() throws Exception { - test("allocateMemory+objectFieldOffset+invokeCleaner", "--sun-misc-unsafe-memory-access=deny") - .shouldHaveExitValue(0) - .shouldContain("java.lang.UnsupportedOperationException: allocateMemory") - .shouldContain("java.lang.UnsupportedOperationException: objectFieldOffset") - .shouldContain("java.lang.UnsupportedOperationException: invokeCleaner"); + for (String[] opt : optionForms("--sun-misc-unsafe-memory-access", "deny")) { + test("allocateMemory+objectFieldOffset+invokeCleaner", opt) + .shouldHaveExitValue(0) + .shouldContain("java.lang.UnsupportedOperationException: allocateMemory") + .shouldContain("java.lang.UnsupportedOperationException: objectFieldOffset") + .shouldContain("java.lang.UnsupportedOperationException: invokeCleaner"); + } } /** @@ -171,8 +177,16 @@ void testInvokeReflectively() throws Exception { @Test void testLastOneWins() throws Exception { test("allocateMemory+objectFieldOffset+invokeCleaner", - "--sun-misc-unsafe-memory-access=allow", - "--sun-misc-unsafe-memory-access=deny") + "--sun-misc-unsafe-memory-access=allow", + "--sun-misc-unsafe-memory-access=deny") + .shouldHaveExitValue(0) + .shouldContain("java.lang.UnsupportedOperationException: allocateMemory") + .shouldContain("java.lang.UnsupportedOperationException: objectFieldOffset") + .shouldContain("java.lang.UnsupportedOperationException: invokeCleaner"); + + test("allocateMemory+objectFieldOffset+invokeCleaner", + "--sun-misc-unsafe-memory-access", "allow", + "--sun-misc-unsafe-memory-access", "deny") .shouldHaveExitValue(0) .shouldContain("java.lang.UnsupportedOperationException: allocateMemory") .shouldContain("java.lang.UnsupportedOperationException: objectFieldOffset") @@ -185,9 +199,11 @@ void testLastOneWins() throws Exception { @ParameterizedTest @ValueSource(strings = { "", "bad" }) void testInvalidValues(String value) throws Exception { - test("allocateMemory", "--sun-misc-unsafe-memory-access=" + value) - .shouldNotHaveExitValue(0) - .shouldContain("Value specified to --sun-misc-unsafe-memory-access not recognized: '" + value); + for (String[] opt : optionForms("--sun-misc-unsafe-memory-access", value)) { + test("allocateMemory", opt) + .shouldNotHaveExitValue(0) + .shouldContain("Value specified to --sun-misc-unsafe-memory-access not recognized: '" + value); + } } /** @@ -214,4 +230,14 @@ private OutputAnalyzer test(String action, String... vmopts) throws Exception { .errorTo(System.err); return outputAnalyzer; } + + /** + * Returns the given option in both supported argument forms. + */ + private String[][] optionForms(String option, String value) { + return new String[][] { + { option + "=" + value }, + { option, value } + }; + } } diff --git a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java index f9610436bc9e..26c5a0e09de6 100644 --- a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java +++ b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java @@ -21,7 +21,7 @@ * questions. */ - /* +/* * @test * @bug 8181157 8202537 8234347 8236548 8261279 8322647 8174269 8346948 * 8354548 8381379 8382020 8384043 8371842 @@ -299,15 +299,17 @@ private static Object[][] sampleTZs() { } private static Stream explicitDstOffsets() { + var irl = Locale.of("en", "IE"); + return Stream.of( // CLDR v48 - Arguments.of(ZonedDateTime.of(2026, 4, 5, 0, 0, 0, 0, ZoneId.of("Europe/Dublin")), "Irish Standard Time", "IST"), - Arguments.of(ZonedDateTime.of(2026, 12, 5, 0, 0, 0, 0, ZoneId.of("Europe/Dublin")), "Greenwich Mean Time", "GMT"), - Arguments.of(ZonedDateTime.of(2026, 4, 5, 0, 0, 0, 0, ZoneId.of("Eire")), "Irish Standard Time", "IST"), - Arguments.of(ZonedDateTime.of(2026, 12, 5, 0, 0, 0, 0, ZoneId.of("Eire")), "Greenwich Mean Time", "GMT"), + Arguments.of(ZonedDateTime.of(2026, 4, 5, 0, 0, 0, 0, ZoneId.of("Europe/Dublin")), irl, "Irish Standard Time", "IST"), + Arguments.of(ZonedDateTime.of(2026, 12, 5, 0, 0, 0, 0, ZoneId.of("Europe/Dublin")), irl, "Greenwich Mean Time", "GMT"), + Arguments.of(ZonedDateTime.of(2026, 4, 5, 0, 0, 0, 0, ZoneId.of("Eire")), irl, "Irish Standard Time", "IST"), + Arguments.of(ZonedDateTime.of(2026, 12, 5, 0, 0, 0, 0, ZoneId.of("Eire")), irl, "Greenwich Mean Time", "GMT"), // CLDR v48.2 & tz2026b. America/Vancouver switched to permanent DST - Arguments.of(ZonedDateTime.of(2026, 4, 5, 0, 0, 0, 0, ZoneId.of("America/Vancouver")), "Pacific Daylight Time", "PDT"), - Arguments.of(ZonedDateTime.of(2026, 12, 5, 0, 0, 0, 0, ZoneId.of("America/Vancouver")), "Pacific Daylight Time", "PDT") + Arguments.of(ZonedDateTime.of(2026, 4, 5, 0, 0, 0, 0, ZoneId.of("America/Vancouver")), Locale.CANADA, "Pacific Daylight Time", "PDT"), + Arguments.of(ZonedDateTime.of(2026, 12, 5, 0, 0, 0, 0, ZoneId.of("America/Vancouver")), Locale.CANADA, "Pacific Daylight Time", "PDT") ); } @@ -348,18 +350,18 @@ public void test_getZoneStrings() { // updated TZDB data are required (e.g., tz2026b for America/Vancouver). @ParameterizedTest @MethodSource("explicitDstOffsets") - public void test_ExplicitMetazoneOffsets(ZonedDateTime zdt, String expectedLong, String expectedShort) { + public void test_ExplicitMetazoneOffsets(ZonedDateTime zdt, Locale l, String expectedLong, String expectedShort) { // java.time - assertEquals(expectedLong, DateTimeFormatter.ofPattern("zzzz").format(zdt)); - assertEquals(expectedShort, DateTimeFormatter.ofPattern("z").format(zdt)); + assertEquals(expectedLong, DateTimeFormatter.ofPattern("zzzz").withLocale(l).format(zdt)); + assertEquals(expectedShort, DateTimeFormatter.ofPattern("z").withLocale(l).format(zdt)); // java.text/util var date = Date.from(zdt.toInstant()); var tz = TimeZone.getTimeZone(zdt.getZone()); - var sdf = new SimpleDateFormat("zzzz"); + var sdf = new SimpleDateFormat("zzzz", l); sdf.setTimeZone(tz); assertEquals(expectedLong, sdf.format(date)); - sdf = new SimpleDateFormat("z"); + sdf = new SimpleDateFormat("z", l); sdf.setTimeZone(tz); assertEquals(expectedShort, sdf.format(date)); } diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitUtilsTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitUtilsTest.java index 291079d3d545..461337749f6d 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitUtilsTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JUnitUtilsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -24,29 +24,82 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; +import java.io.IOException; +import java.util.List; import java.util.Map; +import java.util.Optional; +import jdk.jpackage.test.JUnitUtils.ArrayConverter; +import jdk.jpackage.test.JUnitUtils.ExceptionPattern; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.converter.ConvertWith; +import org.junit.jupiter.params.provider.CsvSource; -public class JUnitUtilsTest { +class JUnitUtilsTest { @Test - public void test_assertArrayEquals() { + void test_assertArrayEquals() { JUnitUtils.assertArrayEquals(new int[] {1, 2, 3}, new int[] {1, 2, 3}); JUnitUtils.assertArrayEquals(new long[] {1, 2, 3}, new long[] {1, 2, 3}); JUnitUtils.assertArrayEquals(new boolean[] {true, true}, new boolean[] {true, true}); JUnitUtils.assertArrayEquals(null, null); + + assertThrows(ClassCastException.class, () -> { + JUnitUtils.assertArrayEquals(new int[0], new Integer[0]); + }); + + assertThrows(AssertionError.class, () -> { + JUnitUtils.assertArrayEquals(new int[0], new int[1]); + }); + + assertThrows(AssertionError.class, () -> { + JUnitUtils.assertArrayEquals(new int[0], null); + }); + + assertThrows(AssertionError.class, () -> { + JUnitUtils.assertArrayEquals(null, new int[0]); + }); } @Test - public void test_assertArrayEquals_negative() { + void test_assertArrayEquals_negative() { assertThrows(AssertionError.class, () -> { JUnitUtils.assertArrayEquals(new int[] {1, 2, 3}, new int[] {2, 3}); }); } @Test - public void test_exceptionAsPropertyMapWithMessageWithoutCause() { + void test_removeExceptionCause() { + + var ex = JUnitUtils.removeExceptionCause(new IllegalArgumentException("Hello", new NullPointerException())); + assertEquals(null, ex.getCause()); + + var props = JUnitUtils.exceptionAsPropertyMap(ex); + assertEquals(IllegalArgumentException.class, props.get("getType")); + assertEquals("Hello", props.get("getMessage")); + assertEquals(null, props.get("getCause")); + } + + @Test + void test_exceptionAsPropertyMap() { + + var ex = new IllegalArgumentException("Hello", new NullPointerException("Bye")); + var props = JUnitUtils.exceptionAsPropertyMap(ex); + + assertEquals(IllegalArgumentException.class.getName(), props.get("getClass")); + assertEquals("Hello", props.get("getMessage")); + + @SuppressWarnings("unchecked") + var causeProps = (Map)props.get("getCause"); + assertEquals(NullPointerException.class.getName(), causeProps.get("getClass")); + assertEquals("Bye", causeProps.get("getMessage")); + assertEquals(null, causeProps.get("getCause")); + } + + @Test + void test_exceptionAsPropertyMapWithMessageWithoutCause() { var ex = new Exception("foo"); @@ -54,4 +107,143 @@ public void test_exceptionAsPropertyMapWithMessageWithoutCause() { assertEquals(Map.of("getClass", Exception.class.getName(), "getMessage", "foo"), map); } + + @ParameterizedTest + @CsvSource({ + "'a,b,c','100,200,300'", + }) + void test_ArrayConverter( + @ConvertWith(ArrayConverter.class) String[] strArray, + @ConvertWith(ArrayConverter.class) Integer[] intArray) { + + assertEquals(List.of("a", "b", "c"), List.of(strArray)); + assertEquals(List.of(100, 200, 300), List.of(intArray)); + } + + @ParameterizedTest + @CsvSource(",") + void test_ArrayConverter_null( + @ConvertWith(ArrayConverter.class) String[] strArray, + @ConvertWith(ArrayConverter.class) Integer[] intArray) { + + assertEquals(null, strArray); + assertEquals(null, intArray); + } + + @ParameterizedTest + @CsvSource({ + ",true,true", + "FOO,true,false", + "NULL,false,true", + "BAR,false,false", + }) + void test_ExceptionPattern_hasMessage(ExceptionPatternMessageMode mode, boolean exWithMessageMatch, boolean exWithoutMessageMatch) { + + var exWithMessage = new Exception(ExceptionPatternMessageMode.FOO.name()); + var exWithoutMessage = new Exception(); + + var pattern = new ExceptionPattern(); + Optional.ofNullable(mode).ifPresent(m -> { + switch (m) { + case NULL -> pattern.hasMessage(null); + default -> pattern.hasMessage(m.name()); + } + }); + + assertEquals(exWithMessageMatch, pattern.match(exWithMessage)); + assertEquals(exWithoutMessageMatch, pattern.match(exWithoutMessage)); + } + + enum ExceptionPatternMessageMode { + NULL, + FOO, + BAR, + } + + @ParameterizedTest + @CsvSource({ + ",true,true", + "NULL,false,true", + "IllegalArgumentException,true,false", + "RuntimeException,true,false", + "Exception,true,false", + "IOException,false,false", + "NullPointerException,false,false", + "TRUE,true,false", + "FALSE,false,true", + "TRUE_DEFAULT,true,false", + }) + void test_ExceptionPattern_hasCause(ExceptionPatternCauseMode mode, boolean exWithCauseMatch, boolean exWithoutCauseMatch) { + + var exWithCause = new Exception(new IllegalArgumentException()); + var exWithoutCause = new Exception(); + + var pattern = new ExceptionPattern(); + Optional.ofNullable(mode).ifPresent(m -> { + switch (m) { + case NULL -> pattern.isCauseInstanceOf(null); + case IllegalArgumentException -> pattern.isCauseInstanceOf(IllegalArgumentException.class); + case RuntimeException -> pattern.isCauseInstanceOf(RuntimeException.class); + case Exception -> pattern.isCauseInstanceOf(Exception.class); + case IOException -> pattern.isCauseInstanceOf(IOException.class); + case NullPointerException -> pattern.isCauseInstanceOf(NullPointerException.class); + case TRUE -> pattern.hasCause(true); + case FALSE -> pattern.hasCause(false); + case TRUE_DEFAULT -> pattern.hasCause(); + } + }); + + assertEquals(exWithCauseMatch, pattern.match(exWithCause)); + assertEquals(exWithoutCauseMatch, pattern.match(exWithoutCause)); + } + + enum ExceptionPatternCauseMode { + NULL, + IllegalArgumentException, + RuntimeException, + Exception, + IOException, + NullPointerException, + TRUE, + FALSE, + TRUE_DEFAULT, + } + + @ParameterizedTest + @CsvSource({ + ",true", + "NULL,true", + "IllegalArgumentException,true", + "RuntimeException,true", + "Exception,true", + "IOException,false", + "NullPointerException,false", + }) + void test_ExceptionPattern_isInstanceOf(ExceptionPatternTypeMode mode, boolean match) { + + var ex = new IllegalArgumentException(); + + var pattern = new ExceptionPattern(); + Optional.ofNullable(mode).ifPresent(m -> { + switch (m) { + case NULL -> pattern.isInstanceOf(null); + case IllegalArgumentException -> pattern.isInstanceOf(IllegalArgumentException.class); + case RuntimeException -> pattern.isInstanceOf(RuntimeException.class); + case Exception -> pattern.isInstanceOf(Exception.class); + case IOException -> pattern.isInstanceOf(IOException.class); + case NullPointerException -> pattern.isInstanceOf(NullPointerException.class); + } + }); + + assertEquals(match, pattern.match(ex)); + } + + enum ExceptionPatternTypeMode { + NULL, + IllegalArgumentException, + RuntimeException, + Exception, + NullPointerException, + IOException, + } } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestMethodSupplier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestMethodSupplier.java index 80c8b1337905..0d1efd2906a8 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestMethodSupplier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TestMethodSupplier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, 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 @@ -395,7 +395,7 @@ private static Stream createArgs(Method ... parameterSuppliers) throws } @SuppressWarnings({"unchecked", "rawtypes"}) - private static Object fromString(String value, Class toType) { + static Object fromString(String value, Class toType) { if (toType.isEnum()) { return Enum.valueOf((Class)toType, value); } diff --git a/test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/LinuxPackageBuilderTest.java b/test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/LinuxPackageBuilderTest.java index 2a760bff2715..bb537c52ca95 100644 --- a/test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/LinuxPackageBuilderTest.java +++ b/test/jdk/tools/jpackage/junit/linux/jdk.jpackage/jdk/jpackage/internal/LinuxPackageBuilderTest.java @@ -170,8 +170,6 @@ private static LinuxPackageBuilder dummy() { null, null, List.of(), - List.of(), - List.of(), ApplicationLayout.build().setAll("").create(), Optional.empty(), List.of(), diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java index 30ee8a41255f..1c6b4762a4a9 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java @@ -229,8 +229,6 @@ private Application createApplication() { null, null, List.of(), - List.of(), - List.of(), null, Optional.empty(), new ApplicationLaunchers( diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java index 23469a46088d..c99a13480739 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/PackagingPipelineTest.java @@ -618,8 +618,6 @@ private static Application createApp(AppImageLayout appImageLayout, Optional pathOptionsValid() { "app-resources,PATH_SEPARATOR", }) public void test_AppContent_valid( - @ConvertWith(OptionValueConverter.class) OptionValue>> option, + @ConvertWith(OptionValueConverter.class) OptionValue> option, Delimiter delimiter, @TempDir Path workDir) throws IOException { var spec = option.getSpec(); @@ -248,7 +250,12 @@ public void test_AppContent_valid( ).orElseThrow(); var paths = option.getFrom(Options.of(Map.of(option, convertedValue))); - var sortedPathList = paths.stream().flatMap(Collection::stream).map(RootedPath::branch).sorted().toList(); + var sortedPathList = paths.stream() + .map(ExplodedPath::children) + .flatMap(Collection::stream) + .map(ExplodedPath.Node::path) + .sorted() + .toList(); var expectedPathList = Stream.of( "a", @@ -387,10 +394,10 @@ public void test_explodedPathOptionMapper(OptionMutatorTest.TestType type, @Temp var explodePath = StandardValueConverter.explodedPathConverter().withPathFileName().create(); - ValueConverter conv = ValueConverter.create(str -> { + ValueConverter conv = ValueConverter.create(str -> { var path = StandardValueConverter.pathConv().convert(str); return explodePath.convert(path); - }, RootedPath[].class); + }, ExplodedPath.class); var test = new OptionMutatorTest<>(_ -> {}, conv) .invalidValue(workDir.resolve("nonexistent").toString()) diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java index b8b1325529de..7eac0df9729f 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java @@ -42,7 +42,7 @@ import java.util.function.UnaryOperator; import java.util.stream.Stream; import jdk.jpackage.internal.util.CompositeProxy.InvokeTunnel; -import jdk.jpackage.test.JUnitUtils.StringArrayConverter; +import jdk.jpackage.test.JUnitUtils.ArrayConverter; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.converter.ConvertWith; @@ -847,7 +847,7 @@ public String foo() { "static-foo", "static-foo,private-foo,no-foo", }) - void testMissingImplementer(@ConvertWith(StringArrayConverter.class) String[] slicesSpec) throws NoSuchMethodException, SecurityException { + void testMissingImplementer(@ConvertWith(ArrayConverter.class) String[] slicesSpec) throws NoSuchMethodException, SecurityException { interface A { void foo(); @@ -934,7 +934,7 @@ interface B extends A { "'b,a',false", }) void testAmbiguousImplementers( - @ConvertWith(StringArrayConverter.class) String[] slicesSpec, + @ConvertWith(ArrayConverter.class) String[] slicesSpec, boolean withObjectConflictResolver) throws NoSuchMethodException, SecurityException { interface A { diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/ExplodedPathTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/ExplodedPathTest.java new file mode 100644 index 000000000000..d98f319a95a5 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/ExplodedPathTest.java @@ -0,0 +1,493 @@ +/* + * Copyright (c) 2026, 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.jpackage.internal.util; + +import static jdk.jpackage.internal.util.ExplodedPath.copy; +import static jdk.jpackage.internal.util.ExplodedPath.copySpec; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; +import jdk.jpackage.internal.util.ExplodedPath.Node; +import jdk.jpackage.test.JUnitUtils.ArrayConverter; +import jdk.jpackage.test.PathDeletionPreventer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.converter.ConvertWith; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.MethodSource; + + +class ExplodedPathTest { + + @Test + void test_of_file(@TempDir Path workdir) throws IOException { + + var path = workdir.resolve("foo"); + + Files.createFile(path); + + var exp = ExplodedPath.of(path); + + assertEquals(path, exp.root()); + assertEquals(1, exp.children().size()); + assertEquals(file(""), exp.children().iterator().next()); + } + + @Test + void test_of_empty_dir(@TempDir Path path) throws IOException { + + var exp = ExplodedPath.of(path); + + assertEquals(path, exp.root()); + assertEquals(1, exp.children().size()); + assertEquals(dir(""), exp.children().iterator().next()); + } + + @Test + void test_of_non_empty_dir(@TempDir Path workdir) throws IOException { + + initTestWorkload(workdir); + + var exp = deepestFirstExplodedPath(workdir); + + assertEquals(workdir, exp.root()); + assertEquals(Set.of( + file("a/b/c/foo"), + file("a/b/foo"), + dir(""), + dir("a"), + dir("a/b"), + dir("a/b/c"), + dir("a/b/empty-dir")), Set.copyOf(exp.children())); + } + + @Test + void test_getParent() { + + var exp = new ExplodedPath(Path.of("a/b"), List.of(file("foo"), file(""))).getParent(); + + assertEquals(new ExplodedPath(Path.of("a"), List.of(file("b/foo"), file("b"))), exp); + } + + @Test + void test_Node_ctor_absolute() { + assertThrowsExactly(IllegalArgumentException.class, () -> { + new Node(Path.of("").toAbsolutePath(), true); + }); + } + + @Test + void test_copy_simple(@TempDir Path workdir) throws IOException { + + initTestWorkload(workdir); + + var dstDir = workdir.resolve("dst"); + + var src = deepestFirstExplodedPath(workdir); + + copy(List.of(copySpec(src, dstDir))); + + assertContentCopied(toUniquePaths(src), dstDir); + } + + @Test + void test_copy_merge(@TempDir Path workdir) throws IOException { + + initTestWorkload(workdir); + + var src = deepestFirstExplodedPath(workdir); + + var dstDir = workdir.resolve("dst"); + initTestFile(dstDir.resolve("a/bar")); + + copy(List.of(copySpec(src, dstDir))); + + assertContentCopied(SetBuilder.build(toUniquePaths(src)) + .add(dstDir.resolve("a/bar")) + .create(), dstDir); + } + + @ParameterizedTest + @CsvSource(delimiter = ':', value = { + "true:,", + "false:,", + "true:REPLACE_EXISTING,", + "false:REPLACE_EXISTING,", + }) + void test_copy_with_multiple_src_file_overlap( + boolean directOrder, + @ConvertWith(ArrayConverter.class) StandardCopyOption copyOptions[], + @TempDir Path workdir) throws IOException { + + initTestWorkload(workdir.resolve("1")); + initTestFile(workdir.resolve("2/a/b/foo")); + + var dstDir = workdir.resolve("dst"); + + var src = deepestFirstExplodedPath(workdir.resolve("1")); + + var specs = List.of( + copySpec(src, dstDir), + copySpec(deepestFirstExplodedPath(workdir.resolve("2")), dstDir) + ); + + copy(directOrder ? specs : specs.reversed(), copyOptions); + + assertContentCopied(SetBuilder.build(toUniquePaths(src)).mutate(builder -> { + if (!directOrder) { + builder.remove(workdir.resolve("1/a/b/foo")); + builder.add(workdir.resolve("2/a/b/foo")); + } + }).create(), dstDir); + } + + @ParameterizedTest + @CsvSource(delimiter = ':', value = { + "true:,", + "false:,", + "true:REPLACE_EXISTING,", + "false:REPLACE_EXISTING,", + }) + void test_copy_with_multiple_src_directory_overlap( + boolean directOrder, + @ConvertWith(ArrayConverter.class) StandardCopyOption copyOptions[], + @TempDir Path workdir) throws IOException { + + // "a/b/foo" path is a file in the "1" exploded directory. + // "a/b/foo" path is a directory in the "2" exploded directory. + initTestWorkload(workdir.resolve("1")); + initTestFile(workdir.resolve("2/a/b/foo/bar")); + + var dstDir = workdir.resolve("dst"); + + var src = deepestFirstExplodedPath(workdir.resolve("1")); + + var specs = List.of( + copySpec(src, dstDir), + copySpec(deepestFirstExplodedPath(workdir.resolve("2")), dstDir) + ); + + copy(directOrder ? specs : specs.reversed(), copyOptions); + + assertContentCopied(SetBuilder.build(toUniquePaths(src)).mutate(builder -> { + if (!directOrder) { + builder.remove(workdir.resolve("1/a/b/foo")); + builder.add(workdir.resolve("2/a/b/foo")); + builder.add(workdir.resolve("2/a/b/foo/bar")); + } + }).create(), dstDir); + } + + @ParameterizedTest + @MethodSource + void test_copy_with_existing_path_overlap( + ExistingPathOverlap type, + boolean replaceExisting, + @TempDir Path workdir) throws IOException { + + initTestWorkload(workdir); + final var src = deepestFirstExplodedPath(workdir); + final var dstContent = SetBuilder.build(toUniquePaths(src)); + + final var dstDir = workdir.resolve("dst"); + switch (type) { + case FILE_ON_FILE -> { + initTestFile(dstDir.resolve("a/b/foo")); + if (!replaceExisting) { + dstContent.remove(workdir.resolve("a/b/foo")); + dstContent.add(dstDir.resolve("a/b/foo")); + } + } + case FILE_ON_DIR -> { + // "a/b/foo" is a source file. + // Create a non-empty "a/b/foo" subdirectory in the destination directory. + initTestFile(dstDir.resolve("a/b/foo/bar")); + initTestFile(dstDir.resolve("a/b/foo/buz")); + if (!replaceExisting) { + dstContent.remove(workdir.resolve("a/b/foo")); + dstContent.add(dstDir.resolve("a/b/foo")); + dstContent.add(dstDir.resolve("a/b/foo/bar")); + dstContent.add(dstDir.resolve("a/b/foo/buz")); + } + } + case DIR_ON_FILE -> { + initTestFile(dstDir.resolve("a/b")); + if (!replaceExisting) { + dstContent.remove(workdir.resolve("a/b")); + dstContent.remove(workdir.resolve("a/b/foo")); + dstContent.remove(workdir.resolve("a/b/c/foo")); + dstContent.remove(workdir.resolve("a/b/c")); + dstContent.remove(workdir.resolve("a/b/empty-dir")); + dstContent.add(dstDir.resolve("a/b")); + } + } + case DIR_ON_DIR -> { + initTestFile(dstDir.resolve("a/b/c/bar")); + initTestFile(dstDir.resolve("a/b/c/d/far")); + initTestFile(dstDir.resolve("a/b/buz")); + + dstContent.add(dstDir.resolve("a/b/c/bar")); + dstContent.add(dstDir.resolve("a/b/c/d")); + dstContent.add(dstDir.resolve("a/b/c/d/far")); + dstContent.add(dstDir.resolve("a/b/buz")); + } + } + + if (replaceExisting) { + copy(List.of(copySpec(src, dstDir)), StandardCopyOption.REPLACE_EXISTING); + } else { + copy(List.of(copySpec(src, dstDir))); + } + + assertContentCopied(dstContent.create(), dstDir); + } + + @SuppressWarnings({ "try" }) + @Test + void test_copy_IOException(@TempDir Path workdir) throws IOException { + + initTestWorkload(workdir); + + var src = ExplodedPath.of(workdir); + + var dstDir = workdir.resolve("dst"); + + var lockPath = dstDir.resolve("a/b/foo"); + + Files.createDirectories(lockPath.getParent()); + + try (final var lock = PathDeletionPreventer.DEFAULT.preventPathDeletion(lockPath)) { + assertThrows(IOException.class, () -> { + copy(List.of(copySpec(src, dstDir)), StandardCopyOption.REPLACE_EXISTING); + }); + } + } + + @ParameterizedTest + @CsvSource(delimiter = ':', value = { + "true:,", + "false:,", + "true:REPLACE_EXISTING,", + "false:REPLACE_EXISTING,", + }) + void test_copy_with_nested_destination_blocked( + boolean directOrder, + @ConvertWith(ArrayConverter.class) StandardCopyOption copyOptions[], + @TempDir Path workdir) throws IOException { + + var appFile = workdir.resolve("foo/app"); + initTestFile(appFile); + + var inputDir = workdir.resolve("input"); + initTestFile(inputDir.resolve("child.jar")); + + var dstDir = workdir.resolve("dst/lib"); + + var specs = List.of( + // Creates dst/lib/app as a file. + copySpec(deepestFirstExplodedPath(appFile).getParent(), dstDir), + + // Creates dst/lib/app directory. + copySpec(deepestFirstExplodedPath(inputDir), dstDir.resolve("app")) + ); + + copy(directOrder ? specs : specs.reversed(), copyOptions); + + if (directOrder) { + assertContentCopied(Set.of(appFile, appFile.getParent()), dstDir); + } else { + assertEquals( + Set.of(Path.of(""), Path.of("app"), Path.of("app/child.jar")), + ExplodedPath.of(dstDir).children().stream().map(Node::path).collect(Collectors.toSet())); + assertContentCopied(Set.of(inputDir, inputDir.resolve("child.jar")), dstDir.resolve("app")); + } + } + + @ParameterizedTest + @CsvSource(delimiter = ':', value = { + "true:,", + "false:,", + "true:REPLACE_EXISTING,", + "false:REPLACE_EXISTING,", + }) + void test_copy_with_nested_destination_merge( + boolean directOrder, + @ConvertWith(ArrayConverter.class) StandardCopyOption copyOptions[], + @TempDir Path workdir) throws IOException { + + var parentResources = workdir.resolve("parent/Resources"); + initTestFile(parentResources.resolve("parent.txt")); + + var nestedResources = workdir.resolve("nested"); + initTestFile(nestedResources.resolve("nested.txt")); + + var dstContents = workdir.resolve("dst/Contents"); + + var specs = List.of( + copySpec(deepestFirstExplodedPath(parentResources).getParent(), dstContents), + copySpec(deepestFirstExplodedPath(nestedResources), dstContents.resolve("Resources")) + ); + + copy(directOrder ? specs : specs.reversed(), copyOptions); + + assertContentCopied(Set.of( + parentResources, + parentResources.resolve("parent.txt"), + nestedResources.resolve("nested.txt")), dstContents.resolve("Resources")); + } + + enum ExistingPathOverlap { + FILE_ON_FILE, + FILE_ON_DIR, + DIR_ON_FILE, + DIR_ON_DIR, + ; + } + + private static Collection test_copy_with_existing_path_overlap() { + + Collection testCases = new ArrayList<>(); + + for (var replaceExisting : List.of(true, false)) { + for (var type : ExistingPathOverlap.values()) { + testCases.add(Arguments.of(type, replaceExisting)); + } + } + + return testCases; + } + + private static ExplodedPath.Node dir(Path path) { + return new Node(path, true); + } + + private static ExplodedPath.Node dir(String path) { + return dir(Path.of(path)); + } + + private static ExplodedPath.Node file(Path path) { + return new Node(path, false); + } + + private static ExplodedPath.Node file(String path) { + return file(Path.of(path)); + } + + private static void initTestWorkload(Path root) throws IOException { + Files.createDirectories(root.resolve("a/b/c")); + initTestFile(root.resolve("a/b/c/foo")); + initTestFile(root.resolve("a/b/foo")); + Files.createDirectories(root.resolve("a/b/empty-dir")); + } + + private static void initTestFile(Path path) throws IOException { + Files.createDirectories(path.getParent()); + Files.writeString(path, path.toString()); + } + + private static void assertFileCopied(Path src, Path dst) throws IOException { + assertTrue(Files.isRegularFile(dst)); + assertEquals(Files.readAllLines(src), Files.readAllLines(dst)); + } + + private static void assertContentCopied(Set sources, Path dstDir) throws IOException { + + var dst = new ExplodedPath(dstDir, new ArrayList<>(ExplodedPath.of(dstDir).children())); + + assertEquals(sources.size(), dst.children().size()); + + UnaryOperator srcToDst = path -> { + var child = dst.children().stream() + .filter(n -> { + return path.endsWith(n.path()) || n.path().equals(Path.of("")); + }) + .sorted(Comparator.comparingInt((Node n) -> { + return pathDepth(n.path()); + }).thenComparing((_, _) -> { + throw new AssertionError(); + }).reversed()) + .findFirst().orElseThrow(); + + assertTrue(dst.children().remove(child)); + + return dstDir.resolve(child.path()); + }; + + for (var srcPath : sources) { + var dstPath = srcToDst.apply(srcPath); + if (Files.isDirectory(srcPath)) { + assertTrue(Files.isDirectory(dstPath)); + } else { + assertFileCopied(srcPath, dstPath); + } + } + + assertTrue(dst.children().isEmpty()); + } + + private static Set toUniquePaths(ExplodedPath exp) { + return exp.children().stream() + .map(Node::path) + .map(exp.root()::resolve) + .collect(Collectors.toMap(x -> x, x -> x)).keySet(); + } + + /** + * Returns an {@code ExplodedPath} instance whose children are ordered in reverse + * order for use with {@link ExplodedPath#copy(List, java.nio.file.CopyOption...)}. + * + * @param root the root path + * @throws IOException if an I/O error occurs + */ + private static ExplodedPath deepestFirstExplodedPath(Path root) throws IOException { + return new ExplodedPath( + root, + ExplodedPath.of(root).children().stream() + .sorted(Comparator.comparingInt((Node n) -> { + return pathDepth(n.path()); + }).thenComparing((Node n) -> { + return n.path().toString(); + }).reversed()) + .collect(Collectors.toUnmodifiableList())); + } + + private static int pathDepth(Path path) { + return path.equals(Path.of("")) ? 0 : path.getNameCount(); + } +} diff --git a/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitUtils.java b/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitUtils.java index 97041ea1a0e4..a3f7c83f90cd 100644 --- a/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitUtils.java +++ b/test/jdk/tools/jpackage/junit/tools/jdk/jpackage/test/JUnitUtils.java @@ -24,14 +24,18 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import java.lang.reflect.Array; import java.util.Map; import java.util.Objects; +import java.util.Optional; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.params.converter.SimpleArgumentConverter; public final class JUnitUtils { + private JUnitUtils() {} + /** * Convenience adapter for {@link Assertions#assertArrayEquals(byte[], byte[])}, * {@link Assertions#assertArrayEquals(int[], int[])}, @@ -82,19 +86,24 @@ public boolean match(Exception ex) { return false; } - if (expectedMessage != null && !expectedMessage.equals(ex.getMessage())) { + if (expectedMessage != null && !Objects.equals(expectedMessage.orElse(null), ex.getMessage())) { return false; } - if (expectedCauseType != null && !expectedCauseType.isInstance(ex.getCause())) { - return false; + if (expectedCauseType != null) { + var cause = ex.getCause(); + if (expectedCauseType.isEmpty() != (cause == null)) { + return false; + } else if (expectedCauseType.isPresent() && !expectedCauseType.orElseThrow().isInstance(cause)) { + return false; + } } return true; } public ExceptionPattern hasMessage(String v) { - expectedMessage = v; + expectedMessage = Optional.ofNullable(v); return this; } @@ -104,7 +113,7 @@ public ExceptionPattern isInstanceOf(Class v) { } public ExceptionPattern isCauseInstanceOf(Class v) { - expectedCauseType = v; + expectedCauseType = Optional.ofNullable(v); return this; } @@ -116,21 +125,34 @@ public ExceptionPattern hasCause() { return hasCause(true); } - private String expectedMessage; + private Optional expectedMessage; private Class expectedType; - private Class expectedCauseType; + private Optional> expectedCauseType; } - public static class StringArrayConverter extends SimpleArgumentConverter { + public static class ArrayConverter extends SimpleArgumentConverter { @Override protected Object convert(Object source, Class targetType) { - if (source instanceof String && String[].class.isAssignableFrom(targetType)) { - return ((String) source).split("\\s*,\\s*"); - } else { - throw new IllegalArgumentException(); + + if (source == null) { + return null; + } + + if (!(source instanceof String value) || !targetType.isArray()) { + throw new IllegalArgumentException("Expected a String and an array type"); } + + var componentType = targetType.getComponentType(); + var values = value.split("\\s*,\\s*"); + var result = Array.newInstance(componentType, values.length); + + for (int i = 0; i < values.length; i++) { + Array.set(result, i, TestMethodSupplier.fromString(values[i], componentType)); + } + + return result; } } @@ -142,6 +164,7 @@ private static final class ExceptionCauseRemover extends Exception { type = ex.getClass(); } + // Not explicitly but implicitly used by exceptionAsPropertyMap() public Class getType() { return type; } diff --git a/test/langtools/tools/javac/SuperInit/EarlyAssignments.java b/test/langtools/tools/javac/SuperInit/EarlyAssignments.java index e1ba3a67381a..0143c990662e 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyAssignments.java +++ b/test/langtools/tools/javac/SuperInit/EarlyAssignments.java @@ -21,9 +21,9 @@ public Inner1() { } public Inner1(int y) { - y = x; // OK - "x" belongs to this class - y = this.x; // OK - "x" belongs to this class - y = Inner1.this.x; // OK - "x" belongs to this class + y = x; // OK - "x" belongs to this class, simple access + y = this.x; // FAIL - "x" belongs to this class, but qualified access + y = Inner1.this.x; // FAIL - "x" belongs to this class, but qualified access super(); } @@ -104,13 +104,17 @@ public Inner4() { public Inner4(int a) { this.x = 0; // OK - this.x = this.x + 1; // OK + this.x = x + 1; // OK, simple access + this.x = this.x + 1; // FAIL, qualified access + this.x = Inner4.this.x + 1; // FAIL, qualified access super(); } public Inner4(char a) { Inner4.this.x = 0; // OK - Inner4.this.x = Inner4.this.x + 1; // OK + Inner4.this.x = x + 1; // OK, simple access + Inner4.this.x = this.x + 1; // FAIL, qualified access + Inner4.this.x = Inner4.this.x + 1; // FAIL, qualified access super(); } } diff --git a/test/langtools/tools/javac/SuperInit/EarlyAssignments.out b/test/langtools/tools/javac/SuperInit/EarlyAssignments.out index 5bb1dc9120e1..2e80ed5bb153 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyAssignments.out +++ b/test/langtools/tools/javac/SuperInit/EarlyAssignments.out @@ -1,3 +1,5 @@ +EarlyAssignments.java:25:21: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:26:28: compiler.err.cant.ref.before.ctor.called: x EarlyAssignments.java:34:26: compiler.err.cant.ref.before.ctor.called: x EarlyAssignments.java:35:21: compiler.err.cant.ref.before.ctor.called: x EarlyAssignments.java:36:26: compiler.err.cant.ref.before.ctor.called: x @@ -10,15 +12,19 @@ EarlyAssignments.java:69:13: compiler.err.cant.ref.before.ctor.called: x EarlyAssignments.java:70:17: compiler.err.cant.ref.before.ctor.called: x EarlyAssignments.java:71:25: compiler.err.cant.ref.before.ctor.called: this EarlyAssignments.java:72:31: compiler.err.cant.ref.before.ctor.called: this -EarlyAssignments.java:122:17: compiler.err.cant.ref.before.ctor.called: x -EarlyAssignments.java:127:22: compiler.err.cant.ref.before.ctor.called: x -EarlyAssignments.java:132:29: compiler.err.cant.ref.before.ctor.called: x -EarlyAssignments.java:137:22: compiler.err.cant.ref.before.ctor.called: x -EarlyAssignments.java:142:28: compiler.err.cant.ref.before.ctor.called: x -EarlyAssignments.java:151:13: compiler.err.cant.assign.initialized.before.ctor.called: x -EarlyAssignments.java:160:13: compiler.err.cant.assign.val.to.var: final, x -EarlyAssignments.java:171:13: compiler.err.cant.ref.before.ctor.called: this -EarlyAssignments.java:180:17: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:108:26: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:109:33: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:116:33: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:117:40: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:126:17: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:131:22: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:136:29: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:141:22: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:146:28: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:155:13: compiler.err.cant.assign.initialized.before.ctor.called: x +EarlyAssignments.java:164:13: compiler.err.cant.assign.val.to.var: final, x +EarlyAssignments.java:175:13: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:184:17: compiler.err.cant.ref.before.ctor.called: x - compiler.note.preview.filename: EarlyAssignments.java, DEFAULT - compiler.note.preview.recompile -21 errors +27 errors diff --git a/test/langtools/tools/javac/SuperInit/InitAssignOp.java b/test/langtools/tools/javac/SuperInit/InitAssignOp.java index 499a2ba32503..21ee3e3c8c70 100644 --- a/test/langtools/tools/javac/SuperInit/InitAssignOp.java +++ b/test/langtools/tools/javac/SuperInit/InitAssignOp.java @@ -63,7 +63,7 @@ public class Test { private int i; public Test() { - ++this.i; + ++i; super(); } public static void main(String... args) { @@ -72,7 +72,7 @@ public static void main(String... args) { } """, List.of( - "Test.java:5:15: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.value.classes)", + "Test.java:5:11: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.value.classes)", "1 error" )), new TestCase(""" @@ -80,7 +80,7 @@ public class Test { private int i; public Test() { - this.i++; + i++; super(); } public static void main(String... args) { @@ -89,7 +89,7 @@ public static void main(String... args) { } """, List.of( - "Test.java:5:13: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.value.classes)", + "Test.java:5:9: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.value.classes)", "1 error" )), new TestCase(""" @@ -97,7 +97,7 @@ public class Test { private int i; public Test() { - this.i += 1; + i += 1; super(); } public static void main(String... args) { @@ -106,7 +106,7 @@ public static void main(String... args) { } """, List.of( - "Test.java:5:13: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.value.classes)", + "Test.java:5:9: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.value.classes)", "1 error" )), }; diff --git a/test/langtools/tools/javac/SuperInit/SuperInitFails.java b/test/langtools/tools/javac/SuperInit/SuperInitFails.java index fbfebc088f86..1149e908d3eb 100644 --- a/test/langtools/tools/javac/SuperInit/SuperInitFails.java +++ b/test/langtools/tools/javac/SuperInit/SuperInitFails.java @@ -95,6 +95,7 @@ public SuperInitFails(char[] x) { public SuperInitFails(short[] x) { this.x++; // this should FAIL + SuperInitFails.this.x++; // this should FAIL super(); } diff --git a/test/langtools/tools/javac/SuperInit/SuperInitFails.out b/test/langtools/tools/javac/SuperInit/SuperInitFails.out index af7dc5fe4fd0..2a4e9bb9de53 100644 --- a/test/langtools/tools/javac/SuperInit/SuperInitFails.out +++ b/test/langtools/tools/javac/SuperInit/SuperInitFails.out @@ -3,35 +3,37 @@ SuperInitFails.java:65:9: compiler.err.cant.ref.before.ctor.called: this SuperInitFails.java:70:9: compiler.err.cant.ref.before.ctor.called: super SuperInitFails.java:75:23: compiler.err.cant.ref.before.ctor.called: this SuperInitFails.java:80:23: compiler.err.cant.ref.before.ctor.called: super -SuperInitFails.java:102:33: compiler.err.cant.ref.before.ctor.called: this -SuperInitFails.java:107:14: compiler.err.cant.ref.before.ctor.called: this -SuperInitFails.java:111:20: compiler.err.not.encl.class: java.lang.Object -SuperInitFails.java:115:17: compiler.err.cant.ref.before.ctor.called: super -SuperInitFails.java:122:22: compiler.err.call.must.only.appear.in.ctor -SuperInitFails.java:128:9: compiler.err.cant.ref.before.ctor.called: this -SuperInitFails.java:136:9: compiler.err.non.canonical.constructor.invoke.another.constructor: SuperInitFails.Record1 -SuperInitFails.java:141:9: compiler.err.non.canonical.constructor.invoke.another.constructor: SuperInitFails.Record2 -SuperInitFails.java:158:50: compiler.err.cant.ref.before.ctor.called: x -SuperInitFails.java:162:15: compiler.err.cant.ref.before.ctor.called: this -SuperInitFails.java:171:13: compiler.err.cant.ref.before.ctor.called: x -SuperInitFails.java:175:17: compiler.err.cant.ref.before.ctor.called: x -SuperInitFails.java:179:24: compiler.err.cant.ref.before.ctor.called: x -SuperInitFails.java:183:18: compiler.err.cant.ref.before.ctor.called: x -SuperInitFails.java:189:32: compiler.err.cant.ref.before.ctor.called: x -SuperInitFails.java:198:36: compiler.err.cant.ref.before.ctor.called: xx -SuperInitFails.java:209:25: compiler.err.return.before.superclass.initialized -SuperInitFails.java:214:33: compiler.err.ctor.calls.not.allowed.here -SuperInitFails.java:219:29: compiler.err.redundant.superclass.init -SuperInitFails.java:232:41: compiler.err.cant.ref.before.ctor.called: x -SuperInitFails.java:233:16: compiler.err.cant.ref.before.ctor.called: x -SuperInitFails.java:242:35: compiler.err.cant.ref.before.ctor.called: this -SuperInitFails.java:254:13: compiler.err.cant.ref.before.ctor.called: x -SuperInitFails.java:267:18: compiler.err.cant.ref.before.ctor.called: x -SuperInitFails.java:283:50: compiler.err.cant.ref.before.ctor.called: check -SuperInitFails.java:284:39: compiler.err.cant.ref.before.ctor.called: check -SuperInitFails.java:294:20: compiler.err.cant.ref.before.ctor.called: this -SuperInitFails.java:306:26: compiler.err.not.encl.class: SuperInitFails.Inner11.Inner11_1 -SuperInitFails.java:316:37: compiler.err.cant.ref.before.ctor.called: check +SuperInitFails.java:97:13: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:98:28: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:103:33: compiler.err.cant.ref.before.ctor.called: this +SuperInitFails.java:108:14: compiler.err.cant.ref.before.ctor.called: this +SuperInitFails.java:112:20: compiler.err.not.encl.class: java.lang.Object +SuperInitFails.java:116:17: compiler.err.cant.ref.before.ctor.called: super +SuperInitFails.java:123:22: compiler.err.call.must.only.appear.in.ctor +SuperInitFails.java:129:9: compiler.err.cant.ref.before.ctor.called: this +SuperInitFails.java:137:9: compiler.err.non.canonical.constructor.invoke.another.constructor: SuperInitFails.Record1 +SuperInitFails.java:142:9: compiler.err.non.canonical.constructor.invoke.another.constructor: SuperInitFails.Record2 +SuperInitFails.java:159:50: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:163:15: compiler.err.cant.ref.before.ctor.called: this +SuperInitFails.java:172:13: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:176:17: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:180:24: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:184:18: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:190:32: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:199:36: compiler.err.cant.ref.before.ctor.called: xx +SuperInitFails.java:210:25: compiler.err.return.before.superclass.initialized +SuperInitFails.java:215:33: compiler.err.ctor.calls.not.allowed.here +SuperInitFails.java:220:29: compiler.err.redundant.superclass.init +SuperInitFails.java:233:41: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:234:16: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:243:35: compiler.err.cant.ref.before.ctor.called: this +SuperInitFails.java:255:13: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:268:18: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:284:50: compiler.err.cant.ref.before.ctor.called: check +SuperInitFails.java:285:39: compiler.err.cant.ref.before.ctor.called: check +SuperInitFails.java:295:20: compiler.err.cant.ref.before.ctor.called: this +SuperInitFails.java:307:26: compiler.err.not.encl.class: SuperInitFails.Inner11.Inner11_1 +SuperInitFails.java:317:37: compiler.err.cant.ref.before.ctor.called: check SuperInitFails.java:36:13: compiler.err.call.must.only.appear.in.ctor SuperInitFails.java:40:14: compiler.err.call.must.only.appear.in.ctor SuperInitFails.java:44:14: compiler.err.call.must.only.appear.in.ctor @@ -40,7 +42,5 @@ SuperInitFails.java:52:33: compiler.err.call.must.only.appear.in.ctor SuperInitFails.java:56:32: compiler.err.call.must.only.appear.in.ctor SuperInitFails.java:86:18: compiler.err.ctor.calls.not.allowed.here SuperInitFails.java:92:13: compiler.err.return.before.superclass.initialized -SuperInitFails.java:153:18: compiler.err.call.must.only.appear.in.ctor -- compiler.note.preview.filename: SuperInitFails.java, DEFAULT -- compiler.note.preview.recompile -43 errors +SuperInitFails.java:154:18: compiler.err.call.must.only.appear.in.ctor +45 errors diff --git a/test/langtools/tools/javac/SuperInit/ValueClassSuperInitFails.java b/test/langtools/tools/javac/SuperInit/ValueClassSuperInitFails.java index e896aa977910..971a22a419ed 100644 --- a/test/langtools/tools/javac/SuperInit/ValueClassSuperInitFails.java +++ b/test/langtools/tools/javac/SuperInit/ValueClassSuperInitFails.java @@ -182,4 +182,10 @@ public ValueClassSuperInitFails(long[][] z) { // these two should FAIL int a = b; int aa = super.b; + + public static value class Forward { + int y = this.x; // FAIL, qualified access + int z = Forward.this.x; // FAIL, qualified access + int x = 1; + } } diff --git a/test/langtools/tools/javac/SuperInit/ValueClassSuperInitFails.out b/test/langtools/tools/javac/SuperInit/ValueClassSuperInitFails.out index cc344c35f710..a8def90c1ea5 100644 --- a/test/langtools/tools/javac/SuperInit/ValueClassSuperInitFails.out +++ b/test/langtools/tools/javac/SuperInit/ValueClassSuperInitFails.out @@ -16,6 +16,8 @@ ValueClassSuperInitFails.java:175:49: compiler.err.cant.ref.before.ctor.called: ValueClassSuperInitFails.java:179:15: compiler.err.cant.ref.before.ctor.called: this ValueClassSuperInitFails.java:183:13: compiler.err.cant.ref.before.ctor.called: b ValueClassSuperInitFails.java:184:19: compiler.err.cant.ref.before.ctor.called: b +ValueClassSuperInitFails.java:187:21: compiler.err.cant.ref.before.ctor.called: x +ValueClassSuperInitFails.java:188:29: compiler.err.cant.ref.before.ctor.called: x ValueClassSuperInitFails.java:43:13: compiler.err.call.must.only.appear.in.ctor ValueClassSuperInitFails.java:47:14: compiler.err.call.must.only.appear.in.ctor ValueClassSuperInitFails.java:51:14: compiler.err.call.must.only.appear.in.ctor @@ -27,4 +29,4 @@ ValueClassSuperInitFails.java:99:13: compiler.err.return.before.superclass.initi ValueClassSuperInitFails.java:170:18: compiler.err.call.must.only.appear.in.ctor - compiler.note.preview.filename: ValueClassSuperInitFails.java, DEFAULT - compiler.note.preview.recompile -27 errors +29 errors diff --git a/test/langtools/tools/javac/SuperInit/ValueClassSuperInitGood.java b/test/langtools/tools/javac/SuperInit/ValueClassSuperInitGood.java index ec4566362cf0..349655534508 100644 --- a/test/langtools/tools/javac/SuperInit/ValueClassSuperInitGood.java +++ b/test/langtools/tools/javac/SuperInit/ValueClassSuperInitGood.java @@ -82,7 +82,7 @@ static value class Test3 { new Object().hashCode(); this.x = new Object().hashCode(); this.y = new Object().hashCode() % 17; - this.z = this.x + this.y; + this.z = x + y; super(); } } @@ -381,14 +381,10 @@ public int hashCode() { } public static value class Test20 { - private final int[] data1 = new int[10]; - private final int[] data2 = new int[10]; - private final int[] data3 = new int[10]; + private final int[] data = new int[10]; Test20() { - for (int i = 0; i < data1.length; i++) { - data1[i] = i; // OK we are assigning to an array component - this.data2[i] = i; // OK we are assigning to an array component - Test20.this.data3[i] = i; // OK we are assigning to an array component + for (int i = 0; i < data.length; i++) { + data[i] = i; // OK we are assigning to an array component } } } diff --git a/test/langtools/tools/javac/diags/examples.not-yet.txt b/test/langtools/tools/javac/diags/examples.not-yet.txt index 4e4227f757aa..08fe5b75461e 100644 --- a/test/langtools/tools/javac/diags/examples.not-yet.txt +++ b/test/langtools/tools/javac/diags/examples.not-yet.txt @@ -147,6 +147,7 @@ compiler.note.preview.plural.additional # preview feature suppor compiler.warn.declared.using.preview # after making sealed classes a final feature there is no other # preview feature but we should keep this key for future use just # in case +compiler.misc.illegal.tvar.bound # ClassReader # The following module-related messages will have to stay on the not-yet list for various reasons: compiler.warn.locn.unknown.file.on.module.path # Never issued ATM (short circuited with an if (false)) diff --git a/test/langtools/tools/javac/diags/examples/BindingPattern.java b/test/langtools/tools/javac/diags/examples/BindingPattern.java index 01913a47fd76..fa88451326bb 100644 --- a/test/langtools/tools/javac/diags/examples/BindingPattern.java +++ b/test/langtools/tools/javac/diags/examples/BindingPattern.java @@ -23,11 +23,15 @@ // key: compiler.err.not.exhaustive.details // key: compiler.misc.binding.pattern +// key: compiler.misc.missing.case class BindingPattern { - int t(Object o) { - return switch (o) { - case String s -> 0; + int t(I i) { + return switch (i) { + case R1 _ -> 0; }; } + sealed interface I {} + record R1() implements I {} + record R2() implements I {} } diff --git a/test/langtools/tools/javac/diags/examples/EnumConstantPattern.java b/test/langtools/tools/javac/diags/examples/EnumConstantPattern.java index b2ab5b9028d8..ba69461f64e2 100644 --- a/test/langtools/tools/javac/diags/examples/EnumConstantPattern.java +++ b/test/langtools/tools/javac/diags/examples/EnumConstantPattern.java @@ -23,6 +23,7 @@ // key: compiler.err.not.exhaustive.details // key: compiler.misc.enum.constant.pattern +// key: compiler.misc.missing.case class NotExhaustiveDetails { int t(I i) { diff --git a/test/langtools/tools/javac/diags/examples/MissingCase.java b/test/langtools/tools/javac/diags/examples/MissingCase.java new file mode 100644 index 000000000000..bb42a2088252 --- /dev/null +++ b/test/langtools/tools/javac/diags/examples/MissingCase.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2026, 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. + */ + +// key: compiler.err.not.exhaustive.details +// key: compiler.misc.binding.pattern +// key: compiler.misc.missing.case + +class MissingCase { + int t(I i) { + return switch (i) { + case R1 _ -> 0; + }; + } + sealed interface I {} + record R1() implements I {} + record R2() implements I {} +} diff --git a/test/langtools/tools/javac/diags/examples/MissingCases.java b/test/langtools/tools/javac/diags/examples/MissingCases.java new file mode 100644 index 000000000000..2d6fd44881f1 --- /dev/null +++ b/test/langtools/tools/javac/diags/examples/MissingCases.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2026, 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. + */ + +// key: compiler.err.not.exhaustive.details +// key: compiler.misc.binding.pattern +// key: compiler.misc.missing.cases + +class MissingCases { + int t(I i) { + return switch (i) { + case R1 _ -> 0; + }; + } + sealed interface I {} + record R1() implements I {} + record R2() implements I {} + record R3() implements I {} +} diff --git a/test/langtools/tools/javac/diags/examples/RecordPattern.java b/test/langtools/tools/javac/diags/examples/RecordPattern.java index 2bb43bfd8002..775a78d5daa7 100644 --- a/test/langtools/tools/javac/diags/examples/RecordPattern.java +++ b/test/langtools/tools/javac/diags/examples/RecordPattern.java @@ -23,6 +23,7 @@ // key: compiler.err.not.exhaustive.statement.details // key: compiler.misc.record.pattern +// key: compiler.misc.missing.case class RecordPattern { void t(R r) { diff --git a/test/langtools/tools/javac/generics/typevars/SOEArrayBoundInheritedTest.java b/test/langtools/tools/javac/generics/typevars/SOEArrayBoundInheritedTest.java new file mode 100644 index 000000000000..dd3399a8d3cf --- /dev/null +++ b/test/langtools/tools/javac/generics/typevars/SOEArrayBoundInheritedTest.java @@ -0,0 +1,21 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8389044 + * @summary javac crashes with StackOverflowError erasing a self-referential + * array-typed type-variable bound reached through inheritance + * @compile/fail/ref=SOEArrayBoundInheritedTest.out -XDrawDiagnostics SOEArrayBoundInheritedTest.java + */ + +class SOEArrayBoundInheritedTest { + void m() { + System.out.println(new A().f()); + } +} + +interface I { T f(); } + +class B implements I { + public U f() { return null; } +} + +class A extends B {} diff --git a/test/langtools/tools/javac/generics/typevars/SOEArrayBoundInheritedTest.out b/test/langtools/tools/javac/generics/typevars/SOEArrayBoundInheritedTest.out new file mode 100644 index 000000000000..8fab2a0c0cfb --- /dev/null +++ b/test/langtools/tools/javac/generics/typevars/SOEArrayBoundInheritedTest.out @@ -0,0 +1,2 @@ +SOEArrayBoundInheritedTest.java:17:20: compiler.err.type.found.req: U[], (compiler.misc.type.req.class) +1 error diff --git a/test/langtools/tools/javac/generics/typevars/TypeVarArrayInBoundTest.java b/test/langtools/tools/javac/generics/typevars/TypeVarArrayInBoundTest.java index 5a5134a72713..046ae3df3a1d 100644 --- a/test/langtools/tools/javac/generics/typevars/TypeVarArrayInBoundTest.java +++ b/test/langtools/tools/javac/generics/typevars/TypeVarArrayInBoundTest.java @@ -1,11 +1,11 @@ /* * @test /nodynamiccopyright/ - * @bug 8388979 + * @bug 8388979 8389044 * @summary javac crashes with NullPointerException in Types.erasure when * evaluating bounds of mutually dependent array type variables * inside an intersection type definition * @build TypeVarArrayInBound - * @compile TypeVarArrayInBoundTest.java + * @compile/fail/ref=TypeVarArrayInBoundTest.out -XDrawDiagnostics TypeVarArrayInBoundTest.java */ class TypeVarArrayInBoundTest { TypeVarArrayInBound field; diff --git a/test/langtools/tools/javac/generics/typevars/TypeVarArrayInBoundTest.out b/test/langtools/tools/javac/generics/typevars/TypeVarArrayInBoundTest.out new file mode 100644 index 000000000000..7260f5026fcd --- /dev/null +++ b/test/langtools/tools/javac/generics/typevars/TypeVarArrayInBoundTest.out @@ -0,0 +1,2 @@ +TypeVarArrayInBoundTest.java:11:5: compiler.err.cant.access: TypeVarArrayInBound, (compiler.misc.bad.class.file.header: TypeVarArrayInBound.class, (compiler.misc.illegal.tvar.bound: B[])) +1 error diff --git a/test/langtools/tools/javac/patterns/ExhaustivenessConvenientErrors.java b/test/langtools/tools/javac/patterns/ExhaustivenessConvenientErrors.java index 6935fcfa0063..f494d5951833 100644 --- a/test/langtools/tools/javac/patterns/ExhaustivenessConvenientErrors.java +++ b/test/langtools/tools/javac/patterns/ExhaustivenessConvenientErrors.java @@ -39,10 +39,10 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; +import javax.tools.Diagnostic; import toolbox.JavacTask; import toolbox.Task; @@ -530,6 +530,640 @@ int t(Base b) { "Test.Pair(Test.Pair(Test.Pair _,Test.Base _),Test.Pair(Test.Pair(Test.Pair _,Test.Base _),Test.Base _))"); } + @Test + public void testInaccessiblePermittedType1(Path base) throws Exception { + doTest(base, + new String[0], + """ + class Lib { + sealed interface Base {} + record NoOp() implements Base {} + private record Inaccessible() implements Base {} + } + public class Test { + int t(Lib.Base b) { + return switch (b) { + case Lib.NoOp _ -> 0; + //Inaccessible missing, but cannot be used here. + }; + } + } + """, + "Lib.Base _"); + } + + @Test + public void testInaccessiblePermittedType2(Path base) throws Exception { + doTest(base, + new String[0], + """ + class Lib { + sealed interface Base {} + record NoOp() implements Base {} + private sealed interface Intermediate1 extends Base {} + private sealed interface Intermediate2 extends Intermediate1 {} + record Rec() implements Intermediate2 {} + } + public class Test { + int t(Lib.Base b) { + return switch (b) { + case Lib.NoOp _ -> 0; +// case Lib.Inaccessible _ -> 0; + }; + } + } + """, + "Lib.Rec _"); + } + + @Test + public void testInaccessiblePermittedType3(Path base) throws Exception { + doTest(base, + new String[0], + """ + class Lib { + sealed interface Base {} + record NoOp() implements Base {} + private record Inaccessible() implements Base {} + } + public class Test { + int t(Box b) { + return switch (b) { + case Box(Lib.NoOp _) -> 0; + //Box(Inaccessible) missing, but cannot be used here. + }; + } + record Box(Lib.Base base) {} + } + """, + "Test.Box(Lib.Base _)"); + } + + @Test + public void testInaccessiblePermittedType4(Path base) throws Exception { + doTest(base, + new String[0], + """ + class Lib { + sealed interface Base {} + record NoOp() implements Base {} + private sealed interface Intermediate1 extends Base {} + private sealed interface Intermediate2 extends Intermediate1 {} + record Rec() implements Intermediate2 {} + } + public class Test { + int t(Box b) { + return switch (b) { + case Box(Lib.NoOp _) -> 0; +// case Box(Lib.Rec _) -> 0; + }; + } + record Box(Lib.Base base) {} + } + """, + "Test.Box(Lib.Rec _)"); + } + + @Test + public void testInaccessiblePermittedType5(Path base) throws Exception { + doTest(base, + new String[0], + """ + class Lib { + sealed interface Base {} + record NoOp() implements Base {} + private sealed interface Intermediate1 extends Base {} + private sealed interface Intermediate2 extends Intermediate1 {} + sealed interface Intermediate3 extends Intermediate2 {} + private record Inaccessible() implements Intermediate3 {} + } + public class Test { + int t(Box b) { + return switch (b) { + case Box(Lib.NoOp _) -> 0; +// case Box(Lib.Intermediate3 _) -> 0; + }; + } + record Box(Lib.Base base) {} + } + """, + "Test.Box(Lib.Base _)"); + } + + @Test + public void testInaccessiblePermittedType6(Path base) throws Exception { + doTest(base, + new String[0], + """ + class Lib { + sealed interface Base {} + record NoOp() implements Base {} + sealed interface Intermediate extends Base {} + private record Leaf1() implements Intermediate {} + record Leaf2() implements Intermediate {} + } + public class Test { + int t(Lib.Base b) { + return switch (b) { + case Lib.NoOp _ -> 0; +// case Lib.Intermediate _ -> 0; + }; + } + } + """, + "Lib.Intermediate _"); + } + + @Test + public void testInaccessiblePermittedType7(Path base) throws Exception { + doTest(base, + new String[0], + """ + class Lib { + sealed interface Base {} + record NoOp() implements Base {} + sealed interface Intermediate extends Base {} + private record Leaf1() implements Intermediate {} + record Leaf2() implements Intermediate {} + } + public class Test { + int t(Lib.Base b) { + return switch (b) { + case Lib.NoOp _ -> 0; + case Lib.Leaf2 _ -> 0; +// cannot refer to Lib.Leaf1, must use Intermediate + }; + } + } + """, + "Lib.Intermediate _"); + } + + @Test + public void testInaccessiblePermittedType8(Path base) throws Exception { + //recursive + doTest(base, + new String[0], + """ + class Lib { + sealed interface Base {} + record NoOp() implements Base {} + private static class Wrapper { + public record Inaccessible() implements Base {} + } + } + public class Test { + int t(Lib.Base b) { + return switch (b) { + case Lib.NoOp _ -> 0; + //Inaccessible missing, but cannot be used here. + }; + } + } + """, + "Lib.Base _"); + } + + @Test + public void testInaccessiblePermittedType9(Path base) throws Exception { + //recursive + doTest(base, + new String[0], + """ + class Lib { + sealed interface Base {} + record NoOp() implements Base {} + private static class Wrapper { + public record Inaccessible() implements Base {} + } + record Box(Base base) {} + } + public class Test { + int t(Lib.Box b) { + return switch (b) { + case Lib.Box(Lib.NoOp _) -> 0; + //Box(Inaccessible) missing, but cannot be used here. + }; + } + } + """, + "Lib.Box(Lib.Base _)"); + } + + @Test + public void testInaccessiblePermittedType10(Path base) throws Exception { + doTest(base, + new String[0], + """ + class Lib { + sealed interface Base {} + record NoOp() implements Base {} + private static class Wrapper { + public sealed interface Intermediate1 extends Base {} + public sealed interface Intermediate2 extends Intermediate1 {} + } + record Rec() implements Wrapper.Intermediate2 {} + } + public class Test { + int t(Box b) { + return switch (b) { + case Box(Lib.NoOp _) -> 0; +// case Box(Lib.Rec _) -> 0; + }; + } + record Box(Lib.Base base) {} + } + """, + "Test.Box(Lib.Rec _)"); + } + + @Test + public void testInaccessiblePermittedType11(Path base) throws Exception { + doTest(base, + new String[0], + """ + class Lib { + sealed interface I permits A, B, X { } + public static final class A implements I { } + public static final class B implements I { } + private static final class X implements I { } + } + public class Test { + sealed interface Op permits NoOp, IOp {} + record NoOp() implements Op {} + record IOp(Lib.I i) implements Op {} + + private void t(Op op) { + switch (op) { + case NoOp() -> {} + case IOp(Lib.A a) -> {} + case IOp(Lib.B b) -> {} +// //IOp(X) missing, but cannot be used here + } + } + } + """, + "Test.IOp(Lib.I _)"); + } + + @Test + public void testInaccessiblePermittedType12(Path base) throws Exception { + doTest(base, + new String[0], + """ + class Lib { + sealed interface Base {} + record NoOp() implements Base {} + private sealed interface Intermediate1 extends Base {} + private sealed interface Intermediate2 extends Intermediate1 {} + record Rec1() implements Intermediate2 {} + record Rec2() implements Intermediate2 {} + } + public class Test { + int t(Lib.Base b) { + return switch (b) { + case Lib.NoOp _ -> 0; +// case Lib.Rec1 _ -> 0; +// case Lib.Rec2 _ -> 0; + }; + } + } + """, + "Lib.Rec1 _", "Lib.Rec2 _"); + } + + @Test + public void testNonAbstract(Path base) throws Exception { + doTest(base, + new String[0], + """ + public class Test { + sealed class Sealed {} + final class Impl extends Sealed {} + record Rec(Sealed s) {} + + int t(Rec r) { + return switch (r) { + case Rec(Impl _) -> 0; + }; + } + } + """, + "Test.Rec(Test.Sealed _)"); + } + + @Test + public void testInaccessiblePermittedTypeCrossPackage(Path base) throws Exception { + doTest(base, + new String[] { + """ + package lib; + public class Lib { + public sealed interface Base {} + public record NoOp() implements Base {} + record Inaccessible() implements Base {} + } + """ + }, + """ + package test; + import lib.Lib; + public class Test { + int t(Lib.Base b) { + return switch (b) { + case Lib.NoOp _ -> 0; + //Inaccessible missing, but cannot be used here. + }; + } + } + """, + "lib.Lib.Base _"); + } + + @Test + public void testInaccessiblePermittedTypeReducedByDominance(Path base) throws Exception { + doTest(base, + new String[] { + """ + package lib; + public class Lib { + public sealed interface Base {} + public record NoOp() implements Base {} + record Inaccessible() implements Base {} + public record Accessible() implements Base {} + } + """ + }, + """ + package test; + import lib.Lib; + public class Test { + int t(Lib.Base b) { + return switch (b) { + case Lib.NoOp _ -> 0; + //Inaccessible and Accessible missing, but cannot be used here. + }; + } + } + """, + "lib.Lib.Base _"); + } + + @Test + public void testMissingFromMultipleHierarchiesAtTopLevel(Path base) throws Exception { + doTest(base, + new String[0], + """ + public class Test { + sealed interface Sealed {} + sealed interface A extends Sealed {} + sealed interface B extends Sealed {} + sealed interface C extends Sealed {} + record A1() implements A {} + record A2() implements A {} + record B1() implements B {} + record B2() implements B {} + record C1() implements C {} + record C2() implements C {} + + int t(Sealed s) { + return switch (s) { + case A1 _ -> 0; + case B1 _ -> 0; + case C1 _ -> 0; + //all of A2, B2 and C2 as missing + }; + } + } + """, + "Test.B2 _", "Test.C2 _", "Test.A2 _"); + doTest(base, + new String[0], + """ + public class Test { + sealed interface Sealed {} + sealed interface A extends Sealed {} + sealed interface B extends Sealed {} + sealed interface C extends Sealed {} + record A1() implements A {} + record A2() implements A {} + record B1() implements B {} + record B2() implements B {} + record C1() implements C {} + record C2() implements C {} + + int t(Sealed s) { + return switch (s) { + case A1 _ -> 0; + case B1 _ -> 0; + //all of A2, B2, C1 and C2 as missing + }; + } + } + """, + "Test.B2 _", "Test.C _", "Test.A2 _"); + } + + @Test + public void testInaccessiblePermittedTypeDiamondSelectorSubtype(Path base) throws Exception { + //diamond hierarchy, pick the accessible type that is the closest to the inaccessible type: + doTest(base, + new String[0], + """ + class Lib { + sealed interface I permits P1, P2, Other { } + sealed interface P1 extends I {} + private sealed interface P1Inaccessible1 extends P1 {} + private sealed interface P1Inaccessible2 extends P1Inaccessible1 {} + private sealed interface P1Inaccessible3 extends P1Inaccessible2 {} + sealed interface P2 extends I {} + private sealed interface P2Inaccessible1 extends P2 {} + private static final class P12Common implements P1Inaccessible3, P2Inaccessible1 {} + public static final class Other implements I { } + } + public class Test { + private void t(Lib.I i) { + switch (i) { + case Lib.Other _ -> {} +// //Lib.P12Common missing, but cannot be used here + } + } + } + """, + "Lib.P2 _"); + doTest(base, + new String[0], + """ + class Lib { + sealed interface I permits P1, P2, Other { } + sealed interface P1 extends I {} + private sealed interface P1Inaccessible1 extends P1 {} + private sealed interface P1Inaccessible2 extends P1Inaccessible1 {} + private sealed interface P1Inaccessible3 extends P1Inaccessible2 {} + sealed interface P2 extends I {} + private sealed interface P2Inaccessible1 extends P2 {} + private static final class P12Common implements P2Inaccessible1, P1Inaccessible1 {} + public static final class Other implements I { } + } + public class Test { + private void t(Lib.I i) { + switch (i) { + case Lib.Other _ -> {} +// //Lib.P12Common missing, but cannot be used here + } + } + } + """, + "Lib.P2 _"); + } + + @Test + public void testInaccessiblePermittedTypeDiamondOutsideSelectorSubtype(Path base) throws Exception { + //diamond hierarchy, pick the accessible type that is the closest to the inaccessible type: + // Baseline: K is inaccessible; J is unrelated to I + doTest(base, + new String[0], + """ + class Lib { + sealed interface I {} + interface J {} + private sealed interface K extends I {} + private static final class C implements K, J {} + static final class Unrelated implements I {} + } + public class Test { + public void test(Lib.I i) { + switch (i) { + case Lib.Unrelated _ -> {} + } + } + } + """, + "Lib.I _"); + // Diff from previous: K is now accessible. + doTest(base, + new String[0], + """ + class Lib { + sealed interface I {} + interface J {} + sealed interface K extends I {} + private static final class C implements K, J {} + static final class Unrelated implements I {} + } + public class Test { + public void test(Lib.I i) { + switch (i) { + case Lib.Unrelated _ -> {} + } + } + } + """, + "Lib.K _"); + // Diff from previous: J now extends I, making J and K sibling subinterfaces of I. + doTest(base, + new String[0], + """ + class Lib { + sealed interface I {} + non-sealed interface J extends I {} + sealed interface K extends I {} + private static final class C implements J, K {} + static final class Unrelated implements I {} + } + public class Test { + public void test(Lib.I i) { + switch (i) { + case Lib.Unrelated _ -> {} + } + } + } + """, + "Lib.J _"); + // Diff from previous: J is sealed and K is non-sealed. + doTest(base, + new String[0], + """ + class Lib { + sealed interface I {} + sealed interface J extends I {} + non-sealed interface K extends I {} + private static final class C implements J, K {} + static final class Unrelated implements I {} + } + public class Test { + public void test(Lib.I i) { + switch (i) { + case Lib.Unrelated _ -> {} + } + } + } + """, + "Lib.J _"); + } + + @Test + public void testTypeVariables(Path base) throws Exception { + doTest(base, + new String[0], + """ + class Test { + sealed interface I permits A, B, C {} + static final class A implements I {} + static final class B implements I {} + static final class C implements I {} + record Box(I i, T t) {} + + static int f(Box b) { + return switch (b) { + case Box(A _, T _) -> 0; + }; + } + } + """, + "Test.Box(Test.B _,T _)", + "Test.Box(Test.C _,T _)"); + } + + @Test + public void testPlularity(Path base) throws Exception { + doExactTest(base, + """ + class Test { + sealed interface I permits A, B {} + static final class A implements I {} + static final class B implements I {} + record Box(I i) {} + + static int f(Box b) { + return switch (b) { + case Box(A _) -> 0; + }; + } + } + """, + "Test.java:8:16: compiler.err.not.exhaustive.details: (compiler.misc.missing.case,{(compiler.misc.record.pattern: Test.Box, (compiler.misc.binding.pattern: Test.B))})", + "1 error"); + doExactTest(base, + """ + class Test { + sealed interface I permits A, B, C {} + static final class A implements I {} + static final class B implements I {} + static final class C implements I {} + record Box(I i) {} + + static int f(Box b) { + return switch (b) { + case Box(A _) -> 0; + }; + } + } + """, + "Test.java:9:16: compiler.err.not.exhaustive.details: (compiler.misc.missing.cases,{(compiler.misc.record.pattern: Test.Box, (compiler.misc.binding.pattern: Test.B)),(compiler.misc.record.pattern: Test.Box, (compiler.misc.binding.pattern: Test.C))})", + "1 error"); + } + private void doTest(Path base, String[] libraryCode, String testCode, String... expectedMissingPatterns) throws IOException { Path current = base.resolve("."); Path libClasses = current.resolve("libClasses"); @@ -565,12 +1199,15 @@ private void doTest(Path base, String[] libraryCode, String testCode, String... "-XDexhaustivityMaxBaseChecks=" + Long.MAX_VALUE) //never give up .outdir(classes) .files(tb.findJavaFiles(src)) - .diagnosticListener(d -> { + .diagnosticListener((Diagnostic d) -> { if ("compiler.err.not.exhaustive.details".equals(d.getCode()) || "compiler.err.not.exhaustive.statement.details".equals(d.getCode())) { if (d instanceof DiagnosticSourceUnwrapper uw) { d = uw.d; } + if (d instanceof JCDiagnostic diag) { + d = (Diagnostic) diag.getArgs()[0]; + } if (d instanceof JCDiagnostic.MultilineDiagnostic diag) { diag.getSubdiagnostics() .stream() @@ -590,4 +1227,27 @@ private void doTest(Path base, String[] libraryCode, String testCode, String... } } + private void doExactTest(Path base, String testCode, String... expectedErrors) throws IOException { + Path current = base.resolve("."); + Path src = current.resolve("src"); + tb.writeJavaFiles(src, testCode); + + Path classes = current.resolve("classes"); + + Files.createDirectories(classes); + + List log = new JavacTask(tb) + .options("-XDrawDiagnostics", + "-XDshould-stop.at=FLOW", + "-XDshould-stop.ifNoError=FLOW", + "-XDexhaustivityMaxBaseChecks=" + Long.MAX_VALUE) //never give up + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + tb.checkEqual(List.of(expectedErrors), log); + } + } diff --git a/test/langtools/tools/javac/preview/PreviewLint.java b/test/langtools/tools/javac/preview/PreviewLint.java new file mode 100644 index 000000000000..6955ad6cb806 --- /dev/null +++ b/test/langtools/tools/javac/preview/PreviewLint.java @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2026, 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 8388373 + * @summary Verify -Xlint works as expected in relation to --enable-preview. + * @library /tools/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask + * @run main PreviewLint + */ +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.TestRunner; +import toolbox.ToolBox; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +public class PreviewLint extends TestRunner { + + protected ToolBox tb; + + PreviewLint() { + super(System.err); + tb = new ToolBox(); + } + + public static void main(String... args) throws Exception { + PreviewLint t = new PreviewLint(); + t.runTests(); + } + + protected void runTests() throws Exception { + runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + @Test + public void previewAPI(Path base) throws Exception { + Path apiSrc = base.resolve("api-src"); + tb.writeJavaFiles(apiSrc, + """ + package preview.api; + @jdk.internal.javac.PreviewFeature(feature=jdk.internal.javac.PreviewFeature.Feature.TEST) + public class Preview { + } + """, + """ + package preview.api; + @jdk.internal.javac.PreviewFeature(feature=jdk.internal.javac.PreviewFeature.Feature.TEST, reflective=true) + public class ReflectivePreview { + } + """); + Path apiClasses = base.resolve("api-classes"); + + new JavacTask(tb, Task.Mode.CMDLINE) + .outdir(apiClasses) + .options("-XDrawDiagnostics", + "--patch-module", "java.base=" + apiSrc.toString(), + "-Werror") + .files(tb.findJavaFiles(apiSrc)) + .run() + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + Path testSrc = base.resolve("test-src"); + tb.writeJavaFiles(testSrc, + """ + package test; + import preview.api.Preview; + import preview.api.ReflectivePreview; + public class UseClass { + Preview f1; + ReflectivePreview f2; + } + """); + Path testClasses = base.resolve("test-classes"); + List log; + List expected; + + log = new JavacTask(tb, Task.Mode.CMDLINE) + .outdir(testClasses) + .options("--patch-module", "java.base=" + apiClasses.toString(), + "--add-exports", "java.base/preview.api=ALL-UNNAMED", + "-XDrawDiagnostics") + .files(tb.findJavaFiles(testSrc)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + expected = List.of( + "UseClass.java:2:19: compiler.err.is.preview: preview.api.Preview", + "UseClass.java:5:5: compiler.err.is.preview: preview.api.Preview", + "UseClass.java:6:5: compiler.warn.is.preview.reflective: preview.api.ReflectivePreview", + "2 errors", + "1 warning"); + + tb.checkEqual(expected, log); + + log = new JavacTask(tb, Task.Mode.CMDLINE) + .outdir(testClasses) + .options("--patch-module", "java.base=" + apiClasses.toString(), + "--add-exports", "java.base/preview.api=ALL-UNNAMED", + "-Xlint", + "-XDrawDiagnostics") + .files(tb.findJavaFiles(testSrc)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + expected = List.of( + "UseClass.java:2:19: compiler.err.is.preview: preview.api.Preview", + "UseClass.java:5:5: compiler.err.is.preview: preview.api.Preview", + "UseClass.java:6:5: compiler.warn.is.preview.reflective: preview.api.ReflectivePreview", + "2 errors", + "1 warning"); + + tb.checkEqual(expected, log); + + log = new JavacTask(tb, Task.Mode.CMDLINE) + .outdir(testClasses) + .options("--patch-module", "java.base=" + apiClasses.toString(), + "--add-exports", "java.base/preview.api=ALL-UNNAMED", + "--enable-preview", "--source", System.getProperty("java.specification.version"), + "-XDrawDiagnostics") + .files(tb.findJavaFiles(testSrc)) + .run(Task.Expect.SUCCESS) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + expected = List.of( + "- compiler.note.preview.filename: UseClass.java, DEFAULT", + "- compiler.note.preview.recompile"); + + tb.checkEqual(expected, log); + + log = new JavacTask(tb, Task.Mode.CMDLINE) + .outdir(testClasses) + .options("--patch-module", "java.base=" + apiClasses.toString(), + "--add-exports", "java.base/preview.api=ALL-UNNAMED", + "--enable-preview", "--source", System.getProperty("java.specification.version"), + "-Xlint", + "-XDrawDiagnostics") + .files(tb.findJavaFiles(testSrc)) + .run(Task.Expect.SUCCESS) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + expected = List.of( + "- compiler.note.preview.filename: UseClass.java, DEFAULT", + "- compiler.note.preview.recompile"); + + tb.checkEqual(expected, log); + + log = new JavacTask(tb, Task.Mode.CMDLINE) + .outdir(testClasses) + .options("--patch-module", "java.base=" + apiClasses.toString(), + "--add-exports", "java.base/preview.api=ALL-UNNAMED", + "--enable-preview", "--source", System.getProperty("java.specification.version"), + "-Xlint:preview", + "-XDrawDiagnostics") + .files(tb.findJavaFiles(testSrc)) + .run(Task.Expect.SUCCESS) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + expected = List.of( + "UseClass.java:5:5: compiler.warn.is.preview: preview.api.Preview", + "UseClass.java:6:5: compiler.warn.is.preview.reflective: preview.api.ReflectivePreview", + "2 warnings"); + + tb.checkEqual(expected, log); + + log = new JavacTask(tb, Task.Mode.CMDLINE) + .outdir(testClasses) + .options("--patch-module", "java.base=" + apiClasses.toString(), + "--add-exports", "java.base/preview.api=ALL-UNNAMED", + "--enable-preview", "--source", System.getProperty("java.specification.version"), + "-Xlint:all", + "-XDrawDiagnostics") + .files(tb.findJavaFiles(testSrc)) + .run(Task.Expect.SUCCESS) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + expected = List.of( + "UseClass.java:5:5: compiler.warn.is.preview: preview.api.Preview", + "UseClass.java:6:5: compiler.warn.is.preview.reflective: preview.api.ReflectivePreview", + "2 warnings"); + + tb.checkEqual(expected, log); + + //combine -Xlint and -Xlint:all + log = new JavacTask(tb, Task.Mode.CMDLINE) + .outdir(testClasses) + .options("--patch-module", "java.base=" + apiClasses.toString(), + "--add-exports", "java.base/preview.api=ALL-UNNAMED", + "--enable-preview", "--source", System.getProperty("java.specification.version"), + "-Xlint:all", "-Xlint", + "-XDrawDiagnostics") + .files(tb.findJavaFiles(testSrc)) + .run(Task.Expect.SUCCESS) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + expected = List.of( + "UseClass.java:5:5: compiler.warn.is.preview: preview.api.Preview", + "UseClass.java:6:5: compiler.warn.is.preview.reflective: preview.api.ReflectivePreview", + "2 warnings"); + + tb.checkEqual(expected, log); + + log = new JavacTask(tb, Task.Mode.CMDLINE) + .outdir(testClasses) + .options("--patch-module", "java.base=" + apiClasses.toString(), + "--add-exports", "java.base/preview.api=ALL-UNNAMED", + "--enable-preview", "--source", System.getProperty("java.specification.version"), + "-Xlint", "-Xlint:all", + "-XDrawDiagnostics") + .files(tb.findJavaFiles(testSrc)) + .run(Task.Expect.SUCCESS) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + expected = List.of( + "UseClass.java:5:5: compiler.warn.is.preview: preview.api.Preview", + "UseClass.java:6:5: compiler.warn.is.preview.reflective: preview.api.ReflectivePreview", + "2 warnings"); + + tb.checkEqual(expected, log); + } + +} diff --git a/test/lib/jdk/test/lib/hprof/model/Snapshot.java b/test/lib/jdk/test/lib/hprof/model/Snapshot.java index dbb9c7fd1f3e..1eb2edab5a37 100644 --- a/test/lib/jdk/test/lib/hprof/model/Snapshot.java +++ b/test/lib/jdk/test/lib/hprof/model/Snapshot.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -593,13 +593,17 @@ private Number makeId(long id) { private void putInClassesMap(JavaClass c) { String name = c.getName(); - if (classes.containsKey(name)) { + JavaClass originClass = classes.get(name); + if (originClass != null) { + if (originClass.getId() == c.getId()) { + throw new IllegalStateException(String.format("%s (id=0x%x) already exists", c.getName(), c.getId())); + } // more than one class can have the same name // if so, create a unique name by appending // - and id string to it. name += "-" + c.getIdString(); } - classes.put(c.getName(), c); + classes.put(name, c); } private void addFakeClass(JavaClass c) { diff --git a/test/lib/jdk/test/lib/process/OutputAnalyzer.java b/test/lib/jdk/test/lib/process/OutputAnalyzer.java index 0a9c31ed4034..425708fb2645 100644 --- a/test/lib/jdk/test/lib/process/OutputAnalyzer.java +++ b/test/lib/jdk/test/lib/process/OutputAnalyzer.java @@ -41,7 +41,7 @@ public final class OutputAnalyzer { private static final String jvmwarningmsg = ".* VM warning:.*"; private static final String VM_DEPRECATED_MSG = ".* VM warning:.* deprecated.*"; - private static final String OTHER_DEPRECATED_MSG = "^WARNING: .* is deprecated.*"; + private static final String OTHER_DEPRECATED_MSG = "(?m)^WARNING: .* is deprecated.*"; private static final String FATAL_ERROR_PAT = "# A fatal error has been detected.*"; diff --git a/test/lib/jdk/test/lib/process/ProcessTools.java b/test/lib/jdk/test/lib/process/ProcessTools.java index e7dd20c62869..e7f43e458790 100644 --- a/test/lib/jdk/test/lib/process/ProcessTools.java +++ b/test/lib/jdk/test/lib/process/ProcessTools.java @@ -392,7 +392,9 @@ private static List addTestThreadFactoryArgs(String testThreadFactoryNam final List doubleWordArgs = List.of( "--add-opens", "--upgrade-module-path", "--add-modules", "--add-exports", "--enable-native-access", - "--limit-modules", "--add-reads", "--patch-module", "--module-path", "-p"); + "--limit-modules", "--add-reads", "--patch-module", "--module-path", "-p", + "--enable-final-field-mutation", "--illegal-native-access", "--illegal-final-field-mutation", + "--sun-misc-unsafe-memory-access", "--finalization"); ArrayList args = new ArrayList<>(); diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 88acdc10d548..23b12e73985e 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -223,7 +223,7 @@ public String printMethods(String classNamePattern, String methodPattern } public native int getMarkWordOffset(); - public native long getInlineTypePattern(); + public native long getValueTypePattern(); public native long getNullFreeArrayBitInPlace(); public native long getFlatArrayBitInPlace(); diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/AllocFromSliceTest.java b/test/micro/org/openjdk/bench/java/lang/foreign/AllocFromSliceTest.java index c650be88f464..014ee4394fa8 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/AllocFromSliceTest.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/AllocFromSliceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, 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 @@ -76,4 +76,7 @@ public MemorySegment alloc_confined_slice() { return arena.allocateFrom(C_CHAR, MemorySegment.ofArray(arr), C_CHAR, start, size); } } + + @Fork(value = 3, jvmArgsAppend = "-Djmh.executor=VIRTUAL") + public static class OfVirtual extends AllocFromSliceTest {} } diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/AllocFromTest.java b/test/micro/org/openjdk/bench/java/lang/foreign/AllocFromTest.java index b627c4de0895..647c1cfadd4f 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/AllocFromTest.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/AllocFromTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, 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 @@ -73,6 +73,13 @@ public MemorySegment alloc_confined() { } } + // Save `jvmArgsAppend` for `OfVirtual` + @Fork(jvmArgs = {"--enable-native-access=ALL-UNNAMED", "--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED", "-Djdk.internal.foreign.native.confined.pool.power.size=-1"}) + @Benchmark + public MemorySegment alloc_confined_no_pool() { + return alloc_confined(); + } + @Benchmark public MemorySegment alloc_malloc_arena() { try (MallocArena arena = new MallocArena()) { @@ -94,6 +101,9 @@ public MemorySegment alloc_pool_arena() { } } + @Fork(value = 3, jvmArgsAppend = "-Djmh.executor=VIRTUAL") + public static class OfVirtual extends AllocFromTest {} + static class SlicingPool { final MemorySegment pool = Arena.ofAuto().allocate(1024); boolean isAcquired = false; diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/AllocTest.java b/test/micro/org/openjdk/bench/java/lang/foreign/AllocTest.java index 1ee6aecbbd39..b79704ebc86d 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/AllocTest.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/AllocTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, 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,6 +60,13 @@ public long alloc_confined() { } } + // Save `jvmArgsAppend` for `OfVirtual` + @Fork(jvmArgs = {"--enable-native-access=ALL-UNNAMED", "--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED", "-Djdk.internal.foreign.native.confined.pool.power.size=-1"}) + @Benchmark + public long alloc_confined_no_pool() { + return alloc_confined(); + } + @Benchmark public long alloc_calloc_arena() { try (CallocArena arena = new CallocArena()) { @@ -74,6 +81,9 @@ public long alloc_unsafe_arena() { } } + @Fork(value = 3, jvmArgsAppend = "-Djmh.executor=VIRTUAL") + public static class OfVirtual extends AllocTest {} + private static class CallocArena implements Arena { static final MethodHandle CALLOC = Linker.nativeLinker() diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/NestedArenasAllocTest.java b/test/micro/org/openjdk/bench/java/lang/foreign/NestedArenasAllocTest.java new file mode 100644 index 000000000000..050f0f6406df --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/foreign/NestedArenasAllocTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2026, 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.foreign; + +import org.openjdk.jmh.annotations.*; + +import java.lang.foreign.*; +import java.lang.foreign.MemorySegment.Scope; +import java.lang.invoke.MethodHandle; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@State(org.openjdk.jmh.annotations.Scope.Thread) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(value = 3, jvmArgs = {"--enable-native-access=ALL-UNNAMED"}) +public class NestedArenasAllocTest { + + @Benchmark + public long alloc_confined_nested() { + return allocateNested(); + } + + @Benchmark + // Reserve jvmArgsAppend for OfVirtual; method-level append arguments take + // precedence over the append arguments declared by a subclass. Method-level + // jvmArgs replaces class-level jvmArgs, so repeat the required access options. + @Fork(jvmArgs = { + "--enable-native-access=ALL-UNNAMED", + "-Djdk.internal.foreign.native.confined.pool.power.size=-1" + }) + public long alloc_confined_nested_no_pool() { + return allocateNested(); + } + + private static long allocateNested() { + // Four nested and cached arenas and one overflow + try (Arena a0 = Arena.ofConfined(); + Arena a1 = Arena.ofConfined(); + Arena a2 = Arena.ofConfined(); + Arena a3 = Arena.ofConfined(); + Arena a4 = Arena.ofConfined();) { + return allocateFour(a0) + + allocateFour(a1) + + allocateFour(a2) + + allocateFour(a3) + + allocateFour(a4); + } + } + + private static long allocateFour(Arena arena) { + return arena.allocate(ValueLayout.JAVA_LONG).address() + + arena.allocate(ValueLayout.JAVA_LONG).address() + + arena.allocate(ValueLayout.JAVA_LONG).address() + + arena.allocate(ValueLayout.JAVA_LONG).address(); + } + + @Fork(value = 3, jvmArgsAppend = "-Djmh.executor=VIRTUAL") + public static class OfVirtual extends NestedArenasAllocTest {} +} diff --git a/test/micro/org/openjdk/bench/jdk/incubator/json/Parse.java b/test/micro/org/openjdk/bench/jdk/incubator/json/Parse.java new file mode 100644 index 000000000000..2c5c91e05214 --- /dev/null +++ b/test/micro/org/openjdk/bench/jdk/incubator/json/Parse.java @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2025, 2026, 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.jdk.incubator.json; + +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 org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import jdk.incubator.json.Json; +import jdk.incubator.json.JsonValue; + +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(value = 3, jvmArgs = {"--add-modules=jdk.incubator.json"}) +@State(Scope.Benchmark) +public class Parse { + + public String json; + + @Setup + public void setup() throws IOException { + json = createJson(); + } + + @Benchmark + public JsonValue parse() { + return Json.parse(json); + } + + public static void main(String... args) throws Exception { + Options opts = new OptionsBuilder().include(Parse.class.getSimpleName()).shouldDoGC(true).build(); + new Runner(opts).run(); + } + + private static String createJson() { + return """ + { + "expand": "renderedFields,names,schema,operations,editmeta,changelog,versionedRepresentations", + "id": "5143806", + "self": "https://bugs.openjdk.org/rest/api/2/issue/5143806", + "key": "JDK-8344154", + "fields": { + "issuetype": { + "self": "https://bugs.openjdk.org/rest/api/2/issuetype/9", + "id": "9", + "description": "Java Enhancement Proposal", + "iconUrl": "https://bugs.openjdk.org/secure/viewavatar?size=xsmall&avatarId=14711&avatarType=issuetype", + "name": "JEP", + "subtask": false, + "avatarId": 14711 + }, + "timespent": null, + "project": { + "self": "https://bugs.openjdk.org/rest/api/2/project/10100", + "id": "10100", + "key": "JDK", + "name": "JDK", + "projectTypeKey": "software", + "avatarUrls": { + "48x48": "https://bugs.openjdk.org/secure/projectavatar?pid=10100&avatarId=10301", + "24x24": "https://bugs.openjdk.org/secure/projectavatar?size=small&pid=10100&avatarId=10301", + "16x16": "https://bugs.openjdk.org/secure/projectavatar?size=xsmall&pid=10100&avatarId=10301", + "32x32": "https://bugs.openjdk.org/secure/projectavatar?size=medium&pid=10100&avatarId=10301" + }, + "projectCategory": { + "self": "https://bugs.openjdk.org/rest/api/2/projectCategory/10100", + "id": "10100", + "description": "Open JDK Projects", + "name": "Open JDK Projects" + } + }, + "customfield_11000": null, + "fixVersions": [], + "customfield_11001": null, + "aggregatetimespent": null, + "resolution": null, + "customfield_11004": "9223372036854775807", + "customfield_11005": null, + "customfield_10700": "Naoto Sato, Paul Sandoz, Justin Lu, Stuart Marks", + "customfield_10701": "540", + "customfield_10702": { + "self": "https://bugs.openjdk.org/rest/api/2/customFieldOption/19103", + "value": "Feature", + "id": "19103", + "disabled": false + }, + "customfield_10901": "core dash libs dash dev at openjdk dot org", + "customfield_10703": { + "self": "https://bugs.openjdk.org/rest/api/2/customFieldOption/19104", + "value": "Open", + "id": "19104", + "disabled": false + }, + "customfield_10704": { + "self": "https://bugs.openjdk.org/rest/api/2/customFieldOption/19107", + "value": "JDK", + "id": "19107", + "disabled": false + }, + "resolutiondate": null, + "customfield_10705": null, + "workratio": -1, + "customfield_10709": { + "self": "https://bugs.openjdk.org/rest/api/2/customFieldOption/19111", + "value": "M", + "id": "19111", + "disabled": false + }, + "lastViewed": null, + "watches": { + "self": "https://bugs.openjdk.org/rest/api/2/issue/JDK-8344154/watchers", + "watchCount": 17, + "isWatching": false + }, + "created": "2024-11-13T23:54:45.000+0000", + "customfield_12000": null, + "customfield_12002": null, + "customfield_12001": null, + "priority": { + "self": "https://bugs.openjdk.org/rest/api/2/priority/2", + "iconUrl": "https://bugs.openjdk.org/images/jbsImages/p2.png", + "name": "P2", + "id": "2" + }, + "customfield_12004": null, + "customfield_12003": null, + "labels": [], + "customfield_11700": "{}", + "customfield_11900": null, + "timeestimate": null, + "aggregatetimeoriginalestimate": null, + "issuelinks": [ + { + "id": "4480253", + "self": "https://bugs.openjdk.org/rest/api/2/issueLink/4480253", + "outwardIssue": { + "id": "5187950", + "key": "JDK-8381976", + "self": "https://bugs.openjdk.org/rest/api/2/issue/5187950", + "fields": { + "summary": "Implementation for Simple JSON API", + "status": { + "self": "https://bugs.openjdk.org/rest/api/2/status/1", + "description": "The issue is open and ready for the assignee to start work on it.", + "iconUrl": "https://bugs.openjdk.org/images/icons/statuses/open.png", + "name": "Open", + "id": "1", + "statusCategory": { + "self": "https://bugs.openjdk.org/rest/api/2/statuscategory/2", + "id": 2, + "key": "new", + "colorName": "default", + "name": "To Do" + } + }, + "priority": { + "self": "https://bugs.openjdk.org/rest/api/2/priority/2", + "iconUrl": "https://bugs.openjdk.org/images/jbsImages/p2.png", + "name": "P2", + "id": "2" + }, + "issuetype": { + "self": "https://bugs.openjdk.org/rest/api/2/issuetype/7", + "id": "7", + "description": "", + "iconUrl": "https://bugs.openjdk.org/secure/viewavatar?size=xsmall&avatarId=14707&avatarType=issuetype", + "name": "Enhancement", + "subtask": false, + "avatarId": 14707 + } + } + }, + "type": { + "id": "10003", + "name": "Relates", + "inward": "relates to", + "outward": "relates to", + "self": "https://bugs.openjdk.org/rest/api/2/issueLinkType/10003" + } + } + ], + "assignee": { + "self": "https://bugs.openjdk.org/rest/api/2/user?username=naoto", + "name": "naoto", + "key": "naoto", + "avatarUrls": { + "48x48": "https://bugs.openjdk.org/secure/useravatar?ownerId=naoto&avatarId=17312", + "24x24": "https://bugs.openjdk.org/secure/useravatar?size=small&ownerId=naoto&avatarId=17312", + "16x16": "https://bugs.openjdk.org/secure/useravatar?size=xsmall&ownerId=naoto&avatarId=17312", + "32x32": "https://bugs.openjdk.org/secure/useravatar?size=medium&ownerId=naoto&avatarId=17312" + }, + "displayName": "Naoto Sato", + "active": true, + "timeZone": "America/Los_Angeles" + }, + "updated": "2026-07-28T17:45:37.627+0000", + "status": { + "self": "https://bugs.openjdk.org/rest/api/2/status/10003", + "description": "", + "iconUrl": "https://bugs.openjdk.org/images/icons/statuses/generic.png", + "name": "Candidate", + "id": "10003", + "statusCategory": { + "self": "https://bugs.openjdk.org/rest/api/2/statuscategory/4", + "id": 4, + "key": "indeterminate", + "colorName": "inprogress", + "name": "In Progress" + } + }, + "components": [ + { + "self": "https://bugs.openjdk.org/rest/api/2/component/10300", + "id": "10300", + "name": "core-libs" + } + ], + "timeoriginalestimate": null, + "description": "\\u003C!--- DO NOT EDIT IN JIRA. SEE COMMENTS. --\\u003E\\r\\n\\r\\nSummary\\r\\n-------\\r\\n\\r\\nDefine a simple, standard API for parsing and generating JSON documents\\r\\nso that doing so does not require an external library. Enable many JSON\\r\\nprocessing tasks to be accomplished with little coding. This is an\\r\\n[incubating API](https://openjdk.org/jeps/11).\\r\\n\\r\\n\\r\\nHistory\\r\\n-------\\r\\n\\r\\nThis JEP supersedes [JEP 198](https://openjdk.org/jeps/198),\\r\\n_Light-Weight JSON API_, which was written in 2014. Circumstances have\\r\\nchanged in the intervening years, so here we take a different approach.\\r\\n\\r\\n\\r\\n## Goals\\r\\n\\r\\n- Provide a standard means in the Java Platform to process\\r\\n [RFC 8259] compliant JSON documents with low ceremony.\\r\\n\\r\\n[RFC 8259]: https://www.rfc-editor.org/info/rfc8259/\\r\\n\\r\\n- Keep the API small, simple, and easy to learn. Provide only those data\\r\\n types and operations required for strict conformance to RFC 8259,\\r\\n in order to facilitate machine-to-machine communication. Avoid\\r\\n features such as multiple parsing configurations, syntax extensions,\\r\\n data binding, and streaming.\\r\\n\\r\\n- Ensure that code that navigates and extracts data from JSON documents\\r\\n with a known structure is simple and readable. Because JSON documents\\r\\n do not have schemas, such code serves as a _de facto_ schema and\\r\\n should be readable as such.\\r\\n\\r\\n- Enable easy and quick exploration of unfamiliar JSON documents. We\\r\\n often interact with JSON documents in an exploratory manner, writing\\r\\n code not using a specification but instead trying it out against\\r\\n example documents. The API should provide methods that fail fast with\\r\\n clear error messages, enabling quick exploration.\\r\\n\\r\\n- Ensure that missing or unexpected values can be handled in a resilient\\r\\n fashion, since JSON document structures can evolve over time.\\r\\n\\r\\n- Make the JDK itself capable of parsing and generating JSON documents.\\r\\n\\r\\n\\r\\n## Non-Goals\\r\\n\\r\\n- It is not a goal to create an API that supplants established external\\r\\n JSON libraries.\\r\\n\\r\\n\\r\\n## Motivation\\r\\n\\r\\nJSON is ubiquitous in modern computing. The Java ecosystem contains a\\r\\nwide range of established JSON libraries:\\r\\n[Jackson](https://github.com/FasterXML/jackson),\\r\\n[Gson](https://google.github.io/gson/), Jakarta JSON\\r\\n[Processing](https://jakarta.ee/specifications/jsonp/2.1/) and\\r\\n[Binding](https://jakarta.ee/specifications/jsonb/3.0/),\\r\\n[Fastjson 2](https://github.com/alibaba/fastjson2), and more. Not\\r\\nonly do these libraries enable the parsing and generation of JSON\\r\\ndocuments, but they also support extended JSON syntaxes such as\\r\\n[JSON5](https://json5.org/) and include higher-level features such as\\r\\ndata binding, i.e., converting Java objects to and from JSON with a high\\r\\ndegree of customization, and event-based streaming.\\r\\n\\r\\nWe often, however, just need to perform simple tasks such as extracting\\r\\nsome data from a JSON document. The Python or Go code to accomplish such\\r\\ntasks is simple; the Java code should be equally simple.\\r\\n\\r\\nFor example, consider the task of computing the average of a set of\\r\\nforecast temperatures in a response from the [U.S. National Weather\\r\\nService REST API]. The response is a JSON document that looks like this:\\r\\n\\r\\n```\\r\\n{\\r\\n ...\\r\\n \\"properties\\": {\\r\\n ...\\r\\n \\"periods\\": [\\r\\n {\\r\\n \\"number\\": 1,\\r\\n \\"name\\": \\"Today\\",\\r\\n \\"startTime\\": \\"2026-04-22T06:00:00-04:00\\",\\r\\n \\"endTime\\": \\"2026-04-22T18:00:00-04:00\\",\\r\\n \\"isDaytime\\": true,\\r\\n \\"temperature\\": 54,\\r\\n \\"temperatureUnit\\": \\"F\\",\\r\\n ...\\r\\n },\\r\\n {\\r\\n \\"number\\": 2,\\r\\n \\"name\\": \\"Tonight\\",\\r\\n \\"startTime\\": \\"2026-04-22T18:00:00-04:00\\",\\r\\n \\"endTime\\": \\"2026-04-23T06:00:00-04:00\\",\\r\\n \\"isDaytime\\": false,\\r\\n \\"temperature\\": 48,\\r\\n \\"temperatureUnit\\": \\"F\\",\\r\\n ...\\r\\n },\\r\\n {\\r\\n \\"number\\": 3,\\r\\n \\"name\\": \\"Thursday\\",\\r\\n \\"startTime\\": \\"2026-04-23T06:00:00-04:00\\",\\r\\n \\"endTime\\": \\"2026-04-23T18:00:00-04:00\\",\\r\\n \\"isDaytime\\": true,\\r\\n \\"temperature\\": 68,\\r\\n \\"temperatureUnit\\": \\"F\\",\\r\\n ...\\r\\n },\\r\\n ...\\r\\n ]\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\nTo compute the average forecast temperature requires parsing the\\r\\ndocument, navigating to the location in the structure that contains the\\r\\nforecasts, and iterating over the array of forecasts while extracting\\r\\nthe temperature data. We should be able to tackle simple tasks like this\\r\\nwith simple Java code, without installing an external library and\\r\\nwithout suspecting that another language might make us more productive.\\r\\n\\r\\nA key goal driving the recent evolution of the Java Platform has been to\\r\\nenable simple tasks to be accomplished more easily and with less\\r\\nceremony. Features serving this goal include [convenience factory\\r\\nmethods for collections](https://openjdk.org/jeps/269), [`var`\\r\\ndeclarations](https://openjdk.org/jeps/286), [running programs from\\r\\nsource files](https://openjdk.org/jeps/330), and [compact source files\\r\\nand instance main methods](https://openjdk.org/jeps/512). A simple JSON\\r\\nAPI for parsing and generating JSON documents would also serve this\\r\\nimportant goal.\\r\\n\\r\\n\\r\\n### Using JSON in the JDK\\r\\n\\r\\nA standard JSON API in the Java Platform would also pave the way for\\r\\nfurther use of JSON in the Platform and by the JDK itself, since the JDK\\r\\ncannot have external dependencies. One potential use case is\\r\\nconfiguration files. The JDK uses the [property\\r\\nfile](https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/util/Properties.html)\\r\\nformat for various configuration files, such as [security properties\\r\\nfiles](https://docs.oracle.com/en/java/javase/26/security/security-properties-file.html).\\r\\nA weakness of this format is that it cannot express structured data. To\\r\\nrepresent an array in a property file, you must use clumsy workarounds\\r\\nsuch as sequentially numbered properties:\\r\\n\\r\\n```\\r\\nsecurity.provider.1=SUN\\r\\nsecurity.provider.2=SunRsaSign\\r\\nsecurity.provider.3=SunEC\\r\\n...\\r\\n```\\r\\n\\r\\nWith JSON built into the JDK, configuration files could represent arrays\\r\\nnaturally, using JSON arrays:\\r\\n\\r\\n```\\r\\n{\\r\\n \\"providers\\": [ \\"SUN\\", \\"SunRsaSign\\", \\"SunEC\\" ],\\r\\n ...\\r\\n}\\r\\n```\\r\\n\\r\\n\\r\\n## Description\\r\\n\\r\\nThe\\r\\n[`jdk.incubator.json`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/package-summary.html)\\r\\nAPI is organized around the\\r\\n[`JsonValue`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html)\\r\\ninterface, which represents a JSON value.\\r\\n\\r\\nThe JSON syntax has four kinds of primitives:\\r\\n\\r\\n 1. JSON strings, delimited with double quotes:\\r\\n\\r\\n ```\\r\\n \\"Hello\\"\\r\\n \\"My name is 'Bob'\\"\\r\\n \\"\\\\u006a\\\\u0061\\\\u0076\\\\u0061\\"\\r\\n ```\\r\\n\\r\\n 2. JSON numbers, represented in base 10 using decimal digits:\\r\\n\\r\\n ```\\r\\n 6 6.0 31.84 2.9E+5\\r\\n ```\\r\\n\\r\\n 3. JSON boolean literals: `true` and `false`\\r\\n\\r\\n 4. The JSON null literal: `null`\\r\\n\\r\\nand two kinds of structures:\\r\\n\\r\\n 5. JSON objects, delimited by `{` `}` and composed of comma-separated\\r\\n members. A member has a name, also called a key, and a value,\\r\\n separated by a colon:\\r\\n\\r\\n ```\\r\\n {\\r\\n \\"address\\" : \\"123 Smith Street\\",\\r\\n \\"value\\" : 31.84,\\r\\n \\"coordinates\\" : [ [ 37, 23, 41 ], [ -121, 57, 10 ] ]\\r\\n }\\r\\n ```\\r\\n\\r\\n 6. JSON arrays, delimited by `[` `]` and composed of comma-separated\\r\\n JSON values:\\r\\n\\r\\n ```\\r\\n [ 1, 2, 3, { \\"value\\": \\"4\\" }, [ 5, 6 ] ]\\r\\n ```\\r\\n\\r\\nThe `JsonValue` interface thus has six corresponding sub-interfaces:\\r\\n[`JsonString`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonString.html),\\r\\n[`JsonNumber`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonNumber.html),\\r\\n[`JsonBoolean`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonBoolean.html),\\r\\n[`JsonNull`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonNull.html),\\r\\n[`JsonObject`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonObject.html),\\r\\nand\\r\\n[`JsonArray`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonArray.html).\\r\\nEach interface declares operations appropriate to its corresponding JSON\\r\\nsyntactic element: Instances of the primitive sub-interfaces offer\\r\\nconversions to Java primitives and strings, `JsonObject` instances\\r\\nexpose members, and `JsonArray` instances expose array elements.\\r\\n\\r\\nThe `JsonValue` interface is [sealed](https://openjdk.org/jeps/409),\\r\\nwhich guarantees that any `JsonValue` instance is always one of this\\r\\nfixed set of subtypes and thus exhaustive `switch` expressions and\\r\\nstatements do not require a `default` clause.\\r\\n\\r\\nThe JSON API makes it easy to parse JSON documents that conform to\\r\\n[RFC 8259]. The\\r\\n[`parse`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/Json.html#parse(java.lang.String))\\r\\nmethod of the\\r\\n[`Json`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/Json.html)\\r\\nclass returns a tree of `JsonValue` instances that expose the names,\\r\\ntypes, and values of the parsed JSON data. Returning to the National\\r\\nWeather Service example, we can compute the average forecast temperature\\r\\nin just a few lines:\\r\\n\\r\\n```\\r\\nString body = ... REST response body, which is a JSON document ... ;\\r\\nJsonValue json = Json.parse(body);\\r\\njson.get(\\"properties\\").get(\\"periods\\").asList().stream()\\r\\n .mapToInt(j -\\u003E j.get(\\"temperature\\").asInt())\\r\\n .average()\\r\\n .ifPresent(IO::println);\\r\\n```\\r\\n\\r\\n(The complete example is shown in the [Appendix](#appendix).)\\r\\n\\r\\nThe API also makes it easy to generate JSON documents. For example, this\\r\\ncode:\\r\\n\\r\\n\\r\\n```\\r\\nIO.println(JsonObject.of(Map.of(\\"providers\\",\\r\\n JsonArray.of(List.of(JsonString.of(\\"SUN\\"),\\r\\n JsonString.of(\\"SunRsaSign\\"),\\r\\n JsonString.of(\\"SunEC\\"))))));\\r\\n```\\r\\n\\r\\nproduces the output:\\r\\n\\r\\n```\\r\\n{\\"providers\\":[\\"SUN\\",\\"SunRsaSign\\",\\"SunEC\\"]}\\r\\n```\\r\\n\\r\\n\\r\\n### Parsing and navigating JSON documents\\r\\n\\r\\nThe `Json` class can parse a JSON document contained in either a\\r\\n`String` or a `char` array. A JSON document might be a REST API response\\r\\nbody read from the network, a configuration file read from disk, or some\\r\\nother text payload produced by an application.\\r\\n\\r\\nParsing a JSON document requires a single call to one of the\\r\\n[`Json.parse`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/Json.html#parse(java.lang.String))\\r\\nmethods:\\r\\n\\r\\n```\\r\\nJsonValue root = Json.parse(doc);\\r\\n```\\r\\n\\r\\nParsing is strict: The document must conform to [RFC 8259]. Syntax\\r\\nextensions such as trailing commas and comments are not supported.\\r\\nAdditionally, documents must not have objects with duplicate member\\r\\nnames. This policy, permitted by the RFC, provides maximum\\r\\ninteroperability and predictability, and reduces concerns about\\r\\nprocessing malformed or ambiguous JSON documents. (See\\r\\n[below](#duplicates) for a full discussion.)\\r\\n\\r\\nSuccessful parsing returns an instance of `JsonValue`. Unsuccessful\\r\\nparsing throws an unchecked\\r\\n[`JsonParseException`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonParseException.html).\\r\\nThe exception includes a detail message that provides specific\\r\\ninformation about the error, its path from the root of the document, and\\r\\nits location within the document. For example, when a document contains duplicate\\r\\nmember names in an object, the exception thrown has the form:\\r\\n\\r\\n```\\r\\njdk.incubator.json.JsonParseException: The duplicate member name: \\"providers\\" was\\r\\nalready parsed. Path: \\"{\\". Location: line 2, position 4.\\r\\n```\\r\\n\\r\\nMost JSON documents have a JSON object or JSON array at the root. For\\r\\nexample, a [JSON-formatted thread dump produced by the `jcmd`\\r\\ntool](https://download.java.net/java/early_access/jdk27/docs/api/jdk.management/com/sun/management/doc-files/threadDump.html)\\r\\ncontains a root object:\\r\\n\\r\\n```\\r\\n{\\r\\n \\"threadDump\\": {\\r\\n \\"formatVersion\\": 2,\\r\\n \\"processId\\": 45178,\\r\\n \\"time\\": \\"2026-04-16T23:13:02.709630Z\\",\\r\\n \\"runtimeVersion\\": \\"27-internal\\",\\r\\n \\"threadContainers\\": [\\r\\n {\\r\\n \\"container\\": \\"\\u003Croot\\u003E\\",\\r\\n \\"parent\\": null,\\r\\n \\"owner\\": null,\\r\\n \\"threads\\": [\\r\\n {\\r\\n \\"tid\\": 3,\\r\\n \\"time\\": \\"2026-04-16T23:13:02.906891Z\\",\\r\\n \\"name\\": \\"main\\",\\r\\n \\"state\\": \\"WAITING\\",\\r\\n ...\\r\\n```\\r\\n\\r\\nThe root object contains a single member, the nested `threadDump`\\r\\nobject, and `threadDump` itself contains both primitive and structural\\r\\nJSON values.\\r\\n\\r\\nOnce you have obtained the root `JsonValue` via `Json.parse(...)`, you\\r\\ncan retrieve values from objects and arrays via their *access methods*,\\r\\nwhich return the requested member value or array element as a\\r\\n`JsonValue`. It is not necessary to downcast a `JsonValue` to `JsonObject`\\r\\nto access a member value, or to `JsonArray` to access an array element.\\r\\n\\r\\n- [`get(String)`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#get(java.lang.String))\\r\\n obtains the value of an object member. To obtain the\\r\\n thread dump object:\\r\\n\\r\\n ```\\r\\n JsonValue threadDump = root.get(\\"threadDump\\");\\r\\n ```\\r\\n\\r\\n- [`get(int)`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#get(int))\\r\\n obtains an array element. To obtain the root thread container:\\r\\n\\r\\n ```\\r\\n JsonValue firstContainer = threadDump.get(\\"threadContainers\\").get(0);\\r\\n ```\\r\\n\\r\\nIf the `JsonValue` instance is of the wrong type, or if the requested\\r\\nmember or element does not exist, the access methods throw a\\r\\n[`JsonValueException`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValueException.html).\\r\\n\\r\\n\\r\\n### Converting JSON values to Java values\\r\\n\\r\\nYou can convert a JSON value to a Java value by calling one of the\\r\\n*conversion methods* of the `JsonValue` interface. For a conversion to\\r\\nsucceed, the `JsonValue` must be an instance of the appropriate subtype\\r\\nof `JsonValue`:\\r\\n\\r\\n\\u003Ctable\\u003E\\r\\n \\u003Cthead\\u003E\\r\\n \\u003Ctr\\u003E\\r\\n \\u003Cth\\u003ESubtype\\u003C/th\\u003E\\r\\n \\u003Cth\\u003EMethod\\u003C/th\\u003E\\r\\n \\u003Cth\\u003EResulting Java type\\u003C/th\\u003E\\r\\n \\u003C/tr\\u003E\\r\\n \\u003C/thead\\u003E\\r\\n \\u003Ctbody\\u003E\\r\\n \\u003Ctr\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ca href=\\"https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonString.html\\"\\u003E\\u003Ccode\\u003EJsonString\\u003C/code\\u003E\\u003C/a\\u003E\\u003C/td\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ca href=\\"https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#asString()\\"\\u003E\\u003Ccode\\u003EasString()\\u003C/code\\u003E\\u003C/a\\u003E\\u003C/td\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ccode\\u003Ejava.lang.String\\u003C/code\\u003E\\u003C/td\\u003E\\r\\n \\u003C/tr\\u003E\\r\\n \\u003Ctr\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ca href=\\"https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonNumber.html\\"\\u003E\\u003Ccode\\u003EJsonNumber\\u003C/code\\u003E\\u003C/a\\u003E\\u003C/td\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ca href=\\"https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#asInt()\\"\\u003E\\u003Ccode\\u003EasInt()\\u003C/code\\u003E\\u003C/a\\u003E\\u003C/td\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ccode\\u003Eint\\u003C/code\\u003E\\u003C/td\\u003E\\r\\n \\u003C/tr\\u003E\\r\\n \\u003Ctr\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ca href=\\"https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonNumber.html\\"\\u003E\\u003Ccode\\u003EJsonNumber\\u003C/code\\u003E\\u003C/a\\u003E\\u003C/td\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ca href=\\"https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#asLong()\\"\\u003E\\u003Ccode\\u003EasLong()\\u003C/code\\u003E\\u003C/a\\u003E\\u003C/td\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ccode\\u003Elong\\u003C/code\\u003E\\u003C/td\\u003E\\r\\n \\u003C/tr\\u003E\\r\\n \\u003Ctr\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ca href=\\"https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonNumber.html\\"\\u003E\\u003Ccode\\u003EJsonNumber\\u003C/code\\u003E\\u003C/a\\u003E\\u003C/td\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ca href=\\"https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#asDouble()\\"\\u003E\\u003Ccode\\u003EasDouble()\\u003C/code\\u003E\\u003C/a\\u003E\\u003C/td\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ccode\\u003Edouble\\u003C/code\\u003E\\u003C/td\\u003E\\r\\n \\u003C/tr\\u003E\\r\\n \\u003Ctr\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ca href=\\"https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonBoolean.html\\"\\u003E\\u003Ccode\\u003EJsonBoolean\\u003C/code\\u003E\\u003C/a\\u003E\\u003C/td\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ca href=\\"https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#asBoolean()\\"\\u003E\\u003Ccode\\u003EasBoolean()\\u003C/code\\u003E\\u003C/a\\u003E\\u003C/td\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ccode\\u003Eboolean\\u003C/code\\u003E\\u003C/td\\u003E\\r\\n \\u003C/tr\\u003E\\r\\n \\u003Ctr\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ca href=\\"https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonObject.html\\"\\u003E\\u003Ccode\\u003EJsonObject\\u003C/code\\u003E\\u003C/a\\u003E\\u003C/td\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ca href=\\"https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#asMap()\\"\\u003E\\u003Ccode\\u003EasMap()\\u003C/code\\u003E\\u003C/a\\u003E\\u003C/td\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ccode\\u003Ejava.util.Map\\u003C/code\\u003E\\u003C/td\\u003E\\r\\n \\u003C/tr\\u003E\\r\\n \\u003Ctr\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ca href=\\"https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonArray.html\\"\\u003E\\u003Ccode\\u003EJsonArray\\u003C/code\\u003E\\u003C/a\\u003E\\u003C/td\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ca href=\\"https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#asList()\\"\\u003E\\u003Ccode\\u003EasList()\\u003C/code\\u003E\\u003C/a\\u003E\\u003C/td\\u003E\\r\\n \\u003Ctd\\u003E\\u003Ccode\\u003Ejava.util.List\\u003C/code\\u003E\\u003C/td\\u003E\\r\\n \\u003C/tr\\u003E\\r\\n \\u003C/tbody\\u003E\\r\\n\\u003C/table\\u003E\\r\\n\\r\\nFor example, you can retrieve the Java `String` value associated with\\r\\nthe thread dump's \\"time\\" member:\\r\\n\\r\\n```\\r\\nJsonValue threadDumpTime = threadDump.get(\\"time\\");\\r\\nString time = threadDumpTime.asString();\\r\\n```\\r\\n\\r\\nYou can convert the thread containers array into a `List` of `JsonValue`\\r\\ninstances and process each instance:\\r\\n\\r\\n```\\r\\nthreadDump.get(\\"threadContainers\\").asList().forEach(jv -\\u003E ...);\\r\\n```\\r\\n\\r\\nYou can access the thread dump object as a `Map` to retrieve the number\\r\\nof members:\\r\\n\\r\\n```\\r\\nint count = threadDump.asMap().size();\\r\\n```\\r\\n\\r\\nYou can navigate deeply into a JSON document, chaining access methods\\r\\nand converting to a Java value only at the end. To retrieve the thread\\r\\nidentifier value of the first thread in the root thread container:\\r\\n\\r\\n```\\r\\nlong tid = threadDump.get(\\"threadContainers\\").get(0)\\r\\n .get(\\"threads\\").get(0).get(\\"tid\\").asLong();\\r\\n```\\r\\n\\r\\nThe design of the conversion methods eliminates most `instanceof`\\r\\nchecking and downcasting in cases where a specific JSON data type is\\r\\nexpected in a document:\\r\\n\\r\\n- [`asString()`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#asString())\\r\\n converts a `JsonString` instance into a Java `String` with RFC 8259\\r\\n JSON escape sequences translated to their corresponding characters.\\r\\n\\r\\n- [`asInt()`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#asInt())\\r\\n converts a `JsonNumber` instance to a Java `int` if its numeric value\\r\\n can be represented exactly.\\r\\n\\r\\n- [`asLong()`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#asLong())\\r\\n converts a `JsonNumber` instance to a Java `long` if its numeric value\\r\\n can be represented exactly.\\r\\n\\r\\n- [`asDouble()`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#asDouble())\\r\\n converts a `JsonNumber` instance to a Java `double` if its numeric\\r\\n value can be represented accurately.\\r\\n\\r\\n- [`asBoolean()`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#asBoolean())\\r\\n converts a `JsonBoolean` instance to a Java `boolean` value of `true`\\r\\n or `false`.\\r\\n\\r\\n- [`asMap()`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#asMap())\\r\\n converts a `JsonObject` instance into an unmodifiable Java `Map`. If\\r\\n the JSON object contains no members, an empty `Map` is returned.\\r\\n\\r\\n- [`asList()`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#asList())\\r\\n converts a `JsonArray` instance into an unmodifiable Java `List`. If\\r\\n the JSON array contains no elements, an empty `List` is returned.\\r\\n\\r\\nThere is no conversion method for the JSON null value.\\r\\n[`JsonNull`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonNull.html)\\r\\ninstances can be handled by testing for `instanceof JsonNull` or via the\\r\\n[`tryValue`](#Handling-null-values) method.\\r\\n\\r\\nIf a `JsonValue` is not an instance of the appropriate subtype for a\\r\\nconversion method then the method throws a `JsonValueException`. For\\r\\nexample, calling `asInt()` on a `JsonValue` that is an instance of\\r\\n`JsonString` will always throw this exception. No attempt is made to\\r\\nparse the string value into a number.\\r\\n\\r\\nNumeric conversions can fail for reasons such as the numeric value not\\r\\nbeing representable in the target Java numeric type, which also causes a\\r\\n`JsonValueException` to be thrown. See [below](#JSON-numbers) for a\\r\\ndeeper discussion of number handling and conversions.\\r\\n\\r\\n\\r\\n### Handling JSON document evolution\\r\\n\\r\\nJSON documents from a particular source may evolve, over time, in ways\\r\\nthat violate your previous expectations of their structure and content:\\r\\n\\r\\n- You might call access methods expecting member names or array indices\\r\\n that do not exist in the JSON objects and JSON arrays of the document.\\r\\n\\r\\n- You might call conversion methods applicable to one JSON type on\\r\\n values of a different type.\\r\\n\\r\\nIf you call access or conversion methods on the wrong type, they throw a\\r\\n`JsonValueException`. This exception is unchecked, so that scripts and\\r\\nsmall programs are easier to read and write.\\r\\n\\r\\nContinuing with the thread dump example, recall that the root JSON value\\r\\nis a JSON object with a single member, `threadDump`. This code:\\r\\n\\r\\n```\\r\\nJsonValue name = root.get(\\"threadName\\");\\r\\n```\\r\\n\\r\\nthrows a `JsonValueException` with a message that makes it clear the JSON\\r\\nobject does not contain a member with the name `\\"threadName\\"`, while this code:\\r\\n\\r\\n```\\r\\nList\\u003CJsonValue\\u003E threadDumpList = threadDump.asList();\\r\\n```\\r\\n\\r\\nthrows a `JsonValueException`, whose message makes it clear the `threadDump` member\\r\\nis a JSON object, not a JSON array.\\r\\n\\r\\nThe exception message describes the path leading from the root of the\\r\\nJSON document to the unexpected JSON value, as well as the position in\\r\\nthe JSON document. This is helpful when a chain of access methods\\r\\nnavigates deeply into the document. For example, if the earlier code\\r\\nsnippet to extract the thread identifier incorrectly converted it to a\\r\\n`boolean` instead of a `long`:\\r\\n\\r\\n```\\r\\nboolean tid = threadDump.get(\\"threadContainers\\").get(0)\\r\\n .get(\\"threads\\").get(0).get(\\"tid\\").asBoolean();\\r\\n```\\r\\n\\r\\nthen the exception thrown by `asBoolean()` would have the form:\\r\\n\\r\\n```\\r\\njdk.incubator.json.JsonValueException: JsonNumber is not a JsonBoolean. Path:\\r\\n \\"{threadDump{threadContainers[0{threads[0{tid\\". Location: line 13, position 19.\\r\\n```\\r\\n\\r\\n### Handling optional members\\r\\n\\r\\nIf you do not know whether a JSON object has a member with a given name,\\r\\nyou can use the\\r\\n[`tryGet`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#tryGet(java.lang.String))\\r\\naccess method. This returns an `Optional` instance containing the\\r\\nmember's value, or else an empty `Optional` if the member does not\\r\\nexist. (The `get` method, by contrast, confirms that the member exists\\r\\nand throws an exception if it does not.) The `tryGet` method throws a\\r\\n`JsonValueException` if it is not called on a `JsonObject`.\\r\\n\\r\\nConsider the following thread object:\\r\\n\\r\\n```\\r\\n{\\r\\n \\"tid\\": 11,\\r\\n \\"time\\": \\"2026-04-16T23:13:02.918321Z\\",\\r\\n \\"name\\": \\"Finalizer\\",\\r\\n \\"state\\": \\"WAITING\\",\\r\\n \\"waitingOn\\": \\"java.lang.Object@c10f5b9\\",\\r\\n \\"stack\\": [\\r\\n ...\\r\\n```\\r\\n\\r\\nA thread object contains multiple optional members. One of them is the\\r\\n`waitingOn` member, which contains the JSON string representation of the\\r\\nobject on which the thread is waiting. However, in cases where the\\r\\nthread is not waiting, the thread object may look like this:\\r\\n\\r\\n```\\r\\n{\\r\\n \\"tid\\": 10,\\r\\n \\"time\\": \\"2026-04-16T23:13:02.918177Z\\",\\r\\n \\"name\\": \\"Reference Handler\\",\\r\\n \\"state\\": \\"RUNNABLE\\",\\r\\n \\"stack\\": [\\r\\n ...\\r\\n```\\r\\n\\r\\nThus, when processing thread objects from a thread dump, you must be\\r\\nprepared for the `waitingOn` member to be absent. You can handle this\\r\\nvia `tryGet`:\\r\\n\\r\\n```\\r\\nJsonValue thread = ...\\r\\nthread.tryGet(\\"waitingOn\\")\\r\\n .ifPresent(result -\\u003E ...);\\r\\n```\\r\\n\\r\\nThe lambda passed to `ifPresent` is called only if the `waitingOn`\\r\\nmember is present.\\r\\n\\r\\n\\r\\n### Handling null values\\r\\n\\r\\nIf you do not know whether a JSON value is a JSON null, you can use the\\r\\n[`tryValue`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#tryValue())\\r\\naccess method. This method returns an empty `Optional` if the JSON value\\r\\nupon which it is invoked is a `JsonNull`; otherwise, it returns that\\r\\nvalue.\\r\\n\\r\\nFor example, a thread container object typically looks like this:\\r\\n\\r\\n```\\r\\n{\\r\\n \\"container\\": \\"java.util.concurrent.ThreadPoolExecutor@1936a586\\",\\r\\n \\"parent\\": \\"\\u003Croot\\u003E\\",\\r\\n ...\\r\\n```\\r\\n\\r\\nHere, the `parent` member's value is a JSON string, the parent\\r\\ncontainer's name. However, the container named \\"\\\\\\u003Croot\\\\\\u003E\\" is the root of\\r\\nall containers and looks like this:\\r\\n\\r\\n```\\r\\n{\\r\\n \\"container\\": \\"\\u003Croot\\u003E\\",\\r\\n \\"parent\\": null,\\r\\n ...\\r\\n```\\r\\n\\r\\nThe root container has no parent, so the `parent` member's value is a\\r\\nJSON null. Thus, when processing container objects from a thread dump,\\r\\nyou must be prepared for the parent member to be either a JSON string or\\r\\na JSON null. You can handle this via `tryValue`:\\r\\n\\r\\n```\\r\\nJsonValue container = ...\\r\\ncontainer.get(\\"parent\\").tryValue()\\r\\n .ifPresent(result -\\u003E ...);\\r\\n```\\r\\n\\r\\nThe lambda passed to `ifPresent` is called only if the \\"parent\\" member's\\r\\nvalue is not a JSON null.\\r\\n\\r\\n\\r\\n### Handling variable structure and content\\r\\n\\r\\nThe structure and content of JSON documents in a particular context is\\r\\noften uniform, but sometimes it is variable. It might vary across\\r\\ndifferent sources, or over time from a particular source which itself\\r\\nevolves, or even within the same document.\\r\\n\\r\\nFor example, in thread dumps in JDK 26 and earlier releases, thread\\r\\nidentifiers are represented as JSON strings; in [JDK 27 and later\\r\\nreleases](https://bugs.openjdk.org/browse/JDK-8381002), thread\\r\\nidentifiers are represented as JSON numbers.\\r\\n\\r\\nCode that expects the `tid` to be a JSON number, for example:\\r\\n\\r\\n```\\r\\nlong tid = thread.get(\\"tid\\").asLong();\\r\\n```\\r\\n\\r\\nwill fail with a `JsonValueException` if it encounters a thread dump\\r\\nproduced by a version of the JDK that emits `tid` values as JSON\\r\\nstrings.\\r\\n\\r\\nIn either representation, the numeric value is specified to fit in a\\r\\nJava `long`. You could use `instanceof` to check whether you have a\\r\\n`JsonNumber` or a `JsonString`, but it is clearer to use type patterns\\r\\nin a `switch` statement:\\r\\n\\r\\n```\\r\\nlong tid = switch (thread.get(\\"tid\\")) {\\r\\n case JsonNumber jn -\\u003E jn.asLong();\\r\\n case JsonString js -\\u003E Long.parseLong(js.asString());\\r\\n default -\\u003E throw new JsonValueException(\\"Unexpected type for \\\\\\"tid\\\\\\"\\");\\r\\n};\\r\\n```\\r\\n\\r\\n\\r\\n### Generating JSON documents\\r\\n\\r\\nTo generate a JSON document, in string form, from a `JsonValue`, simply\\r\\ninvoke its\\r\\n[`toString`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#toString())\\r\\nmethod. This method returns a compact string representation in which all\\r\\nmembers, elements, and values are emitted on the same line, with no\\r\\nwhitespace between them.\\r\\n\\r\\nFor example, this code:\\r\\n\\r\\n```\\r\\nJsonValue json = Json.parse(\\"\\"\\"\\r\\n {\\r\\n \\"service\\" : \\"web_server\\",\\r\\n \\"id\\" : 3\\r\\n }\\r\\n \\"\\"\\");\\r\\nIO.println(json.toString());\\r\\n```\\r\\n\\r\\nprints:\\r\\n\\r\\n```\\r\\n{\\"service\\":\\"web_server\\",\\"id\\":3}\\r\\n```\\r\\n\\r\\n(The `toString` method is distinct from the `asString` method, which\\r\\nthrows an exception if the `JsonValue` upon which it is invoked is not a\\r\\n`JsonString`.)\\r\\n\\r\\nThe static method\\r\\n[`Json.toDisplayString`](https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/Json.html#toDisplayString(jdk.incubator.json.JsonValue,int))\\r\\nemits a pretty-printed form of a JSON document, where members and\\r\\nelements are separated by newlines and nested structures are indented by\\r\\na given amount. For example, this code:\\r\\n\\r\\n```\\r\\nIO.println(Json.toDisplayString(json, 2));\\r\\n```\\r\\n\\r\\nprints the above structure with two spaces of indentation:\\r\\n\\r\\n```\\r\\n{\\r\\n \\"service\\": \\"web_server\\",\\r\\n \\"id\\": 3\\r\\n}\\r\\n```\\r\\n\\r\\nThe outputs of both the `toString` and `Json.toDisplayString` methods\\r\\nare parsable by the `Json.parse` method, which will produce a\\r\\n`JsonValue` that is equivalent to the original.\\r\\n\\r\\n\\r\\n### JSON numbers\\r\\n\\r\\nThe syntax for JSON numbers defined in [RFC 8259] can represent\\r\\ndecimal values of arbitrary precision and range. The JSON API enables\\r\\nJSON numbers to be processed losslessly; in most applications, however,\\r\\ncommon numeric types suffice.\\r\\n\\r\\nRFC 8259 advises that good interoperability among JSON libraries\\r\\ncan be achieved by using\\r\\n[IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) 64-bit binary\\r\\nfloating point values, corresponding to the Java `double` type. The \\u003Ca\\r\\nhref=\\"https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#asDouble()\\"\\u003E\\u003Ccode\\u003EasDouble()\\u003C/code\\u003E\\u003C/a\\u003E\\r\\nmethod therefore converts a numeric JSON value to a Java `double`. The\\r\\nJSON value must lie within the range that a `double` can represent; if\\r\\nthe value is out of range, a `JsonValueException` is thrown. Infinity\\r\\nand not-a-number (\\"NaN\\") values are not representable in JSON, and thus\\r\\nare never returned. Negative zero, however, is representable in JSON,\\r\\nand thus may be returned.\\r\\n\\r\\nIf the JSON value has more precision than can be represented in a\\r\\n`double`, the value is rounded to the closest `double` value. For\\r\\nexample:\\r\\n\\r\\n```\\r\\ndouble d1 = Json.parse(\\"3.141592653589793238462643383279\\").asDouble();\\r\\n// d1 is 3.141592653589793, the nearest double value\\r\\n\\r\\ndouble d2 = Json.parse(\\"1.8E309\\").asDouble();\\r\\n// throws JsonValueException, out of range\\r\\n```\\r\\n\\r\\nIntegral numeric values are frequently used, so the \\u003Ca\\r\\nhref=\\"https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#asInt()\\"\\u003E\\u003Ccode\\u003EasInt()\\u003C/code\\u003E\\u003C/a\\u003E\\r\\nmethod converts a numeric JSON value to a Java `int` value. The JSON\\r\\nvalue must be exactly representable as an `int`, otherwise an exception\\r\\nis thrown. Numbers that have a syntactic fractional part but that\\r\\nrepresent integral values are converted; for example:\\r\\n\\r\\n```\\r\\nint i1 = Json.parse(\\"123.0\\").asInt(); // succeeds\\r\\nint i2 = Json.parse(\\"234.56E2\\").asInt(); // succeeds\\r\\nint i3 = Json.parse(\\"345.6\\").asInt(); // fails, not integral\\r\\nint i4 = Json.parse(\\"2147483648\\").asInt(); // fails, out of range\\r\\n```\\r\\n\\r\\nThe conversion method \\u003Ca\\r\\nhref=\\"https://cr.openjdk.org/~naoto/json/javadoc/api/jdk.incubator.json/jdk/incubator/json/JsonValue.html#asLong()\\"\\u003E\\u003Ccode\\u003EasLong()\\u003C/code\\u003E\\u003C/a\\u003E\\r\\nis similar to `asInt()` except that it returns a Java `long` value and\\r\\nsupports any JSON numeric value that can be represented exactly as a\\r\\n`long`.\\r\\n\\r\\nIf you need a narrower primitive type than `int` or `double`, you can\\r\\nuse [primitive types in patterns](https://openjdk.org/jeps/530)\\r\\n(currently a preview feature), to perform a safe conversion. For\\r\\nexample, if you expect a JSON number to be representable as a `short`:\\r\\n\\r\\n```\\r\\nJsonValue json = Json.parse(\\"\\"\\"\\r\\n {\\r\\n \\"id\\": 12345,\\r\\n \\"price\\": 10.99\\r\\n }\\r\\n \\"\\"\\");\\r\\nif (json.get(\\"id\\").asInt() instanceof short s) {\\r\\n // use s\\r\\n} else {\\r\\n // report out-of-range error\\r\\n}\\r\\n```\\r\\n\\r\\nAs mentioned previously, JSON numbers can have arbitrary precision and\\r\\nrange. The `asDouble()`, `asInt()`, and `asLong()` methods, by\\r\\ndefinition, handle only a subset of JSON numeric values; they reject\\r\\nout-of-range values, and they round overly-precise values. To handle\\r\\nJSON numeric data without loss of information, you can convert\\r\\nessentially any JSON number to a\\r\\n[`java.math.BigDecimal`](https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/math/BigDecimal.html)\\r\\ninstance:\\r\\n\\r\\n```\\r\\nBigDecimal bd = new BigDecimal(jn.toString());\\r\\n```\\r\\n\\r\\n\\r\\n## Alternatives\\r\\n\\r\\n - \\u003Ca id=\\"features\\"/\\u003E _Provide a full feature set instead of a limited\\r\\n feature set._\\r\\n\\r\\n The many existing external JSON libraries provide, among them, a\\r\\n broad set of features. We cannot possibly include all of these\\r\\n features in the Java Platform; we must, instead, select a subset that\\r\\n provides the greatest value relative to its cost.\\r\\n\\r\\n We have excluded the commonly provided feature of data binding. This\\r\\n feature is undeniably useful and convenient for many applications.\\r\\n However, it would add a significant API footprint and increase\\r\\n implementation and maintenance costs dramatically. Many use cases do\\r\\n not require data binding, so we consider this feature not strictly\\r\\n necessary. That the Jackson and Jakarta JSON libraries factor their\\r\\n data binding features into separate modules is an implicit\\r\\n recognition that there are use cases that do not need data binding.\\r\\n\\r\\n A streaming API is clearly essential for certain narrow, specialized\\r\\n use cases, but it induces a fair amount of application complexity for\\r\\n even simple data extraction tasks. We have thus excluded this feature.\\r\\n\\r\\n Omitting data binding and streaming leaves us with a DOM-like\\r\\n approach in which JSON documents are parsed into trees of\\r\\n JSON-specific objects from which data can be extracted easily. The\\r\\n API is small, and it incurs correspondingly small implementation and\\r\\n maintenance costs. This satisfies the needs of a significant subset\\r\\n of JSON applications, from the simplest to the moderately complex.\\r\\n\\r\\n An application might start off using the Java Platform's JSON API but\\r\\n eventually grow to need features such as data binding or streaming,\\r\\n necessitating a migration to a richer API in an external library. We\\r\\n do not view this scenario as a failure, and it is not sufficient\\r\\n justification to include high-cost features such as JSON data binding\\r\\n and streaming in the Java Platform.\\r\\n\\r\\n - _Integrate an external JSON library._\\r\\n\\r\\n We could integrate an external library into the Java Platform and the\\r\\n JDK, as a downstream fork. This would raise difficult issues over\\r\\n licensing and governance. There would be continual tension over\\r\\n changes flowing in both directions, arising from different criteria\\r\\n regarding specification quality, compatibility, release schedules,\\r\\n and so forth. (We have experienced this tension in the past, with\\r\\n various XML APIs.) It seems likely that these costs, plus the\\r\\n additional maintenance burden on the JDK, would outweigh the benefit\\r\\n of integrating an external library.\\r\\n\\r\\n - _Do nothing, since JSON is already handled well by external\\r\\n libraries._\\r\\n\\r\\n Doing nothing would not serve the larger goal of enabling simple\\r\\n tasks to be accomplished more easily and with less ceremony,\\r\\n especially for simple programs and for newcomers to the Java\\r\\n Platform.\\r\\n\\r\\n Adding any external dependency to an application incurs cost and adds\\r\\n risk. There are probably applications that could benefit from using\\r\\n JSON but that do not, because their maintainers wish to minimize cost\\r\\n and risk. Such applications would benefit from having a standard JSON\\r\\n API in the Java Platform.\\r\\n\\r\\n - \\u003Ca id=\\"duplicates\\"/\\u003E _Allow duplicate member names within JSON\\r\\n objects._\\r\\n\\r\\n This has been a longstanding issue with JSON. Early specifications\\r\\n were underdetermined with respect to the handling of duplicate\\r\\n member names within a single JSON object. JSON libraries behaved\\r\\n inconsistently, or else provided application-settable options to\\r\\n select the policy for handling duplicate names.\\r\\n\\r\\n Unfortunately, an object with duplicate names is fundamentally\\r\\n ambiguous. When the issue of duplicate names was discussed on the\\r\\n [ECMAScript Discussion\\r\\n List](https://esdiscuss.org/topic/json-duplicate-keys) in 2013, the\\r\\n concern about prohibiting duplicate names was that doing so would\\r\\n invalidate existing documents. Thus, the \\"should be unique\\" wording\\r\\n (instead of \\"must\\") was retained, and it has been carried over to\\r\\n current specifications. In particular, [RFC 8259\\r\\n says](https://www.rfc-editor.org/info/rfc8259/#section-4):\\r\\n\\r\\n \\u003E The names within an object SHOULD be unique.\\r\\n \\u003E \\r\\n \\u003E ...\\r\\n \\u003E \\r\\n \\u003E An object whose names are all unique is interoperable in the sense\\r\\n \\u003E that all software implementations receiving that object will agree\\r\\n \\u003E on the name-value mappings. When the names within an object are not\\r\\n \\u003E unique, the behavior of software that receives such an object is\\r\\n \\u003E unpredictable.\\r\\n\\r\\n The unpredictability arises when the object is processed by a system\\r\\n consisting of multiple, independently-developed JSON libraries. This\\r\\n can lead to hard-to-diagnose errors, security vulnerabilities,\\r\\n decreased interoperability, and general lack of robustness. This\\r\\n phenomenon is discussed in\\r\\n [RFC 9413](https://www.rfc-editor.org/info/rfc9413/),\\r\\n \\"Maintaining Robust Protocols\\".\\r\\n\\r\\n For these reasons, we have chosen a strict approach where duplicate\\r\\n names are unconditionally treated as errors. The strict approach\\r\\n gives high confidence in the correctness of parsed documents. We hope\\r\\n that the erroneous documents mentioned in the 2013 ECMAScript\\r\\n conversation have been corrected in the intervening years, and that\\r\\n the software that produced those documents has been fixed.\\r\\n\\r\\n - _Support trailing commas, comments, or other syntax extensions._\\r\\n\\r\\n There are several variants of JSON, e.g.,\\r\\n [JSON5](https://json5.org/), that support comments or trailing commas\\r\\n within arrays and objects. These extensions are intended to\\r\\n facilitate the hand-editing of JSON documents.\\r\\n\\r\\n Given our focus on simplicity and machine-to-machine communication,\\r\\n we do not support such extensions. Doing so would enlarge the testing\\r\\n matrix, increase the possibility of interoperability errors, and\\r\\n increase the overall development and maintenance burden.\\r\\n\\r\\n A common workaround is to pre-process incoming extended-JSON\\r\\n documents before parsing them. For example, single-line comments on\\r\\n lines starting with `'#'` characters are easily removed prior to\\r\\n parsing:\\r\\n\\r\\n ```\\r\\n String jsonc = Files.readString(Path.of(\\"file-with-comments.json\\"));\\r\\n String json = jsonc.replaceAll(\\"(?m)^\\\\\\\\s*#.*$\\", \\"\\");\\r\\n JsonValue jv = Json.parse(json);\\r\\n ```\\r\\n\\r\\n - _Provide additional conversion methods._\\r\\n\\r\\n We could include additional conversion methods for added convenience, such as `asBigDecimal()`.\\r\\n Such a method would be trivial to implement. However, the fact that a method is simple to include\\r\\n does not by itself justify adding it to the API. Our goal is to provide a minimal API that applications\\r\\n can build on top of. It is also just as easy for an application to do `new BigDecimal(JsonNumber.toString())`.\\r\\n\\r\\n While we find that each extra method is perhaps one more convenience, it is also one more opinionated\\r\\n decision. Additionally, since the conversion methods are defined uniformly on `JsonValue`, our goal is to keep\\r\\n this set of methods small and focused, consistent with our intention to make this API easy to use. By providing\\r\\n the minimal set of required operations, we leave users of this API free to add on the extra layers they require,\\r\\n tailored to their specific needs.\\r\\n\\r\\n## Testing\\r\\n\\r\\nWe will rigorously test the JSON API to ensure that only canonical forms\\r\\nof RFC 8259 JSON can be parsed and generated. This will help ensure\\r\\nthat using the API will not result in inconsistencies when interacting\\r\\nwith other JSON libraries. To accomplish this, we will not only add\\r\\ncomprehensive unit tests to the JDK but also leverage the\\r\\nestablished [JSON Parsing Test\\r\\nSuite](https://github.com/nst/JSONTestSuite), which contains numerous\\r\\nedge-case inputs.\\r\\n\\r\\n\\r\\n## Risks and Assumptions\\r\\n\\r\\n- We assume that input JSON documents can fit in memory, as either a\\r\\n `String` or a `char` array. Given our tree-based model, if we were to\\r\\n allow JSON sources such as files or network connections, issues such\\r\\n as insufficient memory would be possible with large documents. This\\r\\n decision aligns with our minimalist design philosophy.\\r\\n\\r\\n- A risk of this proposal is that this new API might end up being used\\r\\n in applications that are already using external JSON libraries,\\r\\n resulting in messiness and confusion. We believe this risk is\\r\\n outweighed by the benefits.\\r\\n\\r\\n- During the incubation period, we will gather more information about\\r\\n use cases involving generating and transforming JSON documents, in\\r\\n order to evolve these areas of the API. In addition, we will continue\\r\\n to consider forthcoming pattern-matching language features that might\\r\\n affect the design of the API.\\r\\n\\r\\n\\r\\n## Appendix: Weather Forecast Example \\u003Ca id=\\"appendix\\"/\\u003E\\r\\n\\r\\nThe following program issues a request to the [U.S. National\\r\\nWeather Service REST API] for a seven-day weather forecast for Santa Clara, CA.\\r\\nIt receives a JSON document in the response body. The program then parses the\\r\\ndocument, navigates into the structure, and obtains an array of forecasts.\\r\\nIt then extracts the temperature from each forecast, averages them, and prints\\r\\nthe result.\\r\\n\\r\\n```\\r\\nimport java.net.*;\\r\\nimport java.net.http.*;\\r\\nimport jdk.incubator.json.Json;\\r\\nimport jdk.incubator.json.JsonValue;\\r\\n\\r\\nvoid main() throws Exception {\\r\\n var query = \\"https://api.weather.gov/gridpoints/MTR/97,83/forecast\\";\\r\\n var client = HttpClient.newHttpClient();\\r\\n var request = HttpRequest.newBuilder(URI.create(query)).build();\\r\\n var response = client.send(request, HttpResponse.BodyHandlers.ofString());\\r\\n String body = response.body();\\r\\n JsonValue json = Json.parse(response.body());\\r\\n json.get(\\"properties\\").get(\\"periods\\").asList().stream()\\r\\n .mapToInt(j -\\u003E j.get(\\"temperature\\").asInt())\\r\\n .average()\\r\\n .ifPresent(IO::println);\\r\\n}\\r\\n```\\r\\n\\r\\n### Enabling the incubating API\\r\\n\\r\\nThe JSON API is, at present, an [incubator\\r\\nmodule](https://openjdk.org/jeps/11), disabled by default. To use it,\\r\\nyou must enable it via the command-line option `--add-modules\\r\\njdk.incubator.json`, which adds the incubator module to the set of\\r\\nmodules available for resolution. To run the above example program, you\\r\\nmust provide this option at both compile time and run time.\\r\\n\\r\\nTo run the average forecast program as a single-file source code\\r\\nprogram, do this:\\r\\n\\r\\n $ java --add-modules jdk.incubator.json Weather.java\\r\\n\\r\\nThe output will be something like:\\r\\n\\r\\n WARNING: Using incubator modules: jdk.incubator.json\\r\\n 53.357142857142854\\r\\n\\r\\nTo compile the program with `javac` and run it with `java`, do this:\\r\\n\\r\\n $ javac --add-modules jdk.incubator.json Weather.java\\r\\n $ java --add-modules jdk.incubator.json Weather\\r\\n\\r\\nYou can use `jshell` to experiment interactively with the API. As\\r\\nbefore, you must enable the incubator module on the command line:\\r\\n\\r\\n $ jshell --add-modules jdk.incubator.json\\r\\n jshell\\u003E import jdk.incubator.json.*\\r\\n jshell\\u003E Json.parse(\\"\\"\\"\\r\\n ...\\u003E { \\"name\\": \\"Today\\", \\"temperature\\": 54 }\\r\\n ...\\u003E \\"\\"\\")\\r\\n $2 ==\\u003E {\\"name\\":\\"Today\\",\\"temperature\\":54}\\r\\n jshell\\u003E $2.get(\\"temperature\\").asInt()\\r\\n $3 ==\\u003E 54\\r\\n jshell\\u003E \\r\\n\\r\\n[U.S. National Weather Service REST API]: https://www.weather.gov/documentation/services-web-api\\r\\n", + "customfield_11100": "0|i38pa3:", + "archiveddate": null, + "customfield_10800": { + "self": "https://bugs.openjdk.org/rest/api/2/user?username=naoto", + "name": "naoto", + "key": "naoto", + "avatarUrls": { + "48x48": "https://bugs.openjdk.org/secure/useravatar?ownerId=naoto&avatarId=17312", + "24x24": "https://bugs.openjdk.org/secure/useravatar?size=small&ownerId=naoto&avatarId=17312", + "16x16": "https://bugs.openjdk.org/secure/useravatar?size=xsmall&ownerId=naoto&avatarId=17312", + "32x32": "https://bugs.openjdk.org/secure/useravatar?size=medium&ownerId=naoto&avatarId=17312" + }, + "displayName": "Naoto Sato", + "active": true, + "timeZone": "America/Los_Angeles" + }, + "attachment": [], + "customfield_10801": null, + "aggregatetimeestimate": null, + "customfield_10802": [ + { + "self": "https://bugs.openjdk.org/rest/api/2/user?username=abuckley", + "name": "abuckley", + "key": "abuckley", + "avatarUrls": { + "48x48": "https://bugs.openjdk.org/secure/useravatar?avatarId=10122", + "24x24": "https://bugs.openjdk.org/secure/useravatar?size=small&avatarId=10122", + "16x16": "https://bugs.openjdk.org/secure/useravatar?size=xsmall&avatarId=10122", + "32x32": "https://bugs.openjdk.org/secure/useravatar?size=medium&avatarId=10122" + }, + "displayName": "Alex Buckley", + "active": true, + "timeZone": "America/Los_Angeles" + } + ], + "summary": "JEP 540: Simple JSON API (Incubator)", + "creator": { + "self": "https://bugs.openjdk.org/rest/api/2/user?username=naoto", + "name": "naoto", + "key": "naoto", + "avatarUrls": { + "48x48": "https://bugs.openjdk.org/secure/useravatar?ownerId=naoto&avatarId=17312", + "24x24": "https://bugs.openjdk.org/secure/useravatar?size=small&ownerId=naoto&avatarId=17312", + "16x16": "https://bugs.openjdk.org/secure/useravatar?size=xsmall&ownerId=naoto&avatarId=17312", + "32x32": "https://bugs.openjdk.org/secure/useravatar?size=medium&ownerId=naoto&avatarId=17312" + }, + "displayName": "Naoto Sato", + "active": true, + "timeZone": "America/Los_Angeles" + }, + "subtasks": [], + "customfield_11010": null, + "reporter": { + "self": "https://bugs.openjdk.org/rest/api/2/user?username=naoto", + "name": "naoto", + "key": "naoto", + "avatarUrls": { + "48x48": "https://bugs.openjdk.org/secure/useravatar?ownerId=naoto&avatarId=17312", + "24x24": "https://bugs.openjdk.org/secure/useravatar?size=small&ownerId=naoto&avatarId=17312", + "16x16": "https://bugs.openjdk.org/secure/useravatar?size=xsmall&ownerId=naoto&avatarId=17312", + "32x32": "https://bugs.openjdk.org/secure/useravatar?size=medium&ownerId=naoto&avatarId=17312" + }, + "displayName": "Naoto Sato", + "active": true, + "timeZone": "America/Los_Angeles" + }, + "aggregateprogress": { + "progress": 0, + "total": 0 + }, + "customfield_11006": null, + "customfield_10710": { + "self": "https://bugs.openjdk.org/rest/api/2/customFieldOption/19116", + "value": "M", + "id": "19116", + "disabled": false + }, + "customfield_10711": null, + "customfield_11801": null, + "customfield_11800": null, + "customfield_10713": null, + "customfield_11802": null, + "duedate": null, + "progress": { + "progress": 0, + "total": 0 + }, + "comment": { + "comments": [ + { + "self": "https://bugs.openjdk.org/rest/api/2/issue/5143806/comment/14861183", + "id": "14861183", + "author": { + "self": "https://bugs.openjdk.org/rest/api/2/user?username=smarks", + "name": "smarks", + "key": "smarks", + "avatarUrls": { + "48x48": "https://bugs.openjdk.org/secure/useravatar?ownerId=smarks&avatarId=11508", + "24x24": "https://bugs.openjdk.org/secure/useravatar?size=small&ownerId=smarks&avatarId=11508", + "16x16": "https://bugs.openjdk.org/secure/useravatar?size=xsmall&ownerId=smarks&avatarId=11508", + "32x32": "https://bugs.openjdk.org/secure/useravatar?size=medium&ownerId=smarks&avatarId=11508" + }, + "displayName": "Stuart Marks", + "active": true, + "timeZone": "America/Los_Angeles" + }, + "body": "Adding Alex Buckley as a reviewer per his request.", + "updateAuthor": { + "self": "https://bugs.openjdk.org/rest/api/2/user?username=smarks", + "name": "smarks", + "key": "smarks", + "avatarUrls": { + "48x48": "https://bugs.openjdk.org/secure/useravatar?ownerId=smarks&avatarId=11508", + "24x24": "https://bugs.openjdk.org/secure/useravatar?size=small&ownerId=smarks&avatarId=11508", + "16x16": "https://bugs.openjdk.org/secure/useravatar?size=xsmall&ownerId=smarks&avatarId=11508", + "32x32": "https://bugs.openjdk.org/secure/useravatar?size=medium&ownerId=smarks&avatarId=11508" + }, + "displayName": "Stuart Marks", + "active": true, + "timeZone": "America/Los_Angeles" + }, + "created": "2026-03-04T20:56:41.161+0000", + "updated": "2026-03-04T20:56:41.161+0000" + }, + { + "self": "https://bugs.openjdk.org/rest/api/2/issue/5143806/comment/14877509", + "id": "14877509", + "author": { + "self": "https://bugs.openjdk.org/rest/api/2/user?username=abaragiola", + "name": "abaragiola", + "key": "JIRAUSER24509", + "avatarUrls": { + "48x48": "https://bugs.openjdk.org/secure/useravatar?ownerId=JIRAUSER24509&avatarId=23102", + "24x24": "https://bugs.openjdk.org/secure/useravatar?size=small&ownerId=JIRAUSER24509&avatarId=23102", + "16x16": "https://bugs.openjdk.org/secure/useravatar?size=xsmall&ownerId=JIRAUSER24509&avatarId=23102", + "32x32": "https://bugs.openjdk.org/secure/useravatar?size=medium&ownerId=JIRAUSER24509&avatarId=23102" + }, + "displayName": "Amedeo Baragiola", + "active": true, + "timeZone": "America/Los_Angeles" + }, + "body": "Please add me (from JVT) as a reviewer to the respective MRs", + "updateAuthor": { + "self": "https://bugs.openjdk.org/rest/api/2/user?username=abaragiola", + "name": "abaragiola", + "key": "JIRAUSER24509", + "avatarUrls": { + "48x48": "https://bugs.openjdk.org/secure/useravatar?ownerId=JIRAUSER24509&avatarId=23102", + "24x24": "https://bugs.openjdk.org/secure/useravatar?size=small&ownerId=JIRAUSER24509&avatarId=23102", + "16x16": "https://bugs.openjdk.org/secure/useravatar?size=xsmall&ownerId=JIRAUSER24509&avatarId=23102", + "32x32": "https://bugs.openjdk.org/secure/useravatar?size=medium&ownerId=JIRAUSER24509&avatarId=23102" + }, + "displayName": "Amedeo Baragiola", + "active": true, + "timeZone": "America/Los_Angeles" + }, + "created": "2026-05-06T16:02:26.836+0000", + "updated": "2026-05-06T16:02:26.836+0000" + } + ], + "maxResults": 1000, + "total": 2, + "startAt": 0 + }, + "votes": { + "self": "https://bugs.openjdk.org/rest/api/2/issue/JDK-8344154/votes", + "votes": 2, + "hasVoted": false + }, + "archivedby": null + }, + "renderedFields": null + } + """; + } +} diff --git a/test/micro/org/openjdk/bench/valhalla/sandbox/corelibs/mapprotos/HashMap.java b/test/micro/org/openjdk/bench/valhalla/sandbox/corelibs/mapprotos/HashMap.java index e7feade9c9e8..7d00cb0190ba 100644 --- a/test/micro/org/openjdk/bench/valhalla/sandbox/corelibs/mapprotos/HashMap.java +++ b/test/micro/org/openjdk/bench/valhalla/sandbox/corelibs/mapprotos/HashMap.java @@ -56,7 +56,7 @@ /** * HashMap using hashing and "open addressing". - * Hash entries are inline class instances. + * Hash entries are value class instances. * As described in Introduction to Algorithms, 3rd Edition (The MIT Press), * Section 11 Hash tables and Section 11.4 Open addressing. * diff --git a/test/micro/org/openjdk/bench/valhalla/sandbox/corelibs/mapprotos/README.md b/test/micro/org/openjdk/bench/valhalla/sandbox/corelibs/mapprotos/README.md index 27fce11975b2..944735c834db 100644 --- a/test/micro/org/openjdk/bench/valhalla/sandbox/corelibs/mapprotos/README.md +++ b/test/micro/org/openjdk/bench/valhalla/sandbox/corelibs/mapprotos/README.md @@ -1,8 +1,8 @@ -# Prototype implementations of HashMaps using inline classes for the table entries. +# Prototype implementations of HashMaps using value classes for the table entries. **NOTE: The implementations have NOT been optimized or tuned.** -## HashMap uses Open Addressing to store all entries in a table of inline classes +## HashMap uses Open Addressing to store all entries in a table of value classes The hash of the key is used as the first index into the table. If there is a collision, double hashing (with a static offset) is used to probe subsequent locations for available storage. The Robin Hood hashing variation on insertion is used to reduce worst case lookup times. @@ -14,7 +14,7 @@ Typical storage usage for a table near its load factor is 22 bytes per entry. Inserting entries into the HashMap may resize the table but otherwise does not use any additional memory on each get or put. -## XHashMap stores the initial entry in a table of inline classes +## XHashMap stores the initial entry in a table of value classes The hash of the key is used as the first index into the table. If there is a collision, subsequent entries add the familiar link list of Nodes. On key removal, direct entries in the table are replaced by the first linked node; diff --git a/test/micro/org/openjdk/bench/valhalla/sandbox/corelibs/mapprotos/XHashMap.java b/test/micro/org/openjdk/bench/valhalla/sandbox/corelibs/mapprotos/XHashMap.java index 75657523c5d0..28f3b3d9c57e 100644 --- a/test/micro/org/openjdk/bench/valhalla/sandbox/corelibs/mapprotos/XHashMap.java +++ b/test/micro/org/openjdk/bench/valhalla/sandbox/corelibs/mapprotos/XHashMap.java @@ -54,7 +54,7 @@ import java.util.function.Function; /** - * Hash map implementation that uses inline class entries in the initial table + * Hash map implementation that uses value class entries in the initial table * and maintains a link list of separate Node entries for key/value pairs * that have the same hash value. The handling of the link list is the same * as the original java.util.HashMap. diff --git a/test/micro/org/openjdk/bench/vm/gc/MicroLargePages.java b/test/micro/org/openjdk/bench/vm/gc/MicroLargePages.java index e6427a79e6ed..27876a9eebb7 100644 --- a/test/micro/org/openjdk/bench/vm/gc/MicroLargePages.java +++ b/test/micro/org/openjdk/bench/vm/gc/MicroLargePages.java @@ -1,5 +1,5 @@ // -// Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -26,9 +26,11 @@ import java.util.Arrays; import java.util.concurrent.TimeUnit; import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.ThreadParams; @OutputTimeUnit(TimeUnit.MINUTES) @State(Scope.Thread) +@Threads(1) @Fork(jvmArgs = {"-Xmx256m", "-XX:+UseLargePages", "-XX:LargePageSizeInBytes=1g", "-Xlog:pagesize"}, value = 5) public class MicroLargePages { @@ -43,7 +45,11 @@ public class MicroLargePages { public long[][] OUT; @Setup(Level.Trial) - public void BmSetup() { + public void BmSetup(ThreadParams params) { + if (params.getThreadCount() != 1) { + throw new IllegalStateException("MicroLargePages requires exactly one thread"); + } + INP = new long[NUM][ARRAYSIZE]; OUT = new long[NUM][ARRAYSIZE]; for (int i = 0; i < NUM; i++) {