Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c1e5a7b0b5 | |||
| 87e206b81e | |||
| 8ac703a8d0 | |||
| c82f3b8fdf | |||
| 57649b487e | |||
| 29c7198bbb | |||
| 60140b6e2b | |||
| 8a507d85e9 | |||
| 3be31d10b5 | |||
| c2e49da8f6 | |||
| 0741f25d3d | |||
| c2d84f0d7d | |||
| 64e0cf4162 | |||
| 4a653f8439 |
@@ -3180,13 +3180,9 @@ void LIR_Assembler::emit_opSubstitutabilityCheck(LIR_OpSubstitutabilityCheck* op
|
||||
} else {
|
||||
Register tmp1 = op->tmp1()->as_register();
|
||||
Register tmp2 = op->tmp2()->as_register();
|
||||
if (left == right) { // same operand, so clearly the same klasses, let's save the check
|
||||
__ b(*op->stub()->entry()); // -> do slow check
|
||||
} else {
|
||||
__ cmp_klasses_from_objects(CR0, left, right, tmp1, tmp2);
|
||||
__ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CR0, Assembler::equal),
|
||||
*op->stub()->entry()); // same klass -> do slow check
|
||||
}
|
||||
__ cmp_klasses_from_objects(CR0, left, right, tmp1, tmp2);
|
||||
__ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CR0, Assembler::equal),
|
||||
*op->stub()->entry()); // same klass -> do slow check
|
||||
// fall through to L_oops_not_equal
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "ci/ciInlineKlass.hpp"
|
||||
#include "ci/ciInstance.hpp"
|
||||
#include "ci/ciObjArrayKlass.hpp"
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "code/compiledIC.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "nativeInst_riscv.hpp"
|
||||
@@ -43,6 +44,7 @@
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/frame.inline.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "runtime/threadIdentifier.hpp"
|
||||
#include "utilities/powerOfTwo.hpp"
|
||||
#include "vmreg_riscv.inline.hpp"
|
||||
|
||||
@@ -441,6 +443,19 @@ void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_cod
|
||||
|
||||
case T_LONG:
|
||||
assert(patch_code == lir_patch_none, "no patching handled here");
|
||||
#if INCLUDE_CDS
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
address b = c->as_pointer();
|
||||
if (b == (address)ThreadIdentifier::unsafe_offset()) {
|
||||
__ la(dest->as_register_lo(), ExternalAddress(b));
|
||||
break;
|
||||
}
|
||||
if (AOTRuntimeConstants::contains(b)) {
|
||||
__ load_aotrc_address(dest->as_register_lo(), b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
__ mv(dest->as_register_lo(), (intptr_t)c->as_jlong());
|
||||
break;
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ private:
|
||||
_call_stub_size = 11 * MacroAssembler::instruction_size +
|
||||
1 * MacroAssembler::instruction_size + wordSize,
|
||||
// See emit_exception_handler for detail
|
||||
_exception_handler_size = DEBUG_ONLY(256) NOT_DEBUG(32), // or smaller
|
||||
_exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175), // or smaller
|
||||
// See emit_deopt_handler for detail
|
||||
// far_call (2) + j (1)
|
||||
_deopt_handler_size = 1 * MacroAssembler::instruction_size +
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "gc/g1/g1BarrierSet.hpp"
|
||||
#include "gc/g1/g1BarrierSetAssembler.hpp"
|
||||
#include "gc/g1/g1BarrierSetRuntime.hpp"
|
||||
@@ -257,9 +258,22 @@ static void generate_post_barrier(MacroAssembler* masm,
|
||||
assert(thread == xthread, "must be");
|
||||
assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, noreg);
|
||||
// Does store cross heap regions?
|
||||
__ xorr(tmp1, store_addr, new_val); // tmp1 := store address ^ new value
|
||||
__ srli(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes)
|
||||
__ beqz(tmp1, done);
|
||||
#if INCLUDE_CDS
|
||||
// AOT code needs to load the barrier grain shift from the aot
|
||||
// runtime constants area in the code cache otherwise we can compile
|
||||
// it as an immediate operand
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
__ xorr(tmp1, store_addr, new_val);
|
||||
__ lwu(tmp2, ExternalAddress(AOTRuntimeConstants::grain_shift_address()));
|
||||
__ srl(tmp1, tmp1, tmp2);
|
||||
__ beqz(tmp1, done);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
__ xorr(tmp1, store_addr, new_val); // tmp1 := store address ^ new value
|
||||
__ srli(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes)
|
||||
__ beqz(tmp1, done);
|
||||
}
|
||||
|
||||
// Crosses regions, storing null?
|
||||
if (new_val_may_be_null) {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
#include "classfile/classLoaderData.hpp"
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "gc/shared/barrierSetAssembler.hpp"
|
||||
#include "gc/shared/barrierSetNMethod.hpp"
|
||||
@@ -370,10 +371,20 @@ void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
void BarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error) {
|
||||
assert_different_registers(obj, tmp1, tmp2);
|
||||
// Check if the oop is in the right area of memory
|
||||
__ mv(tmp2, (intptr_t) Universe::verify_oop_mask());
|
||||
__ andr(tmp1, obj, tmp2);
|
||||
__ mv(tmp2, (intptr_t) Universe::verify_oop_bits());
|
||||
#if INCLUDE_CDS
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
__ ld(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_mask_address()));
|
||||
__ andr(tmp1, obj, tmp2);
|
||||
__ ld(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_bits_address()));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
__ mv(tmp2, (intptr_t) Universe::verify_oop_mask());
|
||||
__ andr(tmp1, obj, tmp2);
|
||||
__ mv(tmp2, (intptr_t) Universe::verify_oop_bits());
|
||||
}
|
||||
|
||||
// Compare tmp1 and tmp2.
|
||||
__ bne(tmp1, tmp2, error);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
|
||||
#include "gc/shenandoah/mode/shenandoahMode.hpp"
|
||||
#include "gc/shenandoah/shenandoahBarrierSet.hpp"
|
||||
@@ -219,8 +220,14 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm,
|
||||
|
||||
// Test for in-cset
|
||||
if (is_strong) {
|
||||
__ mv(t1, ShenandoahHeap::in_cset_fast_test_addr());
|
||||
__ srli(t0, x10, ShenandoahHeapRegion::region_size_bytes_shift_jint());
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
__ ld(t1, ExternalAddress(AOTRuntimeConstants::cset_base_address()));
|
||||
__ lwu(t0, ExternalAddress(AOTRuntimeConstants::grain_shift_address()));
|
||||
__ srl(t0, x10, t0);
|
||||
} else {
|
||||
__ mv(t1, ShenandoahHeap::in_cset_fast_test_addr());
|
||||
__ srli(t0, x10, ShenandoahHeapRegion::region_size_bytes_shift_jint());
|
||||
}
|
||||
__ add(t1, t1, t0);
|
||||
__ lbu(t1, Address(t1));
|
||||
__ test_bit(t0, t1, 0);
|
||||
@@ -434,10 +441,20 @@ void ShenandoahBarrierSetAssembler::try_peek_weak_handle_in_nmethod(MacroAssembl
|
||||
}
|
||||
|
||||
void ShenandoahBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& L_error) {
|
||||
assert_different_registers(obj, tmp1, tmp2);
|
||||
// Check if the oop is in the right area of memory
|
||||
__ mv(tmp2, (intptr_t) Universe::verify_oop_mask());
|
||||
__ andr(tmp1, obj, tmp2);
|
||||
__ mv(tmp2, (intptr_t) Universe::verify_oop_bits());
|
||||
#if INCLUDE_CDS
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
__ ld(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_mask_address()));
|
||||
__ andr(tmp1, obj, tmp2);
|
||||
__ ld(tmp2, ExternalAddress(AOTRuntimeConstants::verify_oop_bits_address()));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
__ mv(tmp2, (intptr_t) Universe::verify_oop_mask());
|
||||
__ andr(tmp1, obj, tmp2);
|
||||
__ mv(tmp2, (intptr_t) Universe::verify_oop_bits());
|
||||
}
|
||||
|
||||
// Compare tmp1 and tmp2.
|
||||
__ bne(tmp1, tmp2, L_error);
|
||||
@@ -815,8 +832,14 @@ void ShenandoahBarrierStubC2::lrb(MacroAssembler& masm) {
|
||||
__ mv(_tmp2, _obj);
|
||||
}
|
||||
|
||||
__ mv(_tmp1, ShenandoahHeap::in_cset_fast_test_addr());
|
||||
__ srli(_tmp2, _tmp2, ShenandoahHeapRegion::region_size_bytes_shift_jint());
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
__ lwu(_tmp1, ExternalAddress(AOTRuntimeConstants::grain_shift_address()));
|
||||
__ srl(_tmp2, _tmp2, _tmp1);
|
||||
__ ld(_tmp1, ExternalAddress(AOTRuntimeConstants::cset_base_address()));
|
||||
} else {
|
||||
__ mv(_tmp1, ShenandoahHeap::in_cset_fast_test_addr());
|
||||
__ srli(_tmp2, _tmp2, ShenandoahHeapRegion::region_size_bytes_shift_jint());
|
||||
}
|
||||
__ add(_tmp1, _tmp1, _tmp2);
|
||||
__ lbu(_tmp1, Address(_tmp1, 0));
|
||||
maybe_far_jump_if_zero(masm, _tmp1);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "code/codeBlob.hpp"
|
||||
#include "code/vmreg.inline.hpp"
|
||||
#include "gc/z/zAddress.hpp"
|
||||
@@ -1007,6 +1008,7 @@ void ZBarrierSetAssembler::generate_c1_store_barrier_stub(LIR_Assembler* ce,
|
||||
#define __ masm->
|
||||
|
||||
void ZBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register tmp1, Register tmp2, Label& error) {
|
||||
assert_different_registers(obj, tmp1, tmp2);
|
||||
// C1 calls verify_oop in the middle of barriers, before they have been uncolored
|
||||
// and after being colored. Therefore, we must deal with colored oops as well.
|
||||
Label done;
|
||||
@@ -1044,9 +1046,18 @@ void ZBarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Registe
|
||||
|
||||
__ bind(check_zaddress);
|
||||
// Check if the oop is the right area of memory
|
||||
__ mv(tmp1, (intptr_t) Universe::verify_oop_mask());
|
||||
__ andr(tmp1, tmp1, obj);
|
||||
__ mv(obj, (intptr_t) Universe::verify_oop_bits());
|
||||
#if INCLUDE_CDS
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
__ ld(tmp1, ExternalAddress(AOTRuntimeConstants::verify_oop_mask_address()));
|
||||
__ andr(tmp1, tmp1, obj);
|
||||
__ ld(obj, ExternalAddress(AOTRuntimeConstants::verify_oop_bits_address()));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
__ mv(tmp1, (intptr_t) Universe::verify_oop_mask());
|
||||
__ andr(tmp1, tmp1, obj);
|
||||
__ mv(obj, (intptr_t) Universe::verify_oop_bits());
|
||||
}
|
||||
__ bne(tmp1, obj, error);
|
||||
|
||||
__ bind(done);
|
||||
|
||||
@@ -26,7 +26,9 @@
|
||||
|
||||
#include "asm/assembler.hpp"
|
||||
#include "asm/assembler.inline.hpp"
|
||||
#include "cds/archiveBuilder.hpp"
|
||||
#include "ci/ciInlineKlass.hpp"
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "code/compiledIC.hpp"
|
||||
#include "compiler/disassembler.hpp"
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
@@ -514,7 +516,11 @@ void MacroAssembler::clinit_barrier(Register klass, Register tmp, Label* L_fast_
|
||||
}
|
||||
|
||||
void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file, int line) {
|
||||
if (!VerifyOops) { return; }
|
||||
if (!VerifyOops || VerifyAdapterSharing) {
|
||||
// Below address of the code string confuses VerifyAdapterSharing
|
||||
// because it may differ between otherwise equivalent adapters.
|
||||
return;
|
||||
}
|
||||
|
||||
// Pass register number to verify_oop_subroutine
|
||||
const char* b = nullptr;
|
||||
@@ -522,7 +528,15 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file,
|
||||
ResourceMark rm;
|
||||
stringStream ss;
|
||||
ss.print("verify_oop: %s: %s (%s:%d)", reg->name(), s, file, line);
|
||||
b = code_string(ss.as_string());
|
||||
#if INCLUDE_CDS
|
||||
if (AOTCodeCache::is_on_for_dump() && !code_section()->scratch_emit()) {
|
||||
// This will duplicate string to preserve it.
|
||||
b = AOTCodeCache::add_C_string(ss.as_string());
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
b = code_string(ss.as_string());
|
||||
}
|
||||
}
|
||||
BLOCK_COMMENT("verify_oop {");
|
||||
|
||||
@@ -534,7 +548,7 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file,
|
||||
// on the address of the char buffer so that the size of mach nodes for
|
||||
// scratch emit and normal emit matches.
|
||||
IncompressibleScope scope(this); // Fixed length
|
||||
movptr(t0, (address) b);
|
||||
la(t0, ExternalAddress((address)b));
|
||||
}
|
||||
|
||||
// Call indirectly to solve generation ordering problem
|
||||
@@ -699,7 +713,9 @@ void MacroAssembler::profile_receiver_type(Register recv, Register mdp, int mdp_
|
||||
}
|
||||
|
||||
void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* file, int line) {
|
||||
if (!VerifyOops) {
|
||||
if (!VerifyOops || VerifyAdapterSharing) {
|
||||
// Below address of the code string confuses VerifyAdapterSharing
|
||||
// because it may differ between otherwise equivalent adapters.
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -708,7 +724,15 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* f
|
||||
ResourceMark rm;
|
||||
stringStream ss;
|
||||
ss.print("verify_oop_addr: %s (%s:%d)", s, file, line);
|
||||
b = code_string(ss.as_string());
|
||||
#if INCLUDE_CDS
|
||||
if (AOTCodeCache::is_on_for_dump() && !code_section()->scratch_emit()) {
|
||||
// This will duplicate string to preserve it.
|
||||
b = AOTCodeCache::add_C_string(ss.as_string());
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
b = code_string(ss.as_string());
|
||||
}
|
||||
}
|
||||
BLOCK_COMMENT("verify_oop_addr {");
|
||||
|
||||
@@ -726,7 +750,7 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* f
|
||||
// on the address of the char buffer so that the size of mach nodes for
|
||||
// scratch emit and normal emit matches.
|
||||
IncompressibleScope scope(this); // Fixed length
|
||||
movptr(t0, (address) b);
|
||||
la(t0, ExternalAddress((address)b));
|
||||
}
|
||||
|
||||
// Call indirectly to solve generation ordering problem
|
||||
@@ -879,9 +903,13 @@ void MacroAssembler::resolve_global_jobject(Register value, Register tmp1, Regis
|
||||
}
|
||||
|
||||
void MacroAssembler::stop(const char* msg) {
|
||||
BLOCK_COMMENT(msg);
|
||||
// Skip AOT caching C strings in scratch buffer.
|
||||
const char* str = (code_section()->scratch_emit()) ? msg : AOTCodeCache::add_C_string(msg);
|
||||
BLOCK_COMMENT(str);
|
||||
// load msg into a0 so we can access it from the signal handler
|
||||
// ExternalAddress enables saving and restoring via the code cache
|
||||
la(c_rarg0, ExternalAddress((address) str));
|
||||
illegal_instruction(Assembler::csr::time);
|
||||
emit_int64((uintptr_t)msg);
|
||||
}
|
||||
|
||||
void MacroAssembler::unimplemented(const char* what) {
|
||||
@@ -911,10 +939,8 @@ void MacroAssembler::emit_static_call_stub() {
|
||||
void MacroAssembler::call_VM_leaf_base(address entry_point,
|
||||
int number_of_arguments,
|
||||
Label *retaddr) {
|
||||
int32_t offset = 0;
|
||||
push_reg(RegSet::of(t1, xmethod), sp); // push << t1 & xmethod >> to sp
|
||||
movptr(t1, entry_point, offset, t0);
|
||||
jalr(t1, offset);
|
||||
rt_call(entry_point, t1, t0);
|
||||
if (retaddr != nullptr) {
|
||||
bind(*retaddr);
|
||||
}
|
||||
@@ -1164,16 +1190,17 @@ void MacroAssembler::jalr(Register Rs, int32_t offset) {
|
||||
Assembler::jalr(x1, Rs, offset);
|
||||
}
|
||||
|
||||
void MacroAssembler::rt_call(address dest, Register tmp) {
|
||||
assert(tmp != x5, "tmp register must not be x5.");
|
||||
void MacroAssembler::rt_call(address dest, Register tmp1, Register tmp2) {
|
||||
assert_different_registers(tmp1, x5);
|
||||
assert_different_registers(tmp1, tmp2);
|
||||
RuntimeAddress target(dest);
|
||||
if (CodeCache::contains(dest)) {
|
||||
far_call(target, tmp);
|
||||
far_call(target, tmp1);
|
||||
} else {
|
||||
relocate(target.rspec(), [&] {
|
||||
int32_t offset;
|
||||
movptr(tmp, target.target(), offset);
|
||||
jalr(tmp, offset);
|
||||
movptr(tmp1, target.target(), offset, tmp2);
|
||||
jalr(tmp1, offset);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -3054,7 +3081,7 @@ int MacroAssembler::patch_oop(address insn_addr, address o) {
|
||||
|
||||
void MacroAssembler::reinit_heapbase() {
|
||||
if (UseCompressedOops) {
|
||||
if (Universe::is_fully_initialized()) {
|
||||
if (Universe::is_fully_initialized() && !AOTCodeCache::is_on_for_dump()) {
|
||||
mv(xheapbase, CompressedOops::base());
|
||||
} else {
|
||||
ld(xheapbase, ExternalAddress(CompressedOops::base_addr()));
|
||||
@@ -3925,19 +3952,28 @@ void MacroAssembler::decode_klass_not_null(Register dst, Register src, Register
|
||||
assert_different_registers(dst, tmp);
|
||||
assert_different_registers(src, tmp);
|
||||
|
||||
if (CompressedKlassPointers::base() == nullptr) {
|
||||
Register xbase = tmp;
|
||||
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
// We are generating code during AOT buildup that will run in *future* processes
|
||||
// with likely different encoding settings. Therefore, we have to load the
|
||||
// encoding base dynamically, we cannot just bake it in as immediate.
|
||||
// Note that we only need to do this for base. The encoding shift would be the
|
||||
// same between build time and runtime: the standard precomputed shift.
|
||||
assert(CompressedKlassPointers::shift() == ArchiveBuilder::precomputed_narrow_klass_shift(),
|
||||
"unexpected compressed klass shift!");
|
||||
ld(xbase, ExternalAddress(CompressedKlassPointers::base_addr()));
|
||||
} else if (CompressedKlassPointers::base() == nullptr) {
|
||||
if (CompressedKlassPointers::shift() != 0) {
|
||||
slli(dst, src, CompressedKlassPointers::shift());
|
||||
} else {
|
||||
mv(dst, src);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
mv(xbase, (uintptr_t)CompressedKlassPointers::base());
|
||||
}
|
||||
|
||||
Register xbase = tmp;
|
||||
|
||||
mv(xbase, (uintptr_t)CompressedKlassPointers::base());
|
||||
|
||||
if (CompressedKlassPointers::shift() != 0) {
|
||||
// dst = (src << shift) + xbase
|
||||
shadd(dst, src, xbase, dst /* temporary, dst != xbase */, CompressedKlassPointers::shift());
|
||||
@@ -3952,6 +3988,28 @@ void MacroAssembler::encode_klass_not_null(Register r, Register tmp) {
|
||||
}
|
||||
|
||||
void MacroAssembler::encode_klass_not_null(Register dst, Register src, Register tmp) {
|
||||
Register xbase = dst;
|
||||
if (dst == src) {
|
||||
xbase = tmp;
|
||||
}
|
||||
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
// We are generating code during AOT buildup that will run in *future* processes
|
||||
// with likely different encoding settings. Therefore, we have to load the
|
||||
// encoding base dynamically and must not take the base-value dependent zext
|
||||
// short cut below. Note that we only need to do this for base; the encoding
|
||||
// shift is the same at build and run time: the standard precomputed shift.
|
||||
assert(CompressedKlassPointers::shift() == ArchiveBuilder::precomputed_narrow_klass_shift(),
|
||||
"unexpected compressed klass shift!");
|
||||
assert_different_registers(src, xbase);
|
||||
ld(xbase, ExternalAddress(CompressedKlassPointers::base_addr()));
|
||||
sub(dst, src, xbase);
|
||||
if (CompressedKlassPointers::shift() != 0) {
|
||||
srli(dst, dst, CompressedKlassPointers::shift());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (CompressedKlassPointers::base() == nullptr) {
|
||||
if (CompressedKlassPointers::shift() != 0) {
|
||||
srli(dst, src, CompressedKlassPointers::shift());
|
||||
@@ -3967,11 +4025,6 @@ void MacroAssembler::encode_klass_not_null(Register dst, Register src, Register
|
||||
return;
|
||||
}
|
||||
|
||||
Register xbase = dst;
|
||||
if (dst == src) {
|
||||
xbase = tmp;
|
||||
}
|
||||
|
||||
assert_different_registers(src, xbase);
|
||||
mv(xbase, (uintptr_t)CompressedKlassPointers::base());
|
||||
sub(dst, src, xbase);
|
||||
@@ -5353,8 +5406,7 @@ void MacroAssembler::get_thread(Register thread) {
|
||||
RegSet::range(x28, x31) + ra - thread;
|
||||
push_reg(saved_regs, sp);
|
||||
|
||||
mv(t1, CAST_FROM_FN_PTR(address, Thread::current));
|
||||
jalr(t1);
|
||||
rt_call(CAST_FROM_FN_PTR(address, Thread::current), t1, t0);
|
||||
if (thread != c_rarg0) {
|
||||
mv(thread, c_rarg0);
|
||||
}
|
||||
@@ -5364,12 +5416,33 @@ void MacroAssembler::get_thread(Register thread) {
|
||||
}
|
||||
|
||||
void MacroAssembler::load_byte_map_base(Register reg) {
|
||||
#if INCLUDE_CDS
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
address byte_map_base_adr = AOTRuntimeConstants::card_table_base_address();
|
||||
ld(reg, ExternalAddress(byte_map_base_adr));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
CardTableBarrierSet* ctbs = CardTableBarrierSet::barrier_set();
|
||||
// Strictly speaking the card table base isn't an address at all, and it might
|
||||
// even be negative. It is thus materialised as a constant.
|
||||
mv(reg, (uint64_t)ctbs->card_table_base_const());
|
||||
}
|
||||
|
||||
void MacroAssembler::load_aotrc_address(Register reg, address a) {
|
||||
#if INCLUDE_CDS
|
||||
assert(AOTRuntimeConstants::contains(a), "address out of range for data area");
|
||||
if (AOTCodeCache::is_on_for_dump()) {
|
||||
// all aotrc field addresses should be registered in the AOTCodeCache address table
|
||||
la(reg, ExternalAddress(a));
|
||||
} else {
|
||||
mv(reg, (intptr_t)a);
|
||||
}
|
||||
#else
|
||||
ShouldNotReachHere();
|
||||
#endif
|
||||
}
|
||||
|
||||
void MacroAssembler::build_frame(int framesize) {
|
||||
assert(framesize >= 2, "framesize must include space for FP/RA");
|
||||
assert(framesize % (2*wordSize) == 0, "must preserve 2*wordSize alignment");
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#define CPU_RISCV_MACROASSEMBLER_RISCV_HPP
|
||||
|
||||
#include "asm/assembler.inline.hpp"
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "code/vmreg.hpp"
|
||||
#include "metaprogramming/enableIf.hpp"
|
||||
#include "oops/compressedOops.hpp"
|
||||
@@ -770,7 +771,7 @@ class MacroAssembler: public Assembler {
|
||||
// is used to keep the entry address for jalr/movptr.
|
||||
// Uses call() for intra code cache, else movptr + jalr.
|
||||
// Clobebrs t1
|
||||
void rt_call(address dest, Register tmp = t1);
|
||||
void rt_call(address dest, Register tmp1 = t1, Register tmp2 = noreg);
|
||||
|
||||
// ret: jalr x0, 0(x1)
|
||||
inline void ret() {
|
||||
@@ -1291,6 +1292,9 @@ public:
|
||||
|
||||
void load_byte_map_base(Register reg);
|
||||
|
||||
// Load a constant address in the AOT Runtime Constants area
|
||||
void load_aotrc_address(Register reg, address a);
|
||||
|
||||
void bang_stack_with_offset(int offset) {
|
||||
// stack grows down, caller passes positive offset
|
||||
assert(offset > 0, "must bang with negative offset");
|
||||
|
||||
@@ -2421,10 +2421,7 @@ encode %{
|
||||
// Make the anchor frame walkable
|
||||
__ la(t0, retaddr);
|
||||
__ sd(t0, Address(xthread, JavaThread::last_Java_pc_offset()));
|
||||
int32_t offset = 0;
|
||||
// No relocation needed
|
||||
__ movptr(t1, entry, offset, t0); // lui + lui + slli + add
|
||||
__ jalr(t1, offset);
|
||||
__ rt_call(entry, t1, t0);
|
||||
__ bind(retaddr);
|
||||
__ post_call_nop();
|
||||
}
|
||||
@@ -2821,6 +2818,18 @@ operand immP_1()
|
||||
interface(CONST_INTER);
|
||||
%}
|
||||
|
||||
// AOT Runtime Constants Address
|
||||
operand immAOTRuntimeConstantsAddress()
|
||||
%{
|
||||
// Check if the address is in the range of AOT Runtime Constants
|
||||
predicate(AOTRuntimeConstants::contains((address)(n->get_ptr())));
|
||||
match(ConP);
|
||||
|
||||
op_cost(0);
|
||||
format %{ %}
|
||||
interface(CONST_INTER);
|
||||
%}
|
||||
|
||||
// Int Immediate: low 16-bit mask
|
||||
operand immI_16bits()
|
||||
%{
|
||||
@@ -4782,6 +4791,20 @@ instruct loadConP1(iRegPNoSp dst, immP_1 con)
|
||||
ins_pipe(ialu_imm);
|
||||
%}
|
||||
|
||||
instruct loadAOTRCAddress(iRegPNoSp dst, immAOTRuntimeConstantsAddress con)
|
||||
%{
|
||||
match(Set dst con);
|
||||
|
||||
ins_cost(ALU_COST);
|
||||
format %{ "la $dst, $con\t# aotrc, #@loadAOTRCAddress" %}
|
||||
|
||||
ins_encode %{
|
||||
__ load_aotrc_address($dst$$Register, (address)$con$$constant);
|
||||
%}
|
||||
|
||||
ins_pipe(ialu_imm);
|
||||
%}
|
||||
|
||||
// Load Narrow Pointer Constant
|
||||
instruct loadConN(iRegNNoSp dst, immN con)
|
||||
%{
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#ifdef COMPILER2
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "code/vmreg.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "opto/runtime.hpp"
|
||||
@@ -58,10 +59,15 @@ public:
|
||||
|
||||
//------------------------------generate_uncommon_trap_blob--------------------
|
||||
UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() {
|
||||
const char* name = OptoRuntime::stub_name(StubId::c2_uncommon_trap_id);
|
||||
CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::C2Blob, BlobId::c2_uncommon_trap_id);
|
||||
if (blob != nullptr) {
|
||||
return blob->as_uncommon_trap_blob();
|
||||
}
|
||||
|
||||
// Allocate space for the code
|
||||
ResourceMark rm;
|
||||
// Setup code generation tools
|
||||
const char* name = OptoRuntime::stub_name(StubId::c2_uncommon_trap_id);
|
||||
CodeBuffer buffer(name, 2048, 1024);
|
||||
if (buffer.blob() == nullptr) {
|
||||
return nullptr;
|
||||
@@ -243,8 +249,10 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() {
|
||||
// Make sure all code is generated
|
||||
masm->flush();
|
||||
|
||||
return UncommonTrapBlob::create(&buffer, oop_maps,
|
||||
SimpleRuntimeFrame::framesize >> 1);
|
||||
UncommonTrapBlob* ut_blob = UncommonTrapBlob::create(&buffer, oop_maps,
|
||||
SimpleRuntimeFrame::framesize >> 1);
|
||||
AOTCodeCache::store_code_blob(*ut_blob, AOTCodeEntry::C2Blob, BlobId::c2_uncommon_trap_id);
|
||||
return ut_blob;
|
||||
}
|
||||
|
||||
//------------------------------generate_exception_blob---------------------------
|
||||
@@ -278,10 +286,15 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() {
|
||||
|
||||
assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned");
|
||||
|
||||
const char* name = OptoRuntime::stub_name(StubId::c2_exception_id);
|
||||
CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::C2Blob, BlobId::c2_exception_id);
|
||||
if (blob != nullptr) {
|
||||
return blob->as_exception_blob();
|
||||
}
|
||||
|
||||
// Allocate space for the code
|
||||
ResourceMark rm;
|
||||
// Setup code generation tools
|
||||
const char* name = OptoRuntime::stub_name(StubId::c2_exception_id);
|
||||
CodeBuffer buffer(name, 2048, 1024);
|
||||
if (buffer.blob() == nullptr) {
|
||||
return nullptr;
|
||||
@@ -380,6 +393,8 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() {
|
||||
masm->flush();
|
||||
|
||||
// Set exception blob
|
||||
return ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1);
|
||||
ExceptionBlob* ex_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1);
|
||||
AOTCodeCache::store_code_blob(*ex_blob, AOTCodeEntry::C2Blob, BlobId::c2_exception_id);
|
||||
return ex_blob;
|
||||
}
|
||||
#endif // COMPILER2
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "code/aotCodeCache.hpp"
|
||||
#include "code/compiledIC.hpp"
|
||||
#include "code/debugInfoRec.hpp"
|
||||
#include "code/vtableStubs.hpp"
|
||||
@@ -2123,6 +2124,12 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
// Setup code generation tools
|
||||
int pad = 0;
|
||||
const char* name = SharedRuntime::stub_name(StubId::shared_deopt_id);
|
||||
CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::SharedBlob, BlobId::shared_deopt_id);
|
||||
if (blob != nullptr) {
|
||||
_deopt_blob = blob->as_deoptimization_blob();
|
||||
return;
|
||||
}
|
||||
|
||||
CodeBuffer buffer(name, 2048 + pad, 1024);
|
||||
MacroAssembler* masm = new MacroAssembler(&buffer);
|
||||
int frame_size_in_words = -1;
|
||||
@@ -2427,6 +2434,8 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
_deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words);
|
||||
assert(_deopt_blob != nullptr, "create deoptimization blob fail!");
|
||||
_deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset);
|
||||
|
||||
AOTCodeCache::store_code_blob(*_deopt_blob, AOTCodeEntry::SharedBlob, BlobId::shared_deopt_id);
|
||||
}
|
||||
|
||||
// Number of stack slots between incoming argument block and the start of
|
||||
@@ -2453,13 +2462,18 @@ VMReg SharedRuntime::thread_register() {
|
||||
SafepointBlob* SharedRuntime::generate_handler_blob(StubId id, address call_ptr) {
|
||||
assert(is_polling_page_id(id), "expected a polling page stub id");
|
||||
|
||||
const char* name = SharedRuntime::stub_name(id);
|
||||
CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::SharedBlob, StubInfo::blob(id));
|
||||
if (blob != nullptr) {
|
||||
return blob->as_safepoint_blob();
|
||||
}
|
||||
|
||||
ResourceMark rm;
|
||||
OopMapSet *oop_maps = new OopMapSet();
|
||||
assert_cond(oop_maps != nullptr);
|
||||
OopMap* map = nullptr;
|
||||
|
||||
// Allocate space for the code. Setup code generation tools.
|
||||
const char* name = SharedRuntime::stub_name(id);
|
||||
CodeBuffer buffer(name, 2048, 1024);
|
||||
MacroAssembler* masm = new MacroAssembler(&buffer);
|
||||
assert_cond(masm != nullptr);
|
||||
@@ -2564,7 +2578,10 @@ SafepointBlob* SharedRuntime::generate_handler_blob(StubId id, address call_ptr)
|
||||
masm->flush();
|
||||
|
||||
// Fill-out other meta info
|
||||
return SafepointBlob::create(&buffer, oop_maps, frame_size_in_words);
|
||||
SafepointBlob* sp_blob = SafepointBlob::create(&buffer, oop_maps, frame_size_in_words);
|
||||
|
||||
AOTCodeCache::store_code_blob(*sp_blob, AOTCodeEntry::SharedBlob, StubInfo::blob(id));
|
||||
return sp_blob;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -2579,10 +2596,15 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(StubId id, address destination
|
||||
assert(StubRoutines::forward_exception_entry() != nullptr, "must be generated before");
|
||||
assert(is_resolve_id(id), "expected a resolve stub id");
|
||||
|
||||
const char* name = SharedRuntime::stub_name(id);
|
||||
CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::SharedBlob, StubInfo::blob(id));
|
||||
if (blob != nullptr) {
|
||||
return blob->as_runtime_stub();
|
||||
}
|
||||
|
||||
// allocate space for the code
|
||||
ResourceMark rm;
|
||||
|
||||
const char* name = SharedRuntime::stub_name(id);
|
||||
CodeBuffer buffer(name, 1000, 512);
|
||||
MacroAssembler* masm = new MacroAssembler(&buffer);
|
||||
assert_cond(masm != nullptr);
|
||||
@@ -2653,7 +2675,10 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(StubId id, address destination
|
||||
masm->flush();
|
||||
|
||||
// return the blob
|
||||
return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, true);
|
||||
RuntimeStub* rs_blob = RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, true);
|
||||
|
||||
AOTCodeCache::store_code_blob(*rs_blob, AOTCodeEntry::SharedBlob, StubInfo::blob(id));
|
||||
return rs_blob;
|
||||
}
|
||||
|
||||
// Continuation point for throwing of implicit exceptions that are
|
||||
@@ -2698,6 +2723,11 @@ RuntimeStub* SharedRuntime::generate_throw_exception(StubId id, address runtime_
|
||||
const char* timer_msg = "SharedRuntime generate_throw_exception";
|
||||
TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime));
|
||||
|
||||
CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::SharedBlob, StubInfo::blob(id));
|
||||
if (blob != nullptr) {
|
||||
return blob->as_runtime_stub();
|
||||
}
|
||||
|
||||
CodeBuffer code(name, insts_size, locs_size);
|
||||
OopMapSet* oop_maps = new OopMapSet();
|
||||
MacroAssembler* masm = new MacroAssembler(&code);
|
||||
@@ -2756,6 +2786,8 @@ RuntimeStub* SharedRuntime::generate_throw_exception(StubId id, address runtime_
|
||||
(framesize >> (LogBytesPerWord - LogBytesPerInt)),
|
||||
oop_maps, false);
|
||||
assert(stub != nullptr, "create runtime stub fail!");
|
||||
|
||||
AOTCodeCache::store_code_blob(*stub, AOTCodeEntry::SharedBlob, StubInfo::blob(id));
|
||||
return stub;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -507,7 +507,17 @@ ATTRIBUTE_ALIGNED(4096) juint StubRoutines::riscv::_crc_table[] =
|
||||
};
|
||||
|
||||
#if INCLUDE_CDS
|
||||
// nothing to do for riscv
|
||||
extern void StubGenerator_init_AOTAddressTable(GrowableArray<address>& external_addresses);
|
||||
|
||||
void StubRoutines::init_AOTAddressTable() {
|
||||
ResourceMark rm;
|
||||
GrowableArray<address> external_addresses;
|
||||
// publish static addresses referred to by riscv generator
|
||||
// n.b. we have to use an extern call here because class
|
||||
// StubGenerator, which provides the static method that knows how to
|
||||
// add the relevant addresses, is declared in a source file rather
|
||||
// than in a separately includeable header.
|
||||
StubGenerator_init_AOTAddressTable(external_addresses);
|
||||
AOTCodeCache::publish_external_addresses(external_addresses);
|
||||
}
|
||||
#endif // INCLUDE_CDS
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "runtime/vm_version.hpp"
|
||||
#include "utilities/formatBuffer.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
@@ -509,3 +510,62 @@ bool VM_Version::is_intrinsic_supported(vmIntrinsicID id) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int VM_Version::cpu_features_size() {
|
||||
return sizeof(RVExtFeatures);
|
||||
}
|
||||
|
||||
void VM_Version::store_cpu_features(void* buf) {
|
||||
memcpy(buf, RVExtFeatures::current(), sizeof(RVExtFeatures));
|
||||
}
|
||||
|
||||
bool VM_Version::verify_aot_code_cache_features(void* features_buffer) {
|
||||
RVExtFeatures* features_to_test = (RVExtFeatures*)features_buffer;
|
||||
return RVExtFeatures::current()->verify_aot_code_cache_features(features_to_test);
|
||||
}
|
||||
|
||||
// Print one feature using the same spelling as features_string(): single letter
|
||||
// extensions appear as "rvc"/"rvv" and multi-character extensions with a lower
|
||||
// case leading character ("Zba" -> "zba"). Must stay in sync with the feature
|
||||
// string built in VM_Version::setup_cpu_available_features().
|
||||
void VM_Version::print_feature_name(stringStream& ss, RVFeatureValue* feature) {
|
||||
const char* pretty = feature->pretty();
|
||||
if (strlen(pretty) == 1) {
|
||||
ss.print("rv%s", pretty);
|
||||
} else {
|
||||
ss.print("%c%s", (char)tolower(pretty[0]), &pretty[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void VM_Version::insert_features_names(RVExtFeatures* features, stringStream& ss) {
|
||||
const char* sep = "";
|
||||
int i = 0;
|
||||
while (i < RVExtFeatures::MAX_CPU_FEATURE_INDEX) {
|
||||
if (features->support_feature(i)) {
|
||||
ss.print("%s", sep);
|
||||
print_feature_name(ss, _feature_list[i]);
|
||||
sep = ", ";
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void VM_Version::get_cpu_features_name(void* features_buffer, stringStream& ss) {
|
||||
RVExtFeatures* features = (RVExtFeatures*)features_buffer;
|
||||
insert_features_names(features, ss);
|
||||
}
|
||||
|
||||
void VM_Version::get_missing_features_name(void* features_set1, void* features_set2, stringStream& ss) {
|
||||
RVExtFeatures* rv_ext_features_set1 = (RVExtFeatures*)features_set1;
|
||||
RVExtFeatures* rv_ext_features_set2 = (RVExtFeatures*)features_set2;
|
||||
const char* sep = "";
|
||||
int i = 0;
|
||||
while (i < RVExtFeatures::MAX_CPU_FEATURE_INDEX) {
|
||||
if (rv_ext_features_set1->support_feature(i) && !rv_ext_features_set2->support_feature(i)) {
|
||||
ss.print("%s", sep);
|
||||
print_feature_name(ss, _feature_list[i]);
|
||||
sep = ", ";
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "utilities/sizes.hpp"
|
||||
|
||||
class RiscvHwprobe;
|
||||
class stringStream;
|
||||
|
||||
class VM_Version : public Abstract_VM_Version {
|
||||
friend RiscvHwprobe;
|
||||
@@ -396,6 +397,15 @@ private:
|
||||
int idx = element_index(f);
|
||||
return (_features_bitmap[idx] & feature_bit(f)) != 0;
|
||||
}
|
||||
|
||||
bool verify_aot_code_cache_features(RVExtFeatures* features_to_test) const {
|
||||
for (int i = 0; i < element_count(); i++) {
|
||||
if (_features_bitmap[i] != features_to_test->_features_bitmap[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// enable extensions based on profile, current supported profiles:
|
||||
@@ -523,6 +533,17 @@ private:
|
||||
|
||||
// Check intrinsic support
|
||||
static bool is_intrinsic_supported(vmIntrinsicID id);
|
||||
|
||||
// AOT Code Cache support
|
||||
static int cpu_features_size();
|
||||
static void store_cpu_features(void* buf);
|
||||
static bool verify_aot_code_cache_features(void* features_buffer);
|
||||
static void get_cpu_features_name(void* features_buffer, stringStream& ss);
|
||||
static void get_missing_features_name(void* features_set1, void* features_set2, stringStream& ss);
|
||||
|
||||
private:
|
||||
static void print_feature_name(stringStream& ss, RVFeatureValue* feature);
|
||||
static void insert_features_names(RVExtFeatures* features, stringStream& ss);
|
||||
};
|
||||
|
||||
#endif // CPU_RISCV_VM_VERSION_RISCV_HPP
|
||||
|
||||
@@ -1628,12 +1628,8 @@ void LIR_Assembler::emit_opSubstitutabilityCheck(LIR_OpSubstitutabilityCheck* op
|
||||
} else {
|
||||
Register tmp1 = op->tmp1()->as_register();
|
||||
Register tmp2 = op->tmp2()->as_register();
|
||||
if (left == right) { // same operand, so clearly the same klasses, let's save the check
|
||||
__ jmp (*op->stub()->entry()); // -> do slow check
|
||||
} else {
|
||||
__ cmp_klasses_from_objects(left, right, tmp1, tmp2);
|
||||
__ jcc(Assembler::equal, *op->stub()->entry()); // same klass -> do slow check
|
||||
}
|
||||
__ cmp_klasses_from_objects(left, right, tmp1, tmp2);
|
||||
__ jcc(Assembler::equal, *op->stub()->entry()); // same klass -> do slow check
|
||||
// fall through to L_oops_not_equal
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,11 @@
|
||||
|
||||
#define REG_LR 1
|
||||
#define REG_FP 8
|
||||
// First argument register (x10), used to pass the stop() message
|
||||
// to the signal handler.
|
||||
#ifndef REG_A0
|
||||
#define REG_A0 10
|
||||
#endif
|
||||
#define REG_BCP 22
|
||||
|
||||
NOINLINE address os::current_stack_pointer() {
|
||||
@@ -240,11 +245,8 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info,
|
||||
stub = SharedRuntime::handle_unsafe_access(thread, next_pc);
|
||||
}
|
||||
} else if (sig == SIGILL && nativeInstruction_at(pc)->is_stop()) {
|
||||
// Pull a pointer to the error message out of the instruction
|
||||
// stream.
|
||||
const uint64_t *detail_msg_ptr
|
||||
= (uint64_t*)(pc + NativeInstruction::instruction_size);
|
||||
const char *detail_msg = (const char *)*detail_msg_ptr;
|
||||
// A pointer to the message will have been placed in a0
|
||||
const char *detail_msg = (const char *)(uc->uc_mcontext.__gregs[REG_A0]);
|
||||
const char *msg = "stop";
|
||||
if (TraceTraps) {
|
||||
tty->print_cr("trap: %s: (SIGILL)", msg);
|
||||
|
||||
@@ -3418,6 +3418,11 @@ void LIRGenerator::substitutability_check(If* x, LIRItem& left, LIRItem& right)
|
||||
void LIRGenerator::substitutability_check_common(Value left_val, Value right_val, LIRItem& left, LIRItem& right,
|
||||
LIR_Opr equal_result, LIR_Opr not_equal_result, LIR_Opr result,
|
||||
CodeEmitInfo* info) {
|
||||
if (left.result() == right.result()) {
|
||||
__ move(equal_result, result);
|
||||
return;
|
||||
}
|
||||
|
||||
LIR_Opr tmp1 = LIR_OprFact::illegalOpr;
|
||||
LIR_Opr tmp2 = LIR_OprFact::illegalOpr;
|
||||
|
||||
|
||||
@@ -204,7 +204,7 @@ uint AOTCodeCache::max_aot_code_size() {
|
||||
// At this point all AOT class linking seetings are finilized
|
||||
// and AOT cache is open so we can map AOT code region.
|
||||
void AOTCodeCache::initialize() {
|
||||
#if defined(ZERO) || !(defined(AMD64) || defined(AARCH64))
|
||||
#if defined(ZERO) || !(defined(AMD64) || defined(AARCH64) || defined(RISCV64))
|
||||
log_info(aot, codecache, init)("AOT Code Cache is not supported on this platform.");
|
||||
disable_caching();
|
||||
return;
|
||||
@@ -263,7 +263,7 @@ void AOTCodeCache::initialize() {
|
||||
FLAG_SET_DEFAULT(ForceUnreachable, true);
|
||||
}
|
||||
FLAG_SET_DEFAULT(DelayCompilerStubsGeneration, false);
|
||||
#endif // defined(AMD64) || defined(AARCH64)
|
||||
#endif // defined(AMD64) || defined(AARCH64) || defined(RISCV64)
|
||||
}
|
||||
|
||||
static AOTCodeCache* opened_cache = nullptr; // Use this until we verify the cache
|
||||
@@ -471,7 +471,7 @@ void AOTCodeCache::Config::record(uint cpu_features_offset) {
|
||||
_useUnalignedLoadStores = UseUnalignedLoadStores;
|
||||
#endif
|
||||
|
||||
#if defined(AARCH64) && !defined(ZERO)
|
||||
#if (defined(AARCH64) || defined(RISCV64)) && !defined(ZERO)
|
||||
_avoidUnalignedAccesses = AvoidUnalignedAccesses;
|
||||
#endif
|
||||
|
||||
@@ -601,14 +601,14 @@ bool AOTCodeCache::Config::verify(AOTCodeCache* cache) const {
|
||||
}
|
||||
#endif // defined(X86) && !defined(ZERO)
|
||||
|
||||
#if defined(AARCH64) && !defined(ZERO)
|
||||
#if (defined(AARCH64) || defined(RISCV64)) && !defined(ZERO)
|
||||
// switching on AvoidUnalignedAccesses may affect validity of array
|
||||
// copy stubs and nmethods
|
||||
if (!_avoidUnalignedAccesses && AvoidUnalignedAccesses) {
|
||||
log_config_mismatch(_avoidUnalignedAccesses, AvoidUnalignedAccesses, "AvoidUnalignedAccesses");
|
||||
return false;
|
||||
}
|
||||
#endif // defined(AARCH64) && !defined(ZERO)
|
||||
#endif // (defined(AARCH64) || defined(RISCV64)) && !defined(ZERO)
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1941,6 +1941,8 @@ void AOTCodeAddressTable::init_extrs() {
|
||||
ADD_EXTERNAL_ADDRESS(SharedRuntime::allocate_inline_types);
|
||||
#if defined(AARCH64) && !defined(ZERO)
|
||||
ADD_EXTERNAL_ADDRESS(JavaThread::aarch64_get_thread_helper);
|
||||
#endif
|
||||
#if (defined(AARCH64) || defined(RISCV64)) && !defined(ZERO)
|
||||
ADD_EXTERNAL_ADDRESS(BarrierSetAssembler::patching_epoch_addr());
|
||||
#endif
|
||||
|
||||
|
||||
@@ -352,11 +352,26 @@ public:
|
||||
#define AOTCODECACHE_CONFIGS_X86_DO(do_var, do_fun)
|
||||
#endif
|
||||
|
||||
#if defined(RISCV64) && !defined(ZERO)
|
||||
#define AOTCODECACHE_CONFIGS_RISCV_DO(do_var, do_fun) \
|
||||
do_var(intx, BlockZeroingLowLimit) /* zero blocks stub */ \
|
||||
do_var(bool, UseBlockZeroing) /* zero blocks stub and nmethods */ \
|
||||
do_var(bool, UseConservativeFence) /* fence encoding in stubs and nmethods */ \
|
||||
do_var(bool, UseCtxFencei) /* method entry barrier stub */ \
|
||||
do_var(bool, UseSecondarySupersCache) /* secondary supers cache in nmethods */ \
|
||||
do_var(bool, UseZabha) /* narrow cmpxchg selection in nmethods */ \
|
||||
do_fun(int, RVZicbozBlockSize, (int)VM_Version::zicboz_block_size.value()) \
|
||||
// END
|
||||
#else
|
||||
#define AOTCODECACHE_CONFIGS_RISCV_DO(do_var, do_fun)
|
||||
#endif
|
||||
|
||||
#define AOTCODECACHE_CONFIGS_DO(do_var, do_fun) \
|
||||
AOTCODECACHE_CONFIGS_GENERIC_DO(do_var, do_fun) \
|
||||
AOTCODECACHE_CONFIGS_COMPILER2_DO(do_var, do_fun) \
|
||||
AOTCODECACHE_CONFIGS_AARCH64_DO(do_var, do_fun) \
|
||||
AOTCODECACHE_CONFIGS_X86_DO(do_var, do_fun) \
|
||||
AOTCODECACHE_CONFIGS_RISCV_DO(do_var, do_fun) \
|
||||
// END
|
||||
|
||||
#define AOTCODECACHE_DECLARE_VAR(type, name) type _saved_ ## name;
|
||||
@@ -377,7 +392,7 @@ protected:
|
||||
bool _useUnalignedLoadStores;
|
||||
#endif
|
||||
|
||||
#if defined(AARCH64) && !defined(ZERO)
|
||||
#if (defined(AARCH64) || defined(RISCV64)) && !defined(ZERO)
|
||||
bool _avoidUnalignedAccesses;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -187,7 +187,7 @@ inline void ShenandoahBarrierSet::satb_barrier(T *field) {
|
||||
if (ShenandoahSATBBarrier && _heap->is_concurrent_mark_in_progress()) {
|
||||
T heap_oop = RawAccess<>::oop_load(field);
|
||||
if (!CompressedOops::is_null(heap_oop)) {
|
||||
enqueue(CompressedOops::decode(heap_oop));
|
||||
enqueue(CompressedOops::decode_not_null(heap_oop));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1465,10 +1465,8 @@ void ShenandoahHeap::print_heap_regions_on(outputStream* st) const {
|
||||
st->print_cr("Heap Regions:");
|
||||
st->print_cr("Region state: EU=empty-uncommitted, EC=empty-committed, R=regular, H=humongous start, HP=pinned humongous start");
|
||||
st->print_cr(" HC=humongous continuation, CS=collection set, TR=trash, P=pinned, CSP=pinned collection set");
|
||||
st->print_cr("BTE=bottom/top/end, TAMS=top-at-mark-start");
|
||||
st->print_cr("UWM=update watermark, U=used");
|
||||
st->print_cr("T=TLAB allocs, G=GCLAB allocs");
|
||||
st->print_cr("S=shared allocs, L=live data");
|
||||
st->print_cr("A=age, BTE=bottom/top/end, TAMS=top-at-mark-start, UWM=update watermark, U=used");
|
||||
st->print_cr("T=TLAB allocs, G=GCLAB allocs, S=shared allocs, L=live data");
|
||||
st->print_cr("CP=critical pins");
|
||||
|
||||
for (size_t i = 0; i < num_regions(); i++) {
|
||||
|
||||
@@ -139,7 +139,7 @@ inline void ShenandoahHeap::conc_update_with_forwarded(T* p) {
|
||||
|
||||
// Either we succeed in updating the reference, or something else gets in our way.
|
||||
// We don't care if that is another concurrent GC update, or another mutator update.
|
||||
atomic_update_oop(fwd, p, obj);
|
||||
atomic_update_oop(fwd, p, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -196,14 +196,14 @@ inline void ShenandoahHeap::atomic_update_oop(oop update, oop* addr, oop compare
|
||||
|
||||
inline void ShenandoahHeap::atomic_update_oop(oop update, narrowOop* addr, narrowOop compare) {
|
||||
assert(is_aligned(addr, sizeof(narrowOop)), "Address should be aligned: " PTR_FORMAT, p2i(addr));
|
||||
narrowOop u = CompressedOops::encode(update);
|
||||
narrowOop u = CompressedOops::encode_not_null(update);
|
||||
AtomicAccess::cmpxchg(addr, compare, u, memory_order_release);
|
||||
}
|
||||
|
||||
inline void ShenandoahHeap::atomic_update_oop(oop update, narrowOop* addr, oop compare) {
|
||||
assert(is_aligned(addr, sizeof(narrowOop)), "Address should be aligned: " PTR_FORMAT, p2i(addr));
|
||||
narrowOop c = CompressedOops::encode(compare);
|
||||
narrowOop u = CompressedOops::encode(update);
|
||||
narrowOop u = CompressedOops::encode_not_null(update);
|
||||
AtomicAccess::cmpxchg(addr, c, u, memory_order_release);
|
||||
}
|
||||
|
||||
@@ -214,14 +214,14 @@ inline bool ShenandoahHeap::atomic_update_oop_check(oop update, oop* addr, oop c
|
||||
|
||||
inline bool ShenandoahHeap::atomic_update_oop_check(oop update, narrowOop* addr, narrowOop compare) {
|
||||
assert(is_aligned(addr, sizeof(narrowOop)), "Address should be aligned: " PTR_FORMAT, p2i(addr));
|
||||
narrowOop u = CompressedOops::encode(update);
|
||||
narrowOop u = CompressedOops::encode_not_null(update);
|
||||
return (narrowOop) AtomicAccess::cmpxchg(addr, compare, u, memory_order_release) == compare;
|
||||
}
|
||||
|
||||
inline bool ShenandoahHeap::atomic_update_oop_check(oop update, narrowOop* addr, oop compare) {
|
||||
assert(is_aligned(addr, sizeof(narrowOop)), "Address should be aligned: " PTR_FORMAT, p2i(addr));
|
||||
narrowOop c = CompressedOops::encode(compare);
|
||||
narrowOop u = CompressedOops::encode(update);
|
||||
narrowOop u = CompressedOops::encode_not_null(update);
|
||||
return CompressedOops::decode(AtomicAccess::cmpxchg(addr, c, u, memory_order_release)) == compare;
|
||||
}
|
||||
|
||||
@@ -236,7 +236,7 @@ inline void ShenandoahHeap::atomic_clear_oop(oop* addr, oop compare) {
|
||||
|
||||
inline void ShenandoahHeap::atomic_clear_oop(narrowOop* addr, oop compare) {
|
||||
assert(is_aligned(addr, sizeof(narrowOop)), "Address should be aligned: " PTR_FORMAT, p2i(addr));
|
||||
narrowOop cmp = CompressedOops::encode(compare);
|
||||
narrowOop cmp = CompressedOops::encode_not_null(compare);
|
||||
AtomicAccess::cmpxchg(addr, cmp, narrowOop(), memory_order_relaxed);
|
||||
}
|
||||
|
||||
|
||||
@@ -424,6 +424,7 @@ void ShenandoahHeapRegion::print_on(outputStream* st) const {
|
||||
}
|
||||
|
||||
st->print("|%s", shenandoah_affiliation_code(affiliation()));
|
||||
st->print("|A %2d", age());
|
||||
|
||||
#define SHR_PTR_FORMAT "%12" PRIxPTR
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ JRT_LEAF(narrowOop, ShenandoahRuntime::load_reference_barrier_strong_narrow_narr
|
||||
assert(!CompressedOops::is_null(src), "Filtered by caller");
|
||||
oop s = CompressedOops::decode_not_null(src);
|
||||
oop r = ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator<ON_STRONG_OOP_REF, narrowOop>(s, load_addr);
|
||||
return CompressedOops::encode(r);
|
||||
return CompressedOops::encode_not_null(r);
|
||||
JRT_END
|
||||
|
||||
JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_weak(oopDesc* src, oop* load_addr))
|
||||
|
||||
@@ -399,7 +399,7 @@ bool ConnectionGraph::compute_escape() {
|
||||
if (VerifyReduceAllocationMerges) {
|
||||
for (uint i = 0; i < reducible_merges.size(); i++ ) {
|
||||
Node* n = reducible_merges.at(i);
|
||||
if (!can_reduce_phi(n->as_Phi())) {
|
||||
if (n->outcnt() > 0 && !can_reduce_phi(n->as_Phi())) {
|
||||
TraceReduceAllocationMerges = true;
|
||||
n->dump(2);
|
||||
n->dump(-2);
|
||||
@@ -666,7 +666,7 @@ bool ConnectionGraph::can_reduce_phi(PhiNode* ophi) const {
|
||||
// If there was an error attempting to reduce allocation merges for this
|
||||
// method we might have disabled the compilation and be retrying with RAM
|
||||
// disabled.
|
||||
if (!_compile->do_reduce_allocation_merges() || ophi->region()->Opcode() != Op_Region) {
|
||||
if (!_compile->do_reduce_allocation_merges() || ophi->region() == nullptr || ophi->region()->Opcode() != Op_Region) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -4631,7 +4631,7 @@ bool LibraryCallKit::inline_Class_cast() {
|
||||
}
|
||||
|
||||
// Not-subtype or the mirror's klass ptr is nullptr (in case it is a primitive).
|
||||
enum { _bad_type_path = 1, _prim_path = 2, _npe_path = 3, PATH_LIMIT };
|
||||
enum { _bad_type_path = 1, _prim_path = 2, PATH_LIMIT };
|
||||
RegionNode* region = new RegionNode(PATH_LIMIT);
|
||||
record_for_igvn(region);
|
||||
|
||||
@@ -4653,8 +4653,7 @@ bool LibraryCallKit::inline_Class_cast() {
|
||||
region->init_req(_bad_type_path, bad_type_ctrl);
|
||||
}
|
||||
if (region->in(_prim_path) != top() ||
|
||||
region->in(_bad_type_path) != top() ||
|
||||
region->in(_npe_path) != top()) {
|
||||
region->in(_bad_type_path) != top()) {
|
||||
// Let Interpreter throw ClassCastException.
|
||||
PreserveJVMState pjvms(this);
|
||||
if (new_cast_failure_map != nullptr) {
|
||||
|
||||
@@ -52,6 +52,9 @@ class StringConcat : public ResourceObj {
|
||||
Node_List _control; // List of control nodes that will be deleted
|
||||
Node_List _uncommon_traps; // Uncommon traps that needs to be rewritten
|
||||
// to restart at the initial JVMState.
|
||||
Unique_Node_List _allowed_compares; // validate_control_flow() needs to know which compare nodes are
|
||||
// accepted users of call results. In case of stacked concats,
|
||||
// these need to be persisted across merges for validation.
|
||||
|
||||
static constexpr uint STACKED_CONCAT_UPPER_BOUND = 256; // argument limit for a merged concat.
|
||||
// The value 256 was derived by measuring
|
||||
@@ -286,6 +289,10 @@ void StringConcat::eliminate_unneeded_control() {
|
||||
|
||||
StringConcat* StringConcat::merge(StringConcat* other, Node* arg) {
|
||||
StringConcat* result = new StringConcat(_stringopts, _end);
|
||||
|
||||
Unique_Node_List null_check_ifs;
|
||||
Unique_Node_List skipped_phis;
|
||||
|
||||
for (uint x = 0; x < _control.size(); x++) {
|
||||
Node* n = _control.at(x);
|
||||
if (n->is_Call()) {
|
||||
@@ -311,6 +318,17 @@ StringConcat* StringConcat::merge(StringConcat* other, Node* arg) {
|
||||
result->append(other->argument(y), other->mode(y));
|
||||
}
|
||||
arguments_appended += other->num_arguments();
|
||||
// Cache elements for later verification.
|
||||
if (argument(x)->is_Phi()) {
|
||||
Node* phi = argument(x);
|
||||
assert(phi->as_Phi()->is_diamond_phi() > 0, "must be a diamond phi (ref. skip_string_null_check).");
|
||||
Node* iff = phi->in(0)->in(1)->in(0);
|
||||
Node* bol = iff->in(1);
|
||||
Node* cmpp = bol->as_Bool()->in(1);
|
||||
null_check_ifs.push(iff);
|
||||
skipped_phis.push(phi);
|
||||
result->_allowed_compares.push(cmpp);
|
||||
}
|
||||
} else {
|
||||
result->append(argx, mode(x));
|
||||
arguments_appended++;
|
||||
@@ -327,13 +345,55 @@ StringConcat* StringConcat::merge(StringConcat* other, Node* arg) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that the diamond region isn't shared with non-null check phis;
|
||||
// and that the associated bool doesn't have external uses.
|
||||
for (uint i = 0; i < skipped_phis.size(); i++) {
|
||||
Node* n = skipped_phis.at(i);
|
||||
Node* r = n->in(0);
|
||||
for (SimpleDUIterator j(r); j.has_next(); j.next()) {
|
||||
Node* n2 = j.get();
|
||||
if (n2->is_Phi() && !n2->is_memory_phi() && !skipped_phis.member(n2)) {
|
||||
#ifndef PRODUCT
|
||||
if (PrintOptimizeStringConcat) {
|
||||
tty->print_cr("null-check diamond region has external phi uses");
|
||||
}
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
Node* iff = n->in(0)->in(1)->in(0);
|
||||
Node* bol = iff->in(1);
|
||||
for (SimpleDUIterator j(bol); j.has_next(); j.next()) {
|
||||
if (!null_check_ifs.member(j.get())) {
|
||||
#ifndef PRODUCT
|
||||
if (PrintOptimizeStringConcat) {
|
||||
tty->print_cr("null-check diamond bool has external uses.");
|
||||
}
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result->set_allocation(other->_begin);
|
||||
for (uint i = 0; i < _constructors.size(); i++) {
|
||||
result->add_constructor(_constructors.at(i));
|
||||
}
|
||||
|
||||
for (uint i = 0; i < other->_constructors.size(); i++) {
|
||||
result->add_constructor(other->_constructors.at(i));
|
||||
}
|
||||
|
||||
// We add previous _allowed_compares in case of repeated stacked concatenation.
|
||||
for (uint i = 0; i < _allowed_compares.size(); i++) {
|
||||
result->_allowed_compares.push(_allowed_compares.at(i));
|
||||
}
|
||||
|
||||
for (uint i = 0; i < other->_allowed_compares.size(); i++) {
|
||||
result->_allowed_compares.push(other->_allowed_compares.at(i));
|
||||
}
|
||||
|
||||
result->_multiple = true;
|
||||
return result;
|
||||
}
|
||||
@@ -936,6 +996,10 @@ bool StringConcat::validate_control_flow() {
|
||||
int null_check_count = 0;
|
||||
Unique_Node_List ctrl_path;
|
||||
|
||||
// Local version of _allowed_compares that stores allowed comparisons discovered during traversal
|
||||
// but that we won't persist across merges.
|
||||
Unique_Node_List local_allowed_compares;
|
||||
|
||||
assert(_control.contains(_begin), "missing");
|
||||
assert(_control.contains(_end), "missing");
|
||||
|
||||
@@ -993,11 +1057,31 @@ bool StringConcat::validate_control_flow() {
|
||||
Node* v2 = cmp->in(2);
|
||||
Node* otherproj = iff->proj_out(1 - ptr->as_Proj()->_con);
|
||||
|
||||
// Null check of the return of append which can simply be eliminated
|
||||
// Either a null check of the return of append which can simply be eliminated,
|
||||
// or possibly of a toString during stacked concats.
|
||||
if (b->_test._test == BoolTest::ne &&
|
||||
v2->bottom_type() == TypePtr::NULL_PTR &&
|
||||
v1->is_Proj() && ctrl_path.member(v1->in(0))) {
|
||||
// null check of the return value of the append
|
||||
if (!is_SB_toString(v1->in(0))) {
|
||||
// append type
|
||||
assert(v1->in(0)->as_CallStaticJava()->method()->name() == ciSymbols::append_name(), "must be");
|
||||
local_allowed_compares.push(cmp);
|
||||
} else {
|
||||
// toString
|
||||
assert(_multiple, "if not _multiple, we should not have a toString on this control path");
|
||||
if (!_allowed_compares.member(cmp)) {
|
||||
// Should have been populated during merge if valid.
|
||||
// This should also be caught in result use verification later but we can fail early here.
|
||||
fail = true;
|
||||
#ifndef PRODUCT
|
||||
if (PrintOptimizeStringConcat) {
|
||||
tty->print_cr("Failing as toString()-dependent compare is not part of a recognized string null check.");
|
||||
cmp->dump();
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
null_check_count++;
|
||||
if (otherproj->outcnt() == 1) {
|
||||
CallStaticJavaNode* call = otherproj->unique_out()->isa_CallStaticJava();
|
||||
@@ -1022,6 +1106,8 @@ bool StringConcat::validate_control_flow() {
|
||||
((v1->is_Proj() && is_SB_toString(v1->in(0)) && ctrl_path.member(v1->in(0))) ||
|
||||
(v2->is_Proj() && is_SB_toString(v2->in(0)) && ctrl_path.member(v2->in(0))))) {
|
||||
// iftrue -> if -> bool -> cmpp -> resproj -> tostring
|
||||
assert(!_allowed_compares.member(cmp) && !local_allowed_compares.member(cmp), "Unsound dependency on intermediate values");
|
||||
// Would be caught by containment analysis later but we can fail early here.
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
@@ -1147,7 +1233,9 @@ bool StringConcat::validate_control_flow() {
|
||||
continue;
|
||||
}
|
||||
int opc = use->Opcode();
|
||||
if (opc == Op_CmpP || opc == Op_Node) {
|
||||
if (opc == Op_Node ||
|
||||
(opc == Op_CmpP && (use->outcnt() == 1) // The cmpp validation assumes a unique use.
|
||||
&& (local_allowed_compares.member(use) || _allowed_compares.member(use)))) {
|
||||
ctrl_path.push(use);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1359,7 +1359,7 @@ public class LWWindowPeer
|
||||
if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
focusLog.fine("ungrabbing on " + grabbingWindow);
|
||||
}
|
||||
// ungrab a simple window if its owner looses activation.
|
||||
// ungrab a simple window if its owner loses activation.
|
||||
grabbingWindow.ungrab();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 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
|
||||
@@ -101,8 +101,8 @@ struct _ImageSDOps
|
||||
CGDataProviderRef dataProvider;
|
||||
|
||||
// Pointer in memory that is used for create the CGBitmapContext and the CGDataProvider (used for imgRef). This is a native
|
||||
// copy of the pixels for the Image. There is a spearate copy of the pixels that lives in Java heap. There are two main
|
||||
// reasons why we keep those pixels spearate: 1) CG doesn't support all the Java pixel formats 2) The Garbage collector can
|
||||
// copy of the pixels for the Image. There is a separate copy of the pixels that lives in Java heap. There are two main
|
||||
// reasons why we keep those pixels separate: 1) CG doesn't support all the Java pixel formats 2) The Garbage collector can
|
||||
// move the java pixels at any time. There are possible workarounds for both problems. Number 2) seems to be a more serious issue, since
|
||||
// we can solve 1) by only supporting certain image types.
|
||||
void * nativePixels;
|
||||
|
||||
@@ -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
|
||||
@@ -1810,7 +1810,7 @@ public class PNGMetadata extends IIOMetadata implements Cloneable {
|
||||
* Latin-1 [ISO-8859-1] characters and spaces; that is, only
|
||||
* character codes 32-126 and 161-255 decimal are allowed.
|
||||
* For Latin-1 value fields the 0x10 (linefeed) control
|
||||
* character is aloowed too.
|
||||
* character is allowed too.
|
||||
*
|
||||
* See: http://www.w3.org/TR/PNG/#11keywords
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 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
|
||||
@@ -377,7 +377,7 @@ public abstract class TIFFDecompressor {
|
||||
/**
|
||||
* The width of the source region that will actually be copied
|
||||
* into the destination image, taking into account all
|
||||
* susbampling, offsetting, and clipping.
|
||||
* subsampling, offsetting, and clipping.
|
||||
*
|
||||
* <p> The active source width will always be equal to
|
||||
* {@code (dstWidth - 1)*subsampleX + 1}.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2013, 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
|
||||
@@ -26,7 +26,7 @@
|
||||
package com.sun.media.sound;
|
||||
|
||||
/**
|
||||
* This class is used to store modulator/artiuclation data.
|
||||
* This class is used to store modulator/articulation data.
|
||||
* A modulator connects one synthesizer source to
|
||||
* a destination. For example a note on velocity
|
||||
* can be mapped to the gain of the synthesized voice.
|
||||
|
||||
@@ -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
|
||||
@@ -1221,7 +1221,7 @@ public final class SoftSynthesizer implements AudioSynthesizer,
|
||||
// Always create external_channels array
|
||||
// with 16 or more channels
|
||||
// so getChannels works correctly
|
||||
// when the synhtesizer is closed.
|
||||
// when the synthesizer is closed.
|
||||
if (channels.length < 16)
|
||||
external_channels = new SoftChannelProxy[16];
|
||||
else
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 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
|
||||
@@ -48,7 +48,7 @@ public final class WaveFileReader extends SunFileReader {
|
||||
StandardFileFormat getAudioFileFormatImpl(final InputStream stream)
|
||||
throws UnsupportedAudioFileException, IOException {
|
||||
|
||||
// assumes sream is rewound
|
||||
// assumes stream is rewound
|
||||
|
||||
int nread = 0;
|
||||
int fmt;
|
||||
|
||||
@@ -908,7 +908,7 @@ public class Dialog extends Window {
|
||||
}
|
||||
|
||||
// This call is required as the show() method of the Dialog class
|
||||
// does not invoke the super.show(). So wried... :(
|
||||
// does not invoke the super.show(). So weird... :(
|
||||
mixOnShowing();
|
||||
|
||||
peer.setVisible(true); // now guaranteed never to block
|
||||
|
||||
@@ -417,7 +417,7 @@ public abstract class AbstractButton extends JComponent implements ItemSelectabl
|
||||
* the label.
|
||||
*
|
||||
* @return an <code>Insets</code> object specifying the margin
|
||||
* between the botton's border and the label
|
||||
* between the button's border and the label
|
||||
* @see #setMargin
|
||||
*/
|
||||
public Insets getMargin() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2023, 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
|
||||
@@ -534,7 +534,7 @@ public class ProgressMonitor implements Accessible
|
||||
* AccessibleJLabel
|
||||
* AccessibleJProgressBar
|
||||
*
|
||||
* The abstraction presented to assitive technologies by
|
||||
* The abstraction presented to assistive technologies by
|
||||
* the AccessibleProgressMonitor is that a dialog contains a
|
||||
* progress monitor with three children: a message, a note
|
||||
* label and a progress bar.
|
||||
|
||||
@@ -532,7 +532,7 @@ public class BasicComboBoxUI extends ComboBoxUI {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the default renderer that will be used in a non-editiable combo
|
||||
* Creates the default renderer that will be used in a non-editable combo
|
||||
* box. A default renderer will used only if a renderer has not been
|
||||
* explicitly set with <code>setRenderer</code>.
|
||||
*
|
||||
|
||||
@@ -747,7 +747,7 @@ public class BasicListUI extends ListUI
|
||||
/**
|
||||
* Unregisters keyboard actions installed from
|
||||
* <code>installKeyboardActions</code>.
|
||||
* This method is called at uninstallUI() time - subclassess should
|
||||
* This method is called at uninstallUI() time - subclasses should
|
||||
* ensure that all of the keyboard actions registered at installUI
|
||||
* time are removed here.
|
||||
*
|
||||
|
||||
@@ -105,7 +105,7 @@ public class SynthComboBoxUI extends BasicComboBoxUI implements
|
||||
private ButtonHandler buttonHandler;
|
||||
|
||||
/**
|
||||
* Handler for repainting combo when editor component gains/looses focus
|
||||
* Handler for repainting combo when editor component gains/loses focus
|
||||
*/
|
||||
private EditorFocusHandler editorFocusHandler;
|
||||
|
||||
@@ -766,7 +766,7 @@ public class SynthComboBoxUI extends BasicComboBoxUI implements
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for repainting combo when editor component gains/looses focus
|
||||
* Handler for repainting combo when editor component gains/loses focus
|
||||
*/
|
||||
private static class EditorFocusHandler implements FocusListener,
|
||||
PropertyChangeListener {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2024, 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
|
||||
@@ -3164,7 +3164,7 @@ public class StyleSheet extends StyleContext {
|
||||
|
||||
|
||||
/**
|
||||
* SelectorMapping contains a specifitiy, as an integer, and an associated
|
||||
* SelectorMapping contains a specificity, as an integer, and an associated
|
||||
* Style. It can also reference children <code>SelectorMapping</code>s,
|
||||
* so that it behaves like a tree.
|
||||
* <p>
|
||||
|
||||
@@ -30,7 +30,7 @@ import java.awt.Component;
|
||||
|
||||
/**
|
||||
* Sent when one of the following events occur on the grabbed window: <ul>
|
||||
* <li> it looses focus, but not to one of the owned windows
|
||||
* <li> it loses focus, but not to one of the owned windows
|
||||
* <li> mouse click on the outside area happens (except for one of the owned windows)
|
||||
* <li> switch to another application or desktop happens
|
||||
* <li> click in the non-client area of the owning window or this window happens
|
||||
|
||||
@@ -68,7 +68,7 @@ import sun.java2d.DisposerRecord;
|
||||
* The FontDesignMetrics class expresses font metrics in terms of arbitrary
|
||||
* <i>typographic units</i> (not points) chosen by the font supplier
|
||||
* and used in the underlying platform font representations. These units are
|
||||
* defined by dividing the em-square into a grid. The em-sqaure is the
|
||||
* defined by dividing the em-square into a grid. The em-square is the
|
||||
* theoretical square whose dimensions are the full body height of the
|
||||
* font. A typographic unit is the smallest measurable unit in the
|
||||
* em-square. The number of units-per-em is determined by the font
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2024, 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
|
||||
@@ -39,7 +39,7 @@ public class FontManagerNativeLibrary {
|
||||
top of freetype library (that is used in binary form).
|
||||
|
||||
This wrapper is compiled into fontmanager and this make
|
||||
fontmanger library depending on freetype library.
|
||||
font manager library depending on freetype library.
|
||||
|
||||
On Windows DLL's in the JRE's BIN directory cannot be
|
||||
found by windows DLL loading as that directory is not
|
||||
|
||||
@@ -2617,7 +2617,7 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE {
|
||||
* - family name is not the same as the full name of an installed font
|
||||
* - full name is not the same as the family name of an installed font
|
||||
* The last two of these may initially look odd but the reason is
|
||||
* that (unfortunately) Font constructors do not distinuguish these.
|
||||
* that (unfortunately) Font constructors do not distinguish these.
|
||||
* An extreme example of such a problem would be a font which has
|
||||
* family name "Dialog.Plain" and full name of "Dialog".
|
||||
* The one arguably overly stringent restriction here is that if an
|
||||
|
||||
@@ -75,7 +75,7 @@ public class DesktopProperty implements UIDefaults.ActiveValue {
|
||||
|
||||
|
||||
/**
|
||||
* Cleans up any lingering state held by unrefeernced
|
||||
* Cleans up any lingering state held by unreferenced
|
||||
* DesktopProperties.
|
||||
*/
|
||||
public static void flushUnreferencedProperties() {
|
||||
|
||||
@@ -519,7 +519,7 @@ static int GET_ARRAYS(JNIEnv *env, imageIODataPtr data, const JOCTET **next_byte
|
||||
/*
|
||||
* Set up error handling to use setjmp/longjmp. This is the third such
|
||||
* setup, as both the AWT jpeg decoder and the com.sun... JPEG classes
|
||||
* setup thier own. Ultimately these should be integrated, as they all
|
||||
* setup their own. Ultimately these should be integrated, as they all
|
||||
* do pretty much the same thing.
|
||||
*/
|
||||
|
||||
@@ -2358,7 +2358,7 @@ imageio_term_destination (j_compress_ptr cinfo)
|
||||
JNIEnv *env = (JNIEnv *)JNU_GetEnv(the_jvm, JNI_VERSION_1_2);
|
||||
|
||||
/* find out how much needs to be written */
|
||||
/* this conversion from size_t to jint is safe, because the lenght of the buffer is limited by jint */
|
||||
/* this conversion from size_t to jint is safe, because the length of the buffer is limited by jint */
|
||||
jint datacount = (jint)(sb->bufferLength - dest->free_in_buffer);
|
||||
|
||||
if (datacount != 0) {
|
||||
|
||||
@@ -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
|
||||
@@ -31,10 +31,10 @@ package sun.awt.X11;
|
||||
* Standard X Atom are defined by X11 and these atoms are defined in this class
|
||||
* for convenience. Common X Atoms like {@code XA_WM_NAME} are used to communicate with the
|
||||
* Window manager to let it know the Window name. The use and protocol for these
|
||||
* atoms are defined in the Inter client communications converntions manual.
|
||||
* atoms are defined in the Inter client communications conventions manual.
|
||||
* User specified XAtoms are defined by specifying a name that gets Interned
|
||||
* by the XServer and an {@code XAtom} object is returned. An {@code XAtom} can also be created
|
||||
* by using a pre-exisiting atom like {@code XA_WM_CLASS}. A {@code display} has to be specified
|
||||
* by using a pre-existing atom like {@code XA_WM_CLASS}. A {@code display} has to be specified
|
||||
* in order to create an {@code XAtom}. <p> <p>
|
||||
*
|
||||
* Once an {@code XAtom} instance is created, you can call get and set property methods to
|
||||
|
||||
@@ -485,7 +485,7 @@ public class TypeAnnotations {
|
||||
if (type.hasTag(TypeTag.ARRAY)) {
|
||||
ret = rewriteArrayType(typetree, (ArrayType)type, annotations, onlyTypeAnnotations, pos);
|
||||
} else if (type.hasTag(TypeTag.TYPEVAR)) {
|
||||
ret = type.annotatedType(onlyTypeAnnotations);
|
||||
ret = type.annotatedType(annotations);
|
||||
} else if (type.getKind() == TypeKind.UNION) {
|
||||
// There is a TypeKind, but no TypeTag.
|
||||
UnionClassType ut = (UnionClassType) type;
|
||||
|
||||
@@ -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
|
||||
@@ -167,10 +167,11 @@ public final class OngoingStream extends EventByteStream {
|
||||
byte[] bytes = new byte[Math.max(HEADER_SIZE, size)];
|
||||
for (int attempts = 0; attempts < 25; attempts++) {
|
||||
// read twice and check files state to avoid simultaneous change by JVM
|
||||
input.position(0);
|
||||
input.readFully(bytes, 0, HEADER_SIZE);
|
||||
input.position(0);
|
||||
input.readFully(headerBytes);
|
||||
input.positionPhysical(0);
|
||||
input.readPhysicalFully(bytes, 0, HEADER_SIZE);
|
||||
input.positionPhysical(0);
|
||||
input.readPhysicalFully(headerBytes, 0, HEADER_SIZE);
|
||||
input.position(HEADER_SIZE);
|
||||
if (bytes[HEADER_FILE_STATE_POSITION] != MODIFYING_STATE) {
|
||||
if (bytes[HEADER_FILE_STATE_POSITION] == headerBytes[HEADER_FILE_STATE_POSITION]) {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2025, 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
|
||||
@@ -110,6 +110,10 @@ public final class RecordingInput implements DataInput, AutoCloseable {
|
||||
return file.readLong();
|
||||
}
|
||||
|
||||
void readPhysicalFully(byte[] dest, int offset, int length) throws IOException {
|
||||
file.readFully(dest, offset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final byte readByte() throws IOException {
|
||||
if (!currentBlock.contains(position)) {
|
||||
|
||||
+5
-5
@@ -21,7 +21,7 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package compiler.c2;
|
||||
package compiler.escapeAnalysis;
|
||||
|
||||
/*
|
||||
* @test
|
||||
@@ -29,12 +29,12 @@ package compiler.c2;
|
||||
* @summary Test case where we had escape analysis tell us that we can possibly eliminate
|
||||
* the array allocation, then MergeStores introduces a mismatched store, which
|
||||
* the actual elimination does not verify for. That led to wrong results.
|
||||
* @run main/othervm -XX:CompileCommand=compileonly,compiler.c2.TestMergeStoresAndAllocationElimination::test
|
||||
* -XX:CompileCommand=exclude,compiler.c2.TestMergeStoresAndAllocationElimination::dontinline
|
||||
* @run main/othervm -XX:CompileCommand=compileonly,compiler.escapeAnalysis.TestMergeStoresAndAllocationElimination::test
|
||||
* -XX:CompileCommand=exclude,compiler.escapeAnalysis.TestMergeStoresAndAllocationElimination::dontinline
|
||||
* -XX:-TieredCompilation -Xbatch
|
||||
* -XX:+IgnoreUnrecognizedVMOptions -XX:-CICompileOSR
|
||||
* compiler.c2.TestMergeStoresAndAllocationElimination
|
||||
* @run main compiler.c2.TestMergeStoresAndAllocationElimination
|
||||
* compiler.escapeAnalysis.TestMergeStoresAndAllocationElimination
|
||||
* @run main compiler.escapeAnalysis.TestMergeStoresAndAllocationElimination
|
||||
*/
|
||||
|
||||
public class TestMergeStoresAndAllocationElimination {
|
||||
+4
-4
@@ -27,10 +27,10 @@
|
||||
* @summary Check that the JVM is able to dump the heap even when there are ReduceAllocationMerge in the scope.
|
||||
* @library /test/lib /
|
||||
* @requires vm.flavor == "server"
|
||||
* @run main/othervm compiler.c2.TestReduceAllocationAndHeapDump
|
||||
* @run main/othervm compiler.escapeAnalysis.TestReduceAllocationAndHeapDump
|
||||
*/
|
||||
|
||||
package compiler.c2;
|
||||
package compiler.escapeAnalysis;
|
||||
|
||||
import java.io.File;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
@@ -49,8 +49,8 @@ public class TestReduceAllocationAndHeapDump {
|
||||
"-XX:CompileThresholdScaling=0.01",
|
||||
"-XX:+HeapDumpAfterFullGC",
|
||||
"-XX:HeapDumpPath=" + dumpDirectory.getAbsolutePath(),
|
||||
"-XX:CompileCommand=compileonly,compiler.c2.HeapDumper::testIt",
|
||||
"-XX:CompileCommand=exclude,compiler.c2.HeapDumper::dummy",
|
||||
"-XX:CompileCommand=compileonly,compiler.escapeAnalysis.HeapDumper::testIt",
|
||||
"-XX:CompileCommand=exclude,compiler.escapeAnalysis.HeapDumper::dummy",
|
||||
HeapDumper.class.getName()
|
||||
};
|
||||
|
||||
+2
-2
@@ -29,10 +29,10 @@
|
||||
* @requires vm.compiler2.enabled
|
||||
* @run main/othervm -XX:CompileCommand=compileonly,*TestReduceAllocationAndMemoryLoop*::test*
|
||||
* -XX:-TieredCompilation -Xbatch
|
||||
* compiler.c2.TestReduceAllocationAndMemoryLoop
|
||||
* compiler.escapeAnalysis.TestReduceAllocationAndMemoryLoop
|
||||
*/
|
||||
|
||||
package compiler.c2;
|
||||
package compiler.escapeAnalysis;
|
||||
|
||||
public class TestReduceAllocationAndMemoryLoop {
|
||||
public static void main(String[] args) throws Exception {
|
||||
+2
-2
@@ -35,10 +35,10 @@
|
||||
* -XX:-TieredCompilation
|
||||
* -Xbatch
|
||||
* -Xcomp
|
||||
* compiler.c2.TestReduceAllocationAndNonExactAllocate
|
||||
* compiler.escapeAnalysis.TestReduceAllocationAndNonExactAllocate
|
||||
*/
|
||||
|
||||
package compiler.c2;
|
||||
package compiler.escapeAnalysis;
|
||||
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
+2
-2
@@ -31,10 +31,10 @@
|
||||
* @run main/othervm -XX:CompileCommand=compileonly,*TestReduceAllocationAndNullableLoads*::*
|
||||
* -XX:CompileCommand=dontinline,*TestReduceAllocationAndNullableLoads*::*
|
||||
* -XX:-TieredCompilation -Xcomp
|
||||
* compiler.c2.TestReduceAllocationAndNullableLoads
|
||||
* compiler.escapeAnalysis.TestReduceAllocationAndNullableLoads
|
||||
*/
|
||||
|
||||
package compiler.c2;
|
||||
package compiler.escapeAnalysis;
|
||||
|
||||
public class TestReduceAllocationAndNullableLoads {
|
||||
public static void main(String[] args) {
|
||||
+3
-3
@@ -29,11 +29,11 @@
|
||||
* @run main/othervm -XX:CompileCommand=compileonly,*TestReduceAllocationAndPointerComparisons*::*
|
||||
* -XX:CompileCommand=dontinline,*TestReduceAllocationAndPointerComparisons*::*
|
||||
* -XX:-TieredCompilation -Xcomp
|
||||
* compiler.c2.TestReduceAllocationAndPointerComparisons
|
||||
* @run main compiler.c2.TestReduceAllocationAndPointerComparisons
|
||||
* compiler.escapeAnalysis.TestReduceAllocationAndPointerComparisons
|
||||
* @run main compiler.escapeAnalysis.TestReduceAllocationAndPointerComparisons
|
||||
*/
|
||||
|
||||
package compiler.c2;
|
||||
package compiler.escapeAnalysis;
|
||||
|
||||
public class TestReduceAllocationAndPointerComparisons {
|
||||
public static void main(String[] args) {
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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 8389873
|
||||
* @summary Check that Reduce Allocation Merges correctly handle the situation
|
||||
* where the Phi was optimized out by IGVN during CG construction.
|
||||
* @run main/othervm -XX:CompileCommand=compileonly,*${test.main.class}*::*
|
||||
* -Xcomp -XX:-TieredCompilation ${test.main.class}
|
||||
* @run main ${test.main.class}
|
||||
*/
|
||||
|
||||
package compiler.escapeAnalysis;
|
||||
|
||||
public class TestReduceAllocationOptimizedOutPhi {
|
||||
static int var_369;
|
||||
|
||||
public static void main(String[] args) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
|
||||
static void test() {
|
||||
switch (new Foo().var_2) {
|
||||
case 3:
|
||||
var_369 = (1.0002043F == new Foo().var_2 ? new Bar() : new Bar()).var_151;
|
||||
var_369 = 4;
|
||||
}
|
||||
for (short var_480 = 0; var_480 < 1; var_480++) {
|
||||
var_369 = new Bar().var_151;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
long var_1 = 9;
|
||||
char var_2 = 'B';
|
||||
|
||||
Foo() {
|
||||
int var_121 = 9;
|
||||
for (var_121 = 9; var_121 >= 0; var_121--) {
|
||||
double var_122 = 2.2250738585072014E-308 - (Integer) 0;
|
||||
float var_123 = '@' * (Integer) (Byte.valueOf((byte) 9) * var_121);
|
||||
}
|
||||
long var_124 = (Float.intBitsToFloat(608) == '(' ? 7L : 5);
|
||||
byte var_127 = 5;
|
||||
for (var_127 = 55; var_127 >= 0; var_127--) {
|
||||
if (370 <= -Byte.valueOf((byte) 14)) {
|
||||
long var_131 = 71L + (Integer) (-Character.valueOf('d'));
|
||||
++var_131;
|
||||
var_131--;
|
||||
var_131 >>>= var_131;
|
||||
}
|
||||
}
|
||||
byte var_132 = 0;
|
||||
for (var_132 = 0; var_132 < 6; var_132++) {
|
||||
byte var_134 = ++var_127;
|
||||
short var_135 = 2046;
|
||||
double var_136 = -var_132 < 0.18568599F ? 0.44624205067529954 * Long.valueOf(1048575) + '~' : Short.valueOf((short) 4085);
|
||||
byte var_137 = 3;
|
||||
double var_138 = -Integer.valueOf(6) - 0.9994681372166424 * Long.valueOf(3) + (Integer) (+Short.valueOf((short) 512));
|
||||
int var_141 = (Integer) (Byte.valueOf((byte) 7) * Character.valueOf('U')) - 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Bar {
|
||||
Byte var_151 = 3;
|
||||
}
|
||||
|
||||
+3
-3
@@ -26,10 +26,10 @@
|
||||
* @bug 8361140
|
||||
* @summary Test ConnectionGraph::reduce_phi_on_cmp when OptimizePtrCompare is disabled
|
||||
* @library /test/lib /
|
||||
* @run driver compiler.c2.TestReducePhiOnCmpWithNoOptPtrCompare
|
||||
* @run driver compiler.escapeAnalysis.TestReducePhiOnCmpWithNoOptPtrCompare
|
||||
*/
|
||||
|
||||
package compiler.c2;
|
||||
package compiler.escapeAnalysis;
|
||||
|
||||
import java.util.Random;
|
||||
import jdk.test.lib.Asserts;
|
||||
@@ -87,4 +87,4 @@ public class TestReducePhiOnCmpWithNoOptPtrCompare {
|
||||
return (p.x == x) && (p.y == y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -28,10 +28,10 @@
|
||||
* @library /test/lib /
|
||||
* @requires vm.debug & vm.compiler2.enabled
|
||||
* @compile -XDstringConcat=inline TestScalarReplacementMaxLiveNodes.java
|
||||
* @run main/othervm/timeout=480 compiler.c2.TestScalarReplacementMaxLiveNodes
|
||||
* @run main/othervm/timeout=480 compiler.escapeAnalysis.TestScalarReplacementMaxLiveNodes
|
||||
* @run main/othervm/timeout=480 -Xbatch -XX:-OptimizeStringConcat -XX:-TieredCompilation
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+ReduceAllocationMerges
|
||||
* -XX:CompileCommand=dontinline,compiler.c2.TestScalarReplacementMaxLiveNodes::test
|
||||
* -XX:CompileCommand=dontinline,compiler.escapeAnalysis.TestScalarReplacementMaxLiveNodes::test
|
||||
* -XX:CompileCommand=compileonly,*TestScalarReplacementMaxLiveNodes*::*test*
|
||||
* -XX:CompileCommand=inline,*String*::*
|
||||
* -XX:CompileCommand=dontinline,*StringBuilder*::ensureCapacityInternal
|
||||
@@ -39,9 +39,9 @@
|
||||
* -XX:NodeCountInliningCutoff=220000
|
||||
* -XX:DesiredMethodLimit=100000
|
||||
* -XX:+IgnoreUnrecognizedVMOptions -XX:CompileTaskTimeout=0
|
||||
* compiler.c2.TestScalarReplacementMaxLiveNodes
|
||||
* compiler.escapeAnalysis.TestScalarReplacementMaxLiveNodes
|
||||
*/
|
||||
package compiler.c2;
|
||||
package compiler.escapeAnalysis;
|
||||
|
||||
public class TestScalarReplacementMaxLiveNodes {
|
||||
public static void main(String[] args) {
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2026 IBM Corporation. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8390467
|
||||
* @summary C2: _map != nullptr assert failure in LibraryCallKit::inline_Class_cast()
|
||||
* @run main/othervm -XX:CompileOnly=${test.main.class}::test1 -Xcomp ${test.main.class}
|
||||
*/
|
||||
|
||||
package compiler.intrinsics;
|
||||
|
||||
public class TestClassCastDeadPath {
|
||||
public static void main(String[] args) {
|
||||
B b = new B();
|
||||
C c = new C();
|
||||
A.class.cast(b);
|
||||
try {
|
||||
test1(c);
|
||||
} catch (ClassCastException cce) {
|
||||
}
|
||||
}
|
||||
|
||||
private static void test1(Object o) {
|
||||
if (!(o instanceof I)) {
|
||||
throw new RuntimeException("never taken");
|
||||
}
|
||||
A.class.cast(o);
|
||||
}
|
||||
|
||||
static abstract class A {
|
||||
|
||||
}
|
||||
|
||||
static class B extends A {
|
||||
|
||||
}
|
||||
|
||||
interface I {
|
||||
|
||||
}
|
||||
|
||||
static class C implements I {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,6 +36,8 @@ import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -49,12 +51,15 @@ import java.util.regex.Pattern;
|
||||
* @see TestFrameworkSocket
|
||||
*/
|
||||
public class TestVMProcess {
|
||||
private static final boolean VERBOSE = Boolean.getBoolean("Verbose");
|
||||
private static final boolean PREFER_COMMAND_LINE_FLAGS = Boolean.getBoolean("PreferCommandLineFlags");
|
||||
private static final int WARMUP_ITERATIONS = Integer.getInteger("Warmup", -1);
|
||||
private static final boolean VERIFY_VM = Boolean.getBoolean("VerifyVM") && Platform.isDebugBuild();
|
||||
private static final boolean REPORT_STDOUT = Boolean.getBoolean("ReportStdout");
|
||||
private static final boolean VERBOSE = Boolean.getBoolean("Verbose");
|
||||
private static final boolean EXCLUDE_RANDOM = Boolean.getBoolean("ExcludeRandom");
|
||||
private static final boolean REPORT_STDOUT = Boolean.getBoolean("ReportStdout");
|
||||
private static final boolean DUMP_OUTPUT = VERBOSE || EXCLUDE_RANDOM || REPORT_STDOUT;
|
||||
|
||||
private static final String FATAL_ERROR_MARKER = "# A fatal error has been detected by the Java Runtime Environment:";
|
||||
|
||||
private static String lastTestVMOutput = "";
|
||||
|
||||
@@ -72,11 +77,131 @@ public class TestVMProcess {
|
||||
prepareTestVMFlags(additionalFlags, socket, testClass, helperClasses, defaultWarmup,
|
||||
allowNotCompilable, testClassesOnBootClassPath);
|
||||
start();
|
||||
// Test VM has exited. Do not close the socket, yet, because the accept and/or reader threads could still
|
||||
// be processing its connection. We wait for the socket result and only then close the socket by leaving
|
||||
// this scope.
|
||||
testVmData = processTestVmResult(socket, allowNotCompilable);
|
||||
} // Socket closed here.
|
||||
}
|
||||
|
||||
private TestVMData processTestVmResult(TestFrameworkSocket socket, boolean allowNotCompilable) {
|
||||
if (oa.getExitValue() == 0) {
|
||||
dumpTestVmOutputIfRequested();
|
||||
return readAndDumpTestVmData(socket, allowNotCompilable);
|
||||
}
|
||||
checkTestVMExitCode();
|
||||
|
||||
if (isTestFormatViolation()) {
|
||||
// When a test is malformed, we only show the violation. This kind of failure should be caught during the
|
||||
// development phase of new tests.
|
||||
dumpTestVmOutputIfRequested();
|
||||
throw createTestFormatException();
|
||||
}
|
||||
if (noTestsRun()) {
|
||||
// If no test was selected, we just show the exception message. This kind of failure only happens during
|
||||
// debugging when specifying an empty test set with property flags.
|
||||
dumpTestVmOutputIfRequested();
|
||||
throw createNoTestsRunException();
|
||||
}
|
||||
throw createTestVMExceptionForNonZeroExit(socket, allowNotCompilable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the Test VM output if flags request it.
|
||||
*/
|
||||
private void dumpTestVmOutputIfRequested() {
|
||||
if (DUMP_OUTPUT) {
|
||||
System.out.println("Test VM Output");
|
||||
System.out.println("--------------");
|
||||
System.out.println(oa.getOutput());
|
||||
}
|
||||
}
|
||||
|
||||
private TestVMData readAndDumpTestVmData(TestFrameworkSocket socket, boolean allowNotCompilable) {
|
||||
String hotspotPidFileName = String.format("hotspot_pid%d.log", oa.pid());
|
||||
testVmData = socket.testVmData(hotspotPidFileName, allowNotCompilable);
|
||||
testVmData.printJavaMessages();
|
||||
TestVMData testVMData = socket.testVmData(hotspotPidFileName, allowNotCompilable);
|
||||
testVMData.printJavaMessages();
|
||||
return testVMData;
|
||||
}
|
||||
|
||||
private boolean isTestFormatViolation() {
|
||||
return oa.getStderr().contains("TestFormat.throwIfAnyFailures");
|
||||
}
|
||||
|
||||
private TestFormatException createTestFormatException() {
|
||||
Pattern pattern = Pattern.compile("Violations \\(\\d+\\)[\\s\\S]*(?=/============/)");
|
||||
Matcher matcher = pattern.matcher(oa.getStderr());
|
||||
TestFramework.check(matcher.find(), "Must find violation matches");
|
||||
return new TestFormatException(System.lineSeparator() + System.lineSeparator() + matcher.group());
|
||||
}
|
||||
|
||||
private boolean noTestsRun() {
|
||||
return oa.getStderr().contains("NoTestsRunException");
|
||||
}
|
||||
|
||||
private NoTestsRunException createNoTestsRunException() {
|
||||
return new NoTestsRunException(">>> No tests run due to empty set specified with -DTest and/or -DExclude. " +
|
||||
"Make sure to define a set of at least one @Test method");
|
||||
}
|
||||
|
||||
private TestVMException createTestVMExceptionForNonZeroExit(TestFrameworkSocket socket, boolean allowNotCompilable) {
|
||||
String secondaryException = "";
|
||||
try {
|
||||
readAndDumpTestVmData(socket, allowNotCompilable);
|
||||
} catch (RuntimeException e) {
|
||||
// We observed a message processing exception. We treat it as secondary failure because messages could be
|
||||
// incomplete when the VM crashed or not even sent by the Test VM when it exits early on start-up
|
||||
// (e.g. passing in an unknown VM flag).
|
||||
secondaryException = buildSecondaryExceptionInfo(e);
|
||||
}
|
||||
// Primary exception: non-zero Test VM exit.
|
||||
return new TestVMException(buildExceptionInfo() + secondaryException);
|
||||
}
|
||||
|
||||
private String buildSecondaryExceptionInfo(RuntimeException e) {
|
||||
String secondaryException;
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(stringWriter));
|
||||
|
||||
secondaryException = System.lineSeparator() +
|
||||
"Secondary Message-Processing Exception" + System.lineSeparator() +
|
||||
"--------------------------------------" + System.lineSeparator() +
|
||||
stringWriter;
|
||||
return secondaryException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get more detailed information about the exception in a pretty format.
|
||||
*/
|
||||
private String buildExceptionInfo() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("Test VM exited with code ").append(oa.getExitValue()).append(System.lineSeparator());
|
||||
if (hasFatalErrorMarker() || DUMP_OUTPUT) {
|
||||
// Also dump the Test VM output if we experience a JVM error to show assertion failures etc.
|
||||
builder.append(System.lineSeparator())
|
||||
.append(System.lineSeparator())
|
||||
.append("Test VM - Standard Output").append(System.lineSeparator())
|
||||
.append("-------------------------").append(System.lineSeparator())
|
||||
.append(oa.getStdout());
|
||||
}
|
||||
builder.append(System.lineSeparator())
|
||||
.append(commandLine)
|
||||
.append(System.lineSeparator())
|
||||
.append(System.lineSeparator())
|
||||
.append("Test VM - Error Output").append(System.lineSeparator())
|
||||
.append("----------------------").append(System.lineSeparator())
|
||||
.append(oa.getStderr())
|
||||
.append(System.lineSeparator())
|
||||
.append(System.lineSeparator());
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Best-effort VM crash detection by matching the start of the fatal error message. This covers most of the crashes
|
||||
* but fails when the Test VM was killed externally or when the output is unavailable or truncated which could
|
||||
* happen in native stack overflow cases.
|
||||
*/
|
||||
private boolean hasFatalErrorMarker() {
|
||||
return oa.getExitValue() != 0 && oa.getOutput().contains(FATAL_ERROR_MARKER);
|
||||
}
|
||||
|
||||
public String getCommandLine() {
|
||||
@@ -173,55 +298,4 @@ public class TestVMProcess {
|
||||
+ System.lineSeparator();
|
||||
lastTestVMOutput = oa.getOutput();
|
||||
}
|
||||
|
||||
private void checkTestVMExitCode() {
|
||||
final int exitCode = oa.getExitValue();
|
||||
if (EXCLUDE_RANDOM || REPORT_STDOUT || (VERBOSE && exitCode == 0)) {
|
||||
System.out.println("--- OUTPUT TestFramework Test VM ---");
|
||||
System.out.println(oa.getOutput());
|
||||
}
|
||||
|
||||
if (exitCode != 0) {
|
||||
throwTestVMException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit code was non-zero of Test VM. Check the stderr to determine what kind of exception that should be thrown to
|
||||
* react accordingly later.
|
||||
*/
|
||||
private void throwTestVMException() {
|
||||
String stdErr = oa.getStderr();
|
||||
if (stdErr.contains("TestFormat.throwIfAnyFailures")) {
|
||||
Pattern pattern = Pattern.compile("Violations \\(\\d+\\)[\\s\\S]*(?=/============/)");
|
||||
Matcher matcher = pattern.matcher(stdErr);
|
||||
TestFramework.check(matcher.find(), "Must find violation matches");
|
||||
throw new TestFormatException(System.lineSeparator() + System.lineSeparator() + matcher.group());
|
||||
} else if (stdErr.contains("NoTestsRunException")) {
|
||||
throw new NoTestsRunException(">>> No tests run due to empty set specified with -DTest and/or -DExclude. " +
|
||||
"Make sure to define a set of at least one @Test method");
|
||||
} else {
|
||||
throw new TestVMException(getExceptionInfo());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get more detailed information about the exception in a pretty format.
|
||||
*/
|
||||
private String getExceptionInfo() {
|
||||
int exitCode = oa.getExitValue();
|
||||
String stdErr = oa.getStderr();
|
||||
String stdOut = "";
|
||||
boolean osIsWindows = Platform.isWindows();
|
||||
boolean JVMHadError = (!osIsWindows && exitCode == 134) || (osIsWindows && exitCode == -1);
|
||||
if (JVMHadError) {
|
||||
// Also dump the stdout if we experience a JVM error (e.g. to show hit assertions etc.).
|
||||
stdOut = System.lineSeparator() + System.lineSeparator() + "Standard Output" + System.lineSeparator()
|
||||
+ "---------------" + System.lineSeparator() + oa.getOutput();
|
||||
}
|
||||
return "TestFramework Test VM exited with code " + exitCode + System.lineSeparator() + stdOut
|
||||
+ System.lineSeparator() + commandLine + System.lineSeparator() + System.lineSeparator()
|
||||
+ "Error Output" + System.lineSeparator() + "------------" + System.lineSeparator() + stdErr
|
||||
+ System.lineSeparator() + System.lineSeparator();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ import compiler.lib.ir_framework.driver.network.testvm.java.JavaMessageParser;
|
||||
import compiler.lib.ir_framework.driver.network.testvm.java.JavaMessages;
|
||||
import compiler.lib.ir_framework.test.network.TestVmSocket;
|
||||
|
||||
import jdk.test.lib.Utils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
@@ -41,16 +43,36 @@ import java.util.concurrent.*;
|
||||
*/
|
||||
public class TestFrameworkSocket implements AutoCloseable {
|
||||
private static final String SERVER_PORT_PROPERTY = "ir.framework.server.port";
|
||||
private static final int SOCKET_TIMEOUT_IN_MS = (int)Utils.adjustTimeout(10_000L);
|
||||
|
||||
private final int serverSocketPort;
|
||||
private final ServerSocket serverSocket;
|
||||
private final ExecutorService acceptExecutor;
|
||||
private final ExecutorService clientExecutor;
|
||||
|
||||
// Make these volatile such that the main thread can observe an update written by the worker threads in the executor
|
||||
// services to avoid stale values.
|
||||
/*
|
||||
* CompletableFuture shared by the Driver VM and the accept/reader threads.
|
||||
*
|
||||
* Lifecycle:
|
||||
* 1. The future is created before the accept loop task is submitted.
|
||||
* 2. The Driver VM starts the Test VM. The socket and the executors remain open while the Driver VM waits on the
|
||||
* future to be completed.
|
||||
* 3. The accept thread accepts the Test VM connection and reads the identity handshake.
|
||||
* 4. The accept thread now schedules a reader for incoming Test VM messages.
|
||||
* 5. During normal execution, the Test VM closes the connection before exiting. The reader completes the future
|
||||
* with the parsed Test VM messages.
|
||||
* 6. Accepting, identity handshake, task submission, or message reading failures complete the future exceptionally.
|
||||
* 7. The Driver VM obtains the result, observes a failure, or times out before the socket and executors are closed.
|
||||
*
|
||||
* Note: The future must be created eagerly such that the Driver VM can wait on it even before the accept thread
|
||||
* has accepted the Test VM connection. The accept thread might only be scheduled after the Test VM has exited.
|
||||
* This is possible because the server socket is already listening and the OS can queue the connection until
|
||||
* the accept thread processes it.
|
||||
*/
|
||||
private final CompletableFuture<JavaMessages> javaMessagesFuture;
|
||||
|
||||
// Written by the Driver VM thread and read by the accept thread.
|
||||
private volatile boolean running;
|
||||
private volatile Future<JavaMessages> javaFuture;
|
||||
|
||||
public TestFrameworkSocket() {
|
||||
try {
|
||||
@@ -62,6 +84,7 @@ public class TestFrameworkSocket implements AutoCloseable {
|
||||
serverSocketPort = serverSocket.getLocalPort();
|
||||
acceptExecutor = Executors.newSingleThreadExecutor();
|
||||
clientExecutor = Executors.newCachedThreadPool();
|
||||
javaMessagesFuture = new CompletableFuture<>();
|
||||
if (TestFramework.VERBOSE) {
|
||||
System.out.println("TestFramework server socket uses port " + serverSocketPort);
|
||||
}
|
||||
@@ -73,50 +96,40 @@ public class TestFrameworkSocket implements AutoCloseable {
|
||||
|
||||
public void start() {
|
||||
running = true;
|
||||
CountDownLatch calledAcceptLoopLatch = new CountDownLatch(1);
|
||||
startAcceptLoop(calledAcceptLoopLatch);
|
||||
}
|
||||
|
||||
private void startAcceptLoop(CountDownLatch calledAcceptLoopLatch) {
|
||||
acceptExecutor.submit(() -> acceptLoop(calledAcceptLoopLatch));
|
||||
waitUntilAcceptLoopRuns(calledAcceptLoopLatch);
|
||||
}
|
||||
|
||||
private void waitUntilAcceptLoopRuns(CountDownLatch calledAcceptLoopLatch) {
|
||||
try {
|
||||
if (!calledAcceptLoopLatch.await(10, TimeUnit.SECONDS)) {
|
||||
throw new IllegalStateException("acceptLoop did not start in time");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new TestFrameworkException("Could not start TestFrameworkSocket", e);
|
||||
}
|
||||
acceptExecutor.submit(this::acceptLoop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main loop to wait for new client connections and handling them upon connection request.
|
||||
*/
|
||||
private void acceptLoop(CountDownLatch calledAcceptLoopLatch) {
|
||||
calledAcceptLoopLatch.countDown();
|
||||
private void acceptLoop() {
|
||||
while (running) {
|
||||
try {
|
||||
acceptNewClientConnection();
|
||||
} catch (SocketException e) {
|
||||
} catch (SocketException e) {
|
||||
if (!running || serverSocket.isClosed()) {
|
||||
// Normal shutdown
|
||||
return;
|
||||
}
|
||||
running = false;
|
||||
throw new TestFrameworkException("Server socket error", e);
|
||||
throwServerSocketError(e);
|
||||
} catch (TestFrameworkException e) {
|
||||
running = false;
|
||||
throw e;
|
||||
throwTestFrameworkException(e);
|
||||
} catch (Exception e) {
|
||||
running = false;
|
||||
throw new TestFrameworkException("Server socket error", e);
|
||||
throwServerSocketError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void throwServerSocketError(Exception e) {
|
||||
throwTestFrameworkException(new TestFrameworkException("Server socket error", e));
|
||||
}
|
||||
|
||||
private void throwTestFrameworkException(TestFrameworkException testFrameworkException) {
|
||||
running = false;
|
||||
javaMessagesFuture.completeExceptionally(testFrameworkException);
|
||||
throw testFrameworkException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept new client connection by first reading the identity of the connection (either coming from Java or C2)
|
||||
* and then submitting a task accordingly to manage incoming messages on that connection/socket.
|
||||
@@ -137,11 +150,11 @@ public class TestFrameworkSocket implements AutoCloseable {
|
||||
private String readIdentity(Socket client, BufferedReader reader) throws IOException {
|
||||
String identity;
|
||||
try {
|
||||
client.setSoTimeout(10000);
|
||||
client.setSoTimeout(SOCKET_TIMEOUT_IN_MS);
|
||||
identity = reader.readLine();
|
||||
TestFramework.check(identity != null, "end of stream has been reached without reading the identity");
|
||||
} catch (SocketTimeoutException e) {
|
||||
throw new TestFrameworkException("Did not receive initial identity message after 10s", e);
|
||||
throw new TestFrameworkException("Timed out while waiting for initial identity message", e);
|
||||
} finally {
|
||||
client.setSoTimeout(0);
|
||||
}
|
||||
@@ -154,7 +167,9 @@ public class TestFrameworkSocket implements AutoCloseable {
|
||||
*/
|
||||
private void submitTask(String identity, Socket client, BufferedReader reader) {
|
||||
if (identity.equals(TestVmSocket.IDENTITY)) {
|
||||
javaFuture = clientExecutor.submit(new TestVmMessageReader<>(client, reader, new JavaMessageParser()));
|
||||
TestVmMessageReader<JavaMessages> messageReader =
|
||||
new TestVmMessageReader<>(client, reader, new JavaMessageParser());
|
||||
javaMessagesFuture.completeAsync(messageReader::call, clientExecutor);
|
||||
} else {
|
||||
throw new TestFrameworkException("Unrecognized identity: " + identity);
|
||||
}
|
||||
@@ -179,9 +194,26 @@ public class TestFrameworkSocket implements AutoCloseable {
|
||||
|
||||
private JavaMessages testVmMessages() {
|
||||
try {
|
||||
return javaFuture.get();
|
||||
// Note: The Test VM may have already exited while the accept and message reader thread are still processing
|
||||
// the connection. Let's wait until they are finished.
|
||||
return javaMessagesFuture.get(SOCKET_TIMEOUT_IN_MS, TimeUnit.MILLISECONDS);
|
||||
} catch (ExecutionException e) {
|
||||
throw new TestFrameworkException("No test VM messages were received", e);
|
||||
} catch (TimeoutException e) {
|
||||
throw new RuntimeException("Timed out while waiting for Test VM messages." + System.lineSeparator() +
|
||||
System.lineSeparator() +
|
||||
"Did any of the following happen?" + System.lineSeparator() +
|
||||
"(1) TestFramework.addFlags(-DReproduce=true)" + System.lineSeparator() +
|
||||
"(2) TestFramework.addFlags(--version) or any other VM flag that prevents " +
|
||||
" TestVM.main() from being called?" + System.lineSeparator() +
|
||||
"(3) The Test VM crashed before calling TestVM.main()" + System.lineSeparator() +
|
||||
System.lineSeparator() +
|
||||
"(1) and (2) are unsupported and are expected to fail." + System.lineSeparator() +
|
||||
"-> Please change your test!" + System.lineSeparator() +
|
||||
"(3) The IR Framework cannot handle early VM crashes." + System.lineSeparator() +
|
||||
"-> Please change your test if such a crash was anticipated!" +
|
||||
System.lineSeparator() + System.lineSeparator() +
|
||||
"In all other cases, please file an IR Framework bug!", e);
|
||||
} catch (Exception e) {
|
||||
throw new TestFrameworkException("Error while fetching Test VM Future", e);
|
||||
}
|
||||
|
||||
@@ -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,13 +23,15 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8356246
|
||||
* @bug 8356246 8362117
|
||||
* @summary Test stacked string concatenations where the toString of the first StringBuilder
|
||||
* is used as a shared test by two diamond Ifs in the second StringBuilder.
|
||||
* @run main/othervm compiler.stringopts.TestStackedConcatsSharedTest
|
||||
* @run main/othervm -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=compiler.stringopts.TestStackedConcatsSharedTest::*
|
||||
* compiler.stringopts.TestStackedConcatsSharedTest
|
||||
* (f): make sure we don't crash outright
|
||||
* (g): external null checks depending on the same test/removed call should not give a wrong result.
|
||||
* (h): multiple phis attached to the same diamond region; only one is a proper null check phi.
|
||||
* (i): non-null check phi reused after intermediate stacked concat: check for correct result
|
||||
* @run main/othervm ${test.main.class}
|
||||
* @run main/othervm -XX:-TieredCompilation -Xcomp -XX:CompileOnly=${test.main.class}::* ${test.main.class}
|
||||
*/
|
||||
|
||||
package compiler.stringopts;
|
||||
@@ -42,6 +44,21 @@ public class TestStackedConcatsSharedTest {
|
||||
if (!s.equals("")) {
|
||||
throw new RuntimeException("wrong result");
|
||||
}
|
||||
s = g();
|
||||
if (!s.equals("abcabcabc")) {
|
||||
System.out.println(s);
|
||||
throw new RuntimeException("wrong result");
|
||||
}
|
||||
s = h();
|
||||
if (!s.equals("abcabcnotnull")) {
|
||||
System.out.println(s);
|
||||
throw new RuntimeException("wrong result");
|
||||
}
|
||||
s = i();
|
||||
if (!s.equals("abcabcnotnull")) {
|
||||
System.out.println(s);
|
||||
throw new RuntimeException("wrong result");
|
||||
}
|
||||
}
|
||||
|
||||
static String f() {
|
||||
@@ -52,4 +69,37 @@ public class TestStackedConcatsSharedTest {
|
||||
s = new StringBuilder(String.valueOf(s)).append(String.valueOf(s)).toString();
|
||||
return s;
|
||||
}
|
||||
|
||||
static String g() {
|
||||
String s = "abc";
|
||||
s = new StringBuilder(s).toString();
|
||||
s = new StringBuilder(String.valueOf(s)).append(String.valueOf(s)).toString() + (s == null ? "def" : "abc");
|
||||
return s;
|
||||
}
|
||||
|
||||
static String h() {
|
||||
String s1 = new String("abc");
|
||||
String s2 = new StringBuilder(s1).append(s1).toString();
|
||||
String arg2 = "";
|
||||
if (s2 == null) {
|
||||
arg2 = "null";
|
||||
} else {
|
||||
arg2 = "notnull";
|
||||
}
|
||||
return new StringBuilder(s2).append(arg2).toString();
|
||||
}
|
||||
|
||||
static String i() {
|
||||
String s1 = new String("abc");
|
||||
String s2 = new StringBuilder(s1).append(s1).toString();
|
||||
String arg2 = "";
|
||||
if (s2 == null) {
|
||||
arg2 = "null";
|
||||
} else {
|
||||
arg2 = "notnull";
|
||||
}
|
||||
String s3 = new StringBuilder(s2).toString();
|
||||
String s4 = new StringBuilder(s3).append(arg2).toString();
|
||||
return s4;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 8362117
|
||||
* @summary Basic IR checks to verify that merge validation does not break concat optimizations.
|
||||
* @library /test/lib /
|
||||
* @run driver ${test.main.class}
|
||||
*/
|
||||
|
||||
package compiler.stringopts;
|
||||
|
||||
import compiler.lib.ir_framework.*;
|
||||
|
||||
public class TestStringConcatIR {
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestFramework.runWithFlags();
|
||||
}
|
||||
|
||||
@Run(test = {"stackedConcat", "stackedConcatNullCheck"})
|
||||
public void runMethodA() {
|
||||
stackedConcat();
|
||||
stackedConcatNullCheck();
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {IRNode.CALL, ">= 9"}, phase = {CompilePhase.BEFORE_STRINGOPTS}) // at least init, append, tostring x 3
|
||||
@IR(counts = {IRNode.ALLOC, "= 3"}, phase = {CompilePhase.BEFORE_STRINGOPTS})
|
||||
@IR(counts = {IRNode.CALL, "= 0"}, phase = {CompilePhase.ITER_GVN1})
|
||||
@IR(counts = {IRNode.ALLOC, "= 1"}, phase = {CompilePhase.ITER_GVN1})
|
||||
@IR(counts = {IRNode.STORE_B, "= 16"}, phase = {CompilePhase.ITER_GVN1})
|
||||
static String stackedConcat() {
|
||||
String s = "ab";
|
||||
s = new StringBuilder(s).append(s).toString();
|
||||
s = new StringBuilder(s).append(s).toString();
|
||||
s = new StringBuilder(s).append(s).toString();
|
||||
return s;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(applyIf = {"TieredCompilation", "true"},
|
||||
counts = {IRNode.CALL, ">= 9", IRNode.ALLOC, "= 3"},
|
||||
phase = {CompilePhase.BEFORE_STRINGOPTS})
|
||||
@IR(applyIf = {"TieredCompilation", "true"},
|
||||
counts = {IRNode.CALL, "= 0", IRNode.ALLOC, "= 1", IRNode.STORE_B, "= 24"},
|
||||
phase = {CompilePhase.ITER_GVN1})
|
||||
static String stackedConcatNullCheck() {
|
||||
String s = "abc";
|
||||
s = new StringBuilder(String.valueOf(s)).append(s).toString();
|
||||
s = new StringBuilder(String.valueOf(s)).append(String.valueOf(s)).toString();
|
||||
s = new StringBuilder(s).append(String.valueOf(s)).toString();
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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 8362117
|
||||
* @summary Prevent crashes and miscompilations when external constructs
|
||||
* could be confused for StringConcat append/toString-null checks.
|
||||
* @run main/othervm ${test.main.class}
|
||||
* @run main/othervm -Xbatch
|
||||
* -XX:CompileOnly=${test.main.class}::test* ${test.main.class}
|
||||
* @run main/othervm -Xbatch
|
||||
* -XX:CompileThreshold=500
|
||||
* -XX:CompileOnly=${test.main.class}::test* ${test.main.class}
|
||||
* @run main/othervm -Xbatch
|
||||
* -XX:-TieredCompilation
|
||||
* -XX:CompileOnly=${test.main.class}::test* ${test.main.class}
|
||||
*/
|
||||
|
||||
package compiler.stringopts;
|
||||
|
||||
public class TestStringConcatValidateMerge {
|
||||
|
||||
public static void main (String... args) {
|
||||
|
||||
String gold = test1(false);
|
||||
for (int i = 0; i < 10_000; i++) {
|
||||
test1((i & 1) == 0);
|
||||
}
|
||||
String val = test1(false);
|
||||
if (!val.equals(gold)) {
|
||||
throw new RuntimeException("wrong value: " + val + " vs " + gold);
|
||||
}
|
||||
|
||||
for (int t = 0; t < 10_000; t++) {
|
||||
// The following line is probably important for profiling.
|
||||
try { new String((String) null); } catch (NullPointerException e) {}
|
||||
test2();
|
||||
}
|
||||
|
||||
for (int t = 0; t < 10_000; t++) {
|
||||
try {
|
||||
if (t % 2 != 0) {
|
||||
test3(null, "B");
|
||||
} else {
|
||||
test3("A", null);
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 100_000; i++) {
|
||||
test4();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 100_000; i++) {
|
||||
test5(i % 2 == 0);
|
||||
}
|
||||
|
||||
gold = test6(new StringBuilder(" "));
|
||||
for (int i = 0; i < 100_000; i++) {
|
||||
val = test6(new StringBuilder(" "));
|
||||
}
|
||||
if (!val.equals(gold)) {
|
||||
throw new RuntimeException("wrong result.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// test1-3: StringOpts can't stack as SB1 is used in a compare in SB2 (previously confused as a valid string null check).
|
||||
// test4: can't remove SB1's toString as it's used in an external comparison that needs it -> reject stacking
|
||||
// test5: hand-written branching that changes return value (previously mistaken to be a valid string null check).
|
||||
// test6: merge an unresolved stringbuilder with the intermediate value used in a compare: reject single concat.
|
||||
|
||||
// JDK-8385429
|
||||
static String test1(boolean flag) {
|
||||
String s = new StringBuilder("ABC").toString();
|
||||
return new StringBuilder().append(s).append(s == null ? "x" : "y").append(flag ? "z" : s).toString();
|
||||
}
|
||||
|
||||
// JDK-8385428
|
||||
static int test2() {
|
||||
String s1 = (("a" == null) ? "b" : "c") + 'd';
|
||||
String s2 = new StringBuilder(s1).toString();
|
||||
String s3 = new StringBuilder(s2).append(s1).append(s2 == null ? "" : s2).toString();
|
||||
return s3.length();
|
||||
}
|
||||
|
||||
// JDK-8385415
|
||||
static Object test3(String a, String b) {
|
||||
String s1 = new String(b);
|
||||
String s2 = new StringBuffer(s1).append(s1).toString();
|
||||
return new StringBuffer(s2).append(a).append(s2 == null ? "" : s2).toString();
|
||||
}
|
||||
|
||||
// JDK-8384130
|
||||
static String test4() {
|
||||
String s = new StringBuilder().toString();
|
||||
return new StringBuilder(s).toString() == s ? "a" : "b";
|
||||
}
|
||||
|
||||
static String test5(boolean test) {
|
||||
String s1 = new String("b");
|
||||
String s2 = new StringBuilder(s1).append(s1).toString();
|
||||
String arg1 = "";
|
||||
String arg2 = "";
|
||||
if (s2 == null) {
|
||||
arg2 = "null";
|
||||
} else {
|
||||
arg2 = "Some other string";
|
||||
}
|
||||
return new StringBuffer(s2).append(arg2).toString();
|
||||
}
|
||||
|
||||
static String test6(StringBuilder c) {
|
||||
StringBuilder s = new StringBuilder().append(" ");
|
||||
String ret = s.append(s == c ? "abc" : " ").toString();
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
* @bug 8362117
|
||||
* @summary Similar type of test scenarios as in TestStringConcatValidateMerge.java
|
||||
* but for problems which manifested with -Xcomp
|
||||
* (f): stringopts shouldn't confuse ternary expression with string null check
|
||||
* and fold away diamond phi arbitrarily leading to wrong result when depending on
|
||||
* toString of SB1.
|
||||
* (g): variant of (f) with append instead of toString
|
||||
* @library /test/lib /
|
||||
* @run main/othervm ${test.main.class}
|
||||
* @run main/othervm -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=${test.main.class}::* ${test.main.class}
|
||||
*/
|
||||
|
||||
package compiler.stringopts;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
public class TestStringConcatValidateMergeXcomp {
|
||||
|
||||
public static void main (String... args) {
|
||||
new StringBuilder(); // load the class
|
||||
f();
|
||||
g();
|
||||
}
|
||||
|
||||
static String f() {
|
||||
String s = "a";
|
||||
s = new StringBuilder().append(s).append(s).toString();
|
||||
s = new StringBuilder().append(s).append((s == "xx") ? s : "aa").toString();
|
||||
Asserts.assertEQ(s, "aaaa"); // in particular, we should not have s.equals("aaxx");
|
||||
return s;
|
||||
}
|
||||
|
||||
static String g() {
|
||||
String s = "a";
|
||||
StringBuilder sb0 = new StringBuilder();
|
||||
s = new StringBuilder().append(s).append(s).toString();
|
||||
StringBuilder sb2 = new StringBuilder().append(s);
|
||||
s = sb2.append((sb2 == sb0) ? "xx" : "aa").toString();
|
||||
Asserts.assertEQ(s, "aaaa"); // in particular, we should not have s.equals("aaxx").
|
||||
return s;
|
||||
}
|
||||
}
|
||||
+16
-4
@@ -27,7 +27,7 @@
|
||||
* @summary CPU feature compatibility test for AOT Code Cache
|
||||
* @requires vm.cds.supports.aot.code.caching
|
||||
* @requires vm.compMode != "Xcomp" & vm.compMode != "Xint"
|
||||
* @requires os.simpleArch == "x64" | os.simpleArch == "aarch64"
|
||||
* @requires os.simpleArch == "x64" | os.simpleArch == "aarch64" | os.simpleArch == "riscv64"
|
||||
* @comment The test verifies AOT checks during VM startup and not code generation.
|
||||
* No need to run it with -Xcomp.
|
||||
* @library /test/lib /test/setup_aot
|
||||
@@ -74,6 +74,11 @@ public class AOTCodeCPUFeatureIncompatibilityTest {
|
||||
testIncompatibleFeature("-XX:-UseCRC32", "crc32", IncompatibilityMode.MISSING);
|
||||
testIncompatibleFeature("-XX:-UseCRC32", "crc32", IncompatibilityMode.ADDITIONAL);
|
||||
}
|
||||
} else if (Platform.isRISCV64()) {
|
||||
if (isZbaSupported(cpuFeatures)) {
|
||||
testIncompatibleFeature("-XX:-UseZba", "zba", IncompatibilityMode.MISSING);
|
||||
testIncompatibleFeature("-XX:-UseZba", "zba", IncompatibilityMode.ADDITIONAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,12 +92,14 @@ public class AOTCodeCPUFeatureIncompatibilityTest {
|
||||
if (mode == IncompatibilityMode.MISSING) {
|
||||
return new String[] {"-Xlog:aot+codecache*=debug"};
|
||||
} else {
|
||||
return new String[] {vmOption, "-Xlog:aot+codecache*=debug"};
|
||||
// UnlockDiagnosticVMOptions must precede vmOption because
|
||||
// some tested CPU feature flags are diagnostic (e.g. UseZba on riscv).
|
||||
return new String[] {"-XX:+UnlockDiagnosticVMOptions", vmOption, "-Xlog:aot+codecache*=debug"};
|
||||
}
|
||||
} else if (runMode == RunMode.PRODUCTION) {
|
||||
if (mode == IncompatibilityMode.MISSING) {
|
||||
return new String[] {vmOption,
|
||||
"-XX:+UnlockDiagnosticVMOptions",
|
||||
return new String[] {"-XX:+UnlockDiagnosticVMOptions",
|
||||
vmOption,
|
||||
// Prevent exiting VM on failure
|
||||
"-XX:-AbortVMOnAOTCodeFailure",
|
||||
"-Xlog:aot+codecache*=debug"};
|
||||
@@ -149,4 +156,9 @@ public class AOTCodeCPUFeatureIncompatibilityTest {
|
||||
static boolean isCRC32Supported(List<String> cpuFeatures) {
|
||||
return cpuFeatures.contains("crc32");
|
||||
}
|
||||
|
||||
// Only used on riscv64 platform
|
||||
static boolean isZbaSupported(List<String> cpuFeatures) {
|
||||
return cpuFeatures.contains("zba");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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 8381564
|
||||
* @requires vm.debug == true & vm.compMode != "Xint" & vm.compiler2.enabled & vm.flagless
|
||||
* @summary Test that different ways to avoid executing main() are reported as correctly as failure.
|
||||
* @library /test/lib /testlibrary_tests /
|
||||
* @run driver ${test.main.class}
|
||||
*/
|
||||
|
||||
package testlibrary_tests.ir_framework.tests;
|
||||
|
||||
import compiler.lib.ir_framework.*;
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintStream;
|
||||
|
||||
public class TestNoMainExecution {
|
||||
public static void main(String[] args) {
|
||||
// We do not handshake because this flag disables socket communication
|
||||
run("-DReproduce=true");
|
||||
|
||||
// We do not reach main() because there is no source file involved.
|
||||
run("--version");
|
||||
|
||||
// We do not reach main() because we crash already at start-up.
|
||||
runWithVmCrash();
|
||||
}
|
||||
|
||||
private static void run(String... flags) {
|
||||
try {
|
||||
TestFramework.runWithFlags(flags);
|
||||
Asserts.fail("should throw");
|
||||
} catch (RuntimeException e) {
|
||||
String errorMessage = e.getMessage();
|
||||
// We expect a useful help message - match its header.
|
||||
Asserts.assertTrue(errorMessage.contains("Did any of the following happen?"), errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private static void runWithVmCrash() {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
PrintStream oldErr = System.err;
|
||||
|
||||
try (PrintStream ps = new PrintStream(baos)) {
|
||||
System.setErr(ps);
|
||||
|
||||
try {
|
||||
TestFramework.runWithFlags("-Xcomp", "-XX:+CICountNative", "-XX:CICrashAt=1");
|
||||
Asserts.fail("should throw");
|
||||
} catch (RuntimeException e) {
|
||||
// With a VM crash, the message is found on the normal stderr instead.
|
||||
System.setErr(oldErr);
|
||||
String output = baos.toString();
|
||||
Asserts.assertTrue(output.contains("Did any of the following happen?"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {}
|
||||
}
|
||||
@@ -53,9 +53,7 @@ import java.nio.LongBuffer;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.nio.file.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -603,11 +601,24 @@ public class TestByteBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = UnsupportedOperationException.class)
|
||||
@Test
|
||||
public void testMapCustomPath() throws IOException {
|
||||
Path path = Path.of(URI.create("jrt:/"));
|
||||
try (FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
|
||||
fileChannel.map(FileChannel.MapMode.READ_WRITE, 0L, 0L, Arena.ofAuto());
|
||||
// Zip file systems do support creating file channels
|
||||
// but do not support memory mapping those files
|
||||
Path scratch = Path.of("testMapCustomPath");
|
||||
Files.createDirectories(scratch);
|
||||
Path zipFile = scratch.resolve("test.zip");
|
||||
|
||||
try (FileSystem zipFs = FileSystems.newFileSystem(zipFile, Map.of("create", true))) {
|
||||
// create test file
|
||||
Path testFile = zipFs.getPath("/test_file.txt");
|
||||
Files.writeString(testFile, "testing", StandardOpenOption.CREATE_NEW);
|
||||
|
||||
// now try to map it
|
||||
try (FileChannel fileChannel = FileChannel.open(testFile, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
|
||||
assertThrows(UnsupportedOperationException.class,
|
||||
() -> fileChannel.map(FileChannel.MapMode.READ_WRITE, 0L, 0L, Arena.ofAuto()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,10 +34,7 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertNotEquals;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class TestFunctionDescriptor extends NativeTestHelper {
|
||||
|
||||
@@ -116,16 +113,6 @@ public class TestFunctionDescriptor extends NativeTestHelper {
|
||||
assertEquals(cmt, MethodType.methodType(int.class, int.class, MemorySegment.class, MemorySegment.class));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testBadCarrierMethodType() {
|
||||
FunctionDescriptor fd = FunctionDescriptor.of(C_INT,
|
||||
C_INT,
|
||||
MemoryLayout.structLayout(C_INT, C_INT),
|
||||
MemoryLayout.sequenceLayout(3, C_INT),
|
||||
MemoryLayout.paddingLayout(4));
|
||||
fd.toMethodType(); // should throw
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testIllegalInsertArgNegIndex() {
|
||||
FunctionDescriptor fd = FunctionDescriptor.of(C_INT);
|
||||
|
||||
@@ -307,10 +307,12 @@ public class TestLayouts {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(dataProvider="layoutsAndAlignments", expectedExceptions = IllegalArgumentException.class)
|
||||
@Test(dataProvider="layoutsAndAlignments")
|
||||
public void testBadSequenceElementAlignmentTooBig(MemoryLayout layout, long byteAlign) {
|
||||
layout = layout.withByteAlignment(layout.byteSize() * 2); // hyper-align
|
||||
MemoryLayout.sequenceLayout(1, layout);
|
||||
MemoryLayout elementLayout = layout.withByteAlignment(nextPowerOfTwo(layout.byteSize() * 2)); // hyper-align
|
||||
IllegalArgumentException iae = expectThrows(IllegalArgumentException.class,
|
||||
() -> MemoryLayout.sequenceLayout(1, elementLayout));
|
||||
assertEquals(iae.getMessage(), "Element layout size is not multiple of alignment");
|
||||
}
|
||||
|
||||
@Test(dataProvider="layoutsAndAlignments")
|
||||
@@ -348,15 +350,16 @@ public class TestLayouts {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(dataProvider="layoutsAndAlignments", expectedExceptions = IllegalArgumentException.class)
|
||||
@Test(dataProvider="layoutsAndAlignments")
|
||||
public void testBadStruct(MemoryLayout layout, long byteAlign) {
|
||||
layout = layout.withByteAlignment(layout.byteSize() * 2); // hyper-align
|
||||
MemoryLayout.structLayout(layout, layout);
|
||||
MemoryLayout elementLayout = layout.withByteAlignment(nextPowerOfTwo(layout.byteSize() * 2)); // hyper-align
|
||||
IllegalArgumentException iae = expectThrows(IllegalArgumentException.class,
|
||||
() -> MemoryLayout.structLayout(elementLayout, elementLayout));
|
||||
assertTrue(iae.getMessage().contains("Invalid alignment constraint for member layout"));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testSequenceElement() {
|
||||
SequenceLayout layout = MemoryLayout.sequenceLayout(10, JAVA_INT);
|
||||
// Step must be != 0
|
||||
PathElement.sequenceElement(3, 0);
|
||||
}
|
||||
@@ -543,4 +546,8 @@ public class TestLayouts {
|
||||
ValueLayout.JAVA_LONG,
|
||||
ValueLayout.JAVA_DOUBLE,
|
||||
};
|
||||
|
||||
private static long nextPowerOfTwo(long input) {
|
||||
return 1L << -Long.numberOfLeadingZeros(input - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,24 +73,6 @@ public class TestMemoryAlignment {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(dataProvider = "alignments")
|
||||
public void testUnalignedAccess(long align) {
|
||||
ValueLayout layout = ValueLayout.JAVA_INT
|
||||
.withOrder(ByteOrder.BIG_ENDIAN);
|
||||
assertEquals(layout.byteAlignment(), 4);
|
||||
ValueLayout aligned = layout.withByteAlignment(align);
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemoryLayout alignedGroup = MemoryLayout.structLayout(MemoryLayout.paddingLayout(1), aligned);
|
||||
assertEquals(alignedGroup.byteAlignment(), align);
|
||||
VarHandle vh = aligned.varHandle();
|
||||
MemorySegment segment = arena.allocate(alignedGroup);;
|
||||
vh.set(segment.asSlice(1L), 0L, -42);
|
||||
assertEquals(align, 8); //this is the only case where access is aligned
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertNotEquals(align, 8); //if align != 8, access is always unaligned
|
||||
}
|
||||
}
|
||||
|
||||
@Test(dataProvider = "alignments")
|
||||
public void testUnalignedPath(long align) {
|
||||
MemoryLayout layout = ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN);
|
||||
|
||||
@@ -29,9 +29,7 @@
|
||||
import java.lang.foreign.*;
|
||||
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Spliterator;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CountedCompleter;
|
||||
import java.util.concurrent.RecursiveTask;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
@@ -147,13 +145,19 @@ public class TestSpliterator {
|
||||
.elements(MemoryLayout.sequenceLayout(0, ValueLayout.JAVA_INT));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
@Test
|
||||
public void testHyperAligned() {
|
||||
Arena scope = Arena.ofAuto();
|
||||
MemorySegment segment = scope.allocate(8, 1);
|
||||
// compute an alignment constraint (in bytes) which exceed that of the native segment
|
||||
long bigByteAlign = Long.lowestOneBit(segment.address()) << 1;
|
||||
segment.elements(MemoryLayout.sequenceLayout(2, ValueLayout.JAVA_INT.withByteAlignment(bigByteAlign)));
|
||||
MemoryLayout elementLayout = MemoryLayout.structLayout(
|
||||
Collections.nCopies(Math.toIntExact(bigByteAlign), ValueLayout.JAVA_BYTE).toArray(MemoryLayout[]::new))
|
||||
.withByteAlignment(bigByteAlign);
|
||||
SequenceLayout layout = MemoryLayout.sequenceLayout(2, elementLayout);
|
||||
IllegalArgumentException iae = expectThrows(IllegalArgumentException.class,
|
||||
() -> segment.elements(layout));
|
||||
assertEquals(iae.getMessage(), "Incompatible alignment constraints");
|
||||
}
|
||||
|
||||
static long sumSingle(long acc, MemorySegment segment) {
|
||||
|
||||
@@ -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
|
||||
@@ -65,43 +65,58 @@ public class MetricsMemoryTester {
|
||||
}
|
||||
|
||||
private static void testMemoryFailCount() {
|
||||
long memAndSwapLimit = Metrics.systemMetrics().getMemoryAndSwapLimit();
|
||||
long memLimit = Metrics.systemMetrics().getMemoryLimit();
|
||||
final Metrics metrics = Metrics.systemMetrics();
|
||||
final long memAndSwapLimit = metrics.getMemoryAndSwapLimit();
|
||||
final long memLimit = metrics.getMemoryLimit();
|
||||
|
||||
// We need swap to execute this test or will SEGV
|
||||
if (memAndSwapLimit <= memLimit) {
|
||||
System.out.println("No swap memory limits. Ignoring test!");
|
||||
} else {
|
||||
long count = Metrics.systemMetrics().getMemoryFailCount();
|
||||
final int M = 1024 * 1024;
|
||||
|
||||
// Allocate 512M of data in 1M chunks per iteration
|
||||
byte[][] bytes = new byte[64 * 8][];
|
||||
boolean atLeastOneAllocationWorked = false;
|
||||
for (int i = 0; i < 64 * 8; i++) {
|
||||
try {
|
||||
bytes[i] = new byte[1024 * 1024];
|
||||
atLeastOneAllocationWorked = true;
|
||||
// Break out as soon as we see an increase in failcount
|
||||
// to avoid getting killed by the OOM killer.
|
||||
if (Metrics.systemMetrics().getMemoryFailCount() > count) {
|
||||
break;
|
||||
}
|
||||
} catch (Error e) { // OOM error
|
||||
break;
|
||||
}
|
||||
// We need swap to execute this test. Otherwise OOM killer acts with
|
||||
// SIGKILL before we read the fail counter.
|
||||
|
||||
final long maxHeapSize = Runtime.getRuntime().maxMemory();
|
||||
if (maxHeapSize <= memLimit || maxHeapSize >= memAndSwapLimit) {
|
||||
throw new RuntimeException(
|
||||
"Expected memory limit < maximum heap < memory-and-swap limit: "
|
||||
+ "memory=" + memLimit / M + "M, "
|
||||
+ "heap=" + maxHeapSize / M + "M, "
|
||||
+ "memory-and-swap=" + memAndSwapLimit / M + "M");
|
||||
}
|
||||
|
||||
final long initialFailCount = metrics.getMemoryFailCount();
|
||||
|
||||
System.out.println("Initial memory fail count: " + initialFailCount);
|
||||
|
||||
// Allocate 512M of data in 1M chunks per iteration
|
||||
byte[][] bytes = new byte[512][];
|
||||
|
||||
for (int i = 0; i < 512; i++) {
|
||||
if (i % 8 == 0) {
|
||||
System.out.printf("Allocated: %3dM, Memory usage: %3dM, Memory and swap: %3dM\n",
|
||||
i,
|
||||
metrics.getMemoryUsage() / M,
|
||||
metrics.getMemoryAndSwapUsage() / M);
|
||||
} else {
|
||||
System.out.print(".");
|
||||
}
|
||||
if (!atLeastOneAllocationWorked) {
|
||||
System.out.println("Allocation failed immediately. Ignoring test!");
|
||||
return;
|
||||
}
|
||||
// Be sure bytes allocations don't get optimized out
|
||||
System.out.println("DEBUG: Bytes allocation length 1: " + bytes[0].length);
|
||||
if (Metrics.systemMetrics().getMemoryFailCount() <= count) {
|
||||
throw new RuntimeException("Memory fail count : new : ["
|
||||
+ Metrics.systemMetrics().getMemoryFailCount() + "]"
|
||||
+ ", old : [" + count + "]");
|
||||
bytes[i] = new byte[M];
|
||||
Arrays.fill(bytes[i], (byte) 1); // dirty every page
|
||||
// Break out as soon as we see an increase in failcount
|
||||
if (metrics.getMemoryFailCount() > initialFailCount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Be sure bytes allocations don't get optimized out
|
||||
System.out.println("\nDEBUG: Bytes allocation length 1: " + bytes[0].length);
|
||||
final long newCount = metrics.getMemoryFailCount();
|
||||
System.out.println("Final memory fail count: " + newCount);
|
||||
|
||||
if (newCount <= initialFailCount) {
|
||||
throw new RuntimeException("Memory fail count did not increase: initial="
|
||||
+ initialFailCount + ", final=" + newCount);
|
||||
}
|
||||
|
||||
System.out.println("TEST PASSED!!!");
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -76,7 +76,7 @@ public class TestDockerMemoryMetrics {
|
||||
}
|
||||
testOomKillFlag("100m", true);
|
||||
|
||||
testMemoryFailCount("128m");
|
||||
testMemoryFailCount("128m" /*memory*/, "768m" /*max_heap*/, "1024m" /*memory_n_swap*/);
|
||||
|
||||
testMemorySoftLimit("500m","200m");
|
||||
|
||||
@@ -105,36 +105,47 @@ public class TestDockerMemoryMetrics {
|
||||
DockerTestUtils.dockerRunJava(opts).shouldHaveExitValue(0).shouldContain("TEST PASSED!!!");
|
||||
}
|
||||
|
||||
private static void testMemoryFailCount(String value) throws Exception {
|
||||
Common.logNewTestCase("testMemoryFailCount" + value);
|
||||
private static void testMemoryFailCount(String memory, String heap, String memoryAndSwap) throws Exception {
|
||||
Common.logNewTestCase("testMemoryFailCount, memory = " + memory
|
||||
+ ", heap = " + heap
|
||||
+ ", memory + swap = " + memoryAndSwap);
|
||||
|
||||
// Check whether swapping really works for this test
|
||||
// On some systems there is no swap space enabled. And running
|
||||
// 'java -Xms{mem-limit} -Xmx{mem-limit} -XX:+AlwaysPreTouch -version'
|
||||
// 'java -Xms{heap} -Xmx{heap} -XX:+AlwaysPreTouch -version'
|
||||
// would fail due to swap space size being 0. Note that when swap is
|
||||
// properly enabled on the system the container gets the same amount
|
||||
// of swap as is configured for memory. Thus, 2x{mem-limit} is the actual
|
||||
// memory and swap bound for this pre-test.
|
||||
// properly enabled, the explicit memory-and-swap limit gives the JVM
|
||||
// enough headroom to exceed the physical memory limit without being
|
||||
// killed by the OOM killer.
|
||||
DockerRunOptions preOpts =
|
||||
new DockerRunOptions(imageName, "/jdk/bin/java", "-version");
|
||||
preOpts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/")
|
||||
.addDockerOpts("--memory=" + value)
|
||||
.addDockerOpts("--memory=" + memory)
|
||||
.addDockerOpts("--memory-swap=" + memoryAndSwap)
|
||||
.addJavaOpts("-XX:+AlwaysPreTouch")
|
||||
.addJavaOpts("-Xms" + value)
|
||||
.addJavaOpts("-Xmx" + value);
|
||||
.addJavaOptsAppended("-XX:InitialHeapSize=" + heap)
|
||||
.addJavaOptsAppended("-XX:MaxHeapSize=" + heap);
|
||||
OutputAnalyzer oa = DockerTestUtils.dockerRunJava(preOpts);
|
||||
String output = oa.getOutput();
|
||||
if (!output.contains("version")) {
|
||||
throw new SkippedException("Swapping doesn't work for this test.");
|
||||
}
|
||||
|
||||
// 0 128 1024
|
||||
// |---o----------------|---------------------------X--------------)-------------|
|
||||
// START memory.max growth target MaxHeapSize memory+swap limit
|
||||
// o~~~~~>~>~>~>~>~>~>~>~>~>~>~>~>~>~>~>~> (growth) OOM
|
||||
// failcount: 0 1 2 3 . . . N
|
||||
//
|
||||
DockerRunOptions opts =
|
||||
new DockerRunOptions(imageName, "/jdk/bin/java", "MetricsMemoryTester");
|
||||
opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/")
|
||||
.addDockerOpts("--memory=" + value)
|
||||
.addJavaOpts("-Xmx" + value)
|
||||
.addDockerOpts("--memory=" + memory)
|
||||
.addDockerOpts("--memory-swap=" + memoryAndSwap)
|
||||
.addJavaOpts("-cp", "/test-classes/")
|
||||
.addJavaOpts("--add-exports", "java.base/jdk.internal.platform=ALL-UNNAMED")
|
||||
// set the required heap size *after* inherited jtreg options
|
||||
.addJavaOptsAppended("-XX:MaxHeapSize=" + heap)
|
||||
.addClassOptions("failcount");
|
||||
oa = DockerTestUtils.dockerRunJava(opts);
|
||||
output = oa.getOutput();
|
||||
|
||||
@@ -477,7 +477,7 @@ public class VMProps implements Callable<Map<String, String>> {
|
||||
protected String vmCDSSupportsAOTCodeCaching() {
|
||||
if ("true".equals(vmCDSSupportsAOTClassLinking()) &&
|
||||
!"zero".equals(vmFlavor()) &&
|
||||
(Platform.isX64() || Platform.isAArch64())) {
|
||||
(Platform.isX64() || Platform.isAArch64() || Platform.isRISCV64())) {
|
||||
return "true";
|
||||
} else {
|
||||
return "false";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2024, 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
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8013852 8031744 8225377 8323684
|
||||
* @bug 8013852 8031744 8225377 8323684 8389859
|
||||
* @summary Annotations on types
|
||||
* @library /tools/javac/lib
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
@@ -103,7 +103,9 @@ public class BasicAnnoTests extends JavacTestingAbstractProcessor {
|
||||
new NameToAnnotationEntry("BasicAnnoTests.TB", BasicAnnoTests.TB.class),
|
||||
new NameToAnnotationEntry("BasicAnnoTests.TC", BasicAnnoTests.TC.class),
|
||||
new NameToAnnotationEntry("BasicAnnoTests.TCs", BasicAnnoTests.TCs.class),
|
||||
new NameToAnnotationEntry("BasicAnnoTests.TD", BasicAnnoTests.TD.class));
|
||||
new NameToAnnotationEntry("BasicAnnoTests.TD", BasicAnnoTests.TD.class),
|
||||
new NameToAnnotationEntry("BasicAnnoTests.DTF", BasicAnnoTests.DTF.class),
|
||||
new NameToAnnotationEntry("BasicAnnoTests.DTP", BasicAnnoTests.DTP.class));
|
||||
|
||||
static class NameToAnnotationEntry extends AbstractMap.SimpleEntry<String, Class<? extends Annotation>> {
|
||||
public NameToAnnotationEntry(String key, Class<? extends Annotation> entry) {
|
||||
@@ -531,6 +533,16 @@ public class BasicAnnoTests extends JavacTestingAbstractProcessor {
|
||||
int value();
|
||||
}
|
||||
|
||||
@Target({ElementType.TYPE_USE, ElementType.FIELD})
|
||||
public @interface DTF {
|
||||
int value();
|
||||
}
|
||||
|
||||
@Target({ElementType.TYPE_USE, ElementType.PARAMETER})
|
||||
public @interface DTP {
|
||||
int value();
|
||||
}
|
||||
|
||||
// Test cases
|
||||
|
||||
// TODO: add more cases for arrays
|
||||
@@ -697,6 +709,29 @@ public class BasicAnnoTests extends JavacTestingAbstractProcessor {
|
||||
@Test(posn=6, annoType = TB.class, expect = "61")
|
||||
<T> void m60(@TA(60) @TB(61) String t) { }
|
||||
|
||||
// Test dual target annotations on uses of type variables
|
||||
@Test(posn=6, annoType = DTP.class, expect = "61")
|
||||
<T> void m61(@DTP(61) T t) { }
|
||||
|
||||
@Test(posn=7, annoType = DTP.class, expect = "62")
|
||||
<T> void m62(@DTP(62) T[] t) { }
|
||||
|
||||
class Inner63<T> {
|
||||
@Test(posn=0, annoType = DTF.class, expect = "63")
|
||||
@DTF(63) T f;
|
||||
}
|
||||
// Test dual target annotations on uses of Class types
|
||||
@Test(posn=6, annoType = DTP.class, expect = "64")
|
||||
<T> void m64(@DTP(64) String t) { }
|
||||
|
||||
@Test(posn=7, annoType = DTP.class, expect = "65")
|
||||
<T> void m65(@DTP(65) String[] t) { }
|
||||
|
||||
class Inner66<T> {
|
||||
@Test(posn=0, annoType = DTF.class, expect = "66")
|
||||
@DTF(66) String f;
|
||||
}
|
||||
|
||||
class Inner70<T> {
|
||||
@Test(posn=0, annoType = TA.class, expect = "70")
|
||||
@Test(posn=0, annoType = TB.class, expect = "71")
|
||||
|
||||
Reference in New Issue
Block a user