8299089: Instrument global jni handles with tag to make them distinguishable

Co-authored-by: Stefan Karlsson <stefank@openjdk.org>
Co-authored-by: Martin Doerr <mdoerr@openjdk.org>
Co-authored-by: Leslie Zhai <lzhai@openjdk.org>
Reviewed-by: eosterlund, stefank, ayang
This commit is contained in:
Axel Boldt-Christmas 2023-01-18 09:21:08 +00:00
parent 66f7387b5f
commit c7056737e3
36 changed files with 470 additions and 227 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -122,8 +122,8 @@ void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators
void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,
Register obj, Register tmp, Label& slowpath) {
// If mask changes we need to ensure that the inverse is still encodable as an immediate
STATIC_ASSERT(JNIHandles::weak_tag_mask == 1);
__ andr(obj, obj, ~JNIHandles::weak_tag_mask);
STATIC_ASSERT(JNIHandles::tag_mask == 0b11);
__ andr(obj, obj, ~JNIHandles::tag_mask);
__ ldr(obj, Address(obj, 0)); // *obj
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -2458,22 +2458,56 @@ void MacroAssembler::verify_heapbase(const char* msg) {
#endif
void MacroAssembler::resolve_jobject(Register value, Register tmp1, Register tmp2) {
Label done, not_weak;
assert_different_registers(value, tmp1, tmp2);
Label done, tagged, weak_tagged;
cbz(value, done); // Use NULL as-is.
tst(value, JNIHandles::tag_mask); // Test for tag.
br(Assembler::NE, tagged);
STATIC_ASSERT(JNIHandles::weak_tag_mask == 1u);
tbz(value, 0, not_weak); // Test for jweak tag.
// Resolve jweak.
access_load_at(T_OBJECT, IN_NATIVE | ON_PHANTOM_OOP_REF, value,
Address(value, -JNIHandles::weak_tag_value), tmp1, tmp2);
// Resolve local handle
access_load_at(T_OBJECT, IN_NATIVE | AS_RAW, value, Address(value, 0), tmp1, tmp2);
verify_oop(value);
b(done);
bind(not_weak);
// Resolve (untagged) jobject.
access_load_at(T_OBJECT, IN_NATIVE, value, Address(value, 0), tmp1, tmp2);
bind(tagged);
STATIC_ASSERT(JNIHandles::TypeTag::weak_global == 0b1);
tbnz(value, 0, weak_tagged); // Test for weak tag.
// Resolve global handle
access_load_at(T_OBJECT, IN_NATIVE, value, Address(value, -JNIHandles::TypeTag::global), tmp1, tmp2);
verify_oop(value);
b(done);
bind(weak_tagged);
// Resolve jweak.
access_load_at(T_OBJECT, IN_NATIVE | ON_PHANTOM_OOP_REF,
value, Address(value, -JNIHandles::TypeTag::weak_global), tmp1, tmp2);
verify_oop(value);
bind(done);
}
void MacroAssembler::resolve_global_jobject(Register value, Register tmp1, Register tmp2) {
assert_different_registers(value, tmp1, tmp2);
Label done;
cbz(value, done); // Use NULL as-is.
#ifdef ASSERT
{
STATIC_ASSERT(JNIHandles::TypeTag::global == 0b10);
Label valid_global_tag;
tbnz(value, 1, valid_global_tag); // Test for global tag
stop("non global jobject using resolve_global_jobject");
bind(valid_global_tag);
}
#endif
// Resolve global handle
access_load_at(T_OBJECT, IN_NATIVE, value, Address(value, -JNIHandles::TypeTag::global), tmp1, tmp2);
verify_oop(value);
bind(done);
}

View file

@ -823,6 +823,7 @@ public:
void store_check(Register obj, Address dst); // same as above, dst is exact store location (reg. is destroyed)
void resolve_jobject(Register value, Register tmp1, Register tmp2);
void resolve_global_jobject(Register value, Register tmp1, Register tmp2);
// C 'boolean' to Java boolean: x == 0 ? 0 : 1
void c2bool(Register x);

View file

@ -6923,12 +6923,7 @@ class StubGenerator: public StubCodeGenerator {
// The handle is dereferenced through a load barrier.
static void jfr_epilogue(MacroAssembler* _masm) {
__ reset_last_Java_frame(true);
Label null_jobject;
__ cbz(r0, null_jobject);
DecoratorSet decorators = ACCESS_READ | IN_NATIVE;
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->load_at(_masm, decorators, T_OBJECT, r0, Address(r0, 0), rscratch1, rscratch2);
__ bind(null_jobject);
__ resolve_global_jobject(r0, rscratch1, rscratch2);
}
// For c2: c_rarg0 is junk, call to runtime to write a checkpoint.
@ -6943,7 +6938,7 @@ class StubGenerator: public StubCodeGenerator {
framesize // inclusive of return address
};
int insts_size = 512;
int insts_size = 1024;
int locs_size = 64;
CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size);
OopMapSet* oop_maps = new OopMapSet();

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -113,7 +113,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
__ ldr_s32(Rsafept_cnt, Address(Rsafepoint_counter_addr));
__ tbnz(Rsafept_cnt, 0, slow_case);
__ bic(R1, R1, JNIHandles::weak_tag_mask);
__ bic(R1, R1, JNIHandles::tag_mask);
if (JvmtiExport::can_post_field_access()) {
// Using barrier to order wrt. JVMTI check and load of result.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -1284,20 +1284,57 @@ void MacroAssembler::resolve_jobject(Register value,
Register tmp1,
Register tmp2) {
assert_different_registers(value, tmp1, tmp2);
Label done, not_weak;
cbz(value, done); // Use NULL as-is.
STATIC_ASSERT(JNIHandles::weak_tag_mask == 1u);
tbz(value, 0, not_weak); // Test for jweak tag.
Label done, tagged, weak_tagged;
cbz(value, done); // Use NULL as-is.
tst(value, JNIHandles::tag_mask); // Test for tag.
b(tagged, ne);
// Resolve local handle
access_load_at(T_OBJECT, IN_NATIVE | AS_RAW, Address(value, 0), value, tmp1, tmp2, noreg);
verify_oop(value);
b(done);
bind(tagged);
tst(value, JNIHandles::TypeTag::weak_global); // Test for weak tag.
b(weak_tagged, ne);
// Resolve global handle
access_load_at(T_OBJECT, IN_NATIVE, Address(value, -JNIHandles::TypeTag::global), value, tmp1, tmp2, noreg);
verify_oop(value);
b(done);
bind(weak_tagged);
// Resolve jweak.
access_load_at(T_OBJECT, IN_NATIVE | ON_PHANTOM_OOP_REF,
Address(value, -JNIHandles::weak_tag_value), value, tmp1, tmp2, noreg);
b(done);
bind(not_weak);
// Resolve (untagged) jobject.
access_load_at(T_OBJECT, IN_NATIVE,
Address(value, 0), value, tmp1, tmp2, noreg);
Address(value, -JNIHandles::TypeTag::weak_global), value, tmp1, tmp2, noreg);
verify_oop(value);
bind(done);
}
void MacroAssembler::resolve_global_jobject(Register value,
Register tmp1,
Register tmp2) {
assert_different_registers(value, tmp1, tmp2);
Label done;
cbz(value, done); // Use NULL as-is.
#ifdef ASSERT
{
Label valid_global_tag;
tst(value, JNIHandles::TypeTag::global); // Test for global tag.
b(valid_global_tag, ne);
stop("non global jobject using resolve_global_jobject");
bind(valid_global_tag);
}
#endif
// Resolve global handle
access_load_at(T_OBJECT, IN_NATIVE, Address(value, -JNIHandles::TypeTag::global), value, tmp1, tmp2, noreg);
verify_oop(value);
bind(done);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -356,6 +356,7 @@ public:
}
void resolve_jobject(Register value, Register tmp1, Register tmp2);
void resolve_global_jobject(Register value, Register tmp1, Register tmp2);
void nop() {
mov(R0, R0);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -3053,13 +3053,7 @@ class StubGenerator: public StubCodeGenerator {
__ reset_last_Java_frame(Rtemp);
// R0 is jobject handle result, unpack and process it through a barrier.
Label L_null_jobject;
__ cbz(R0, L_null_jobject);
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->load_at(masm, ACCESS_READ | IN_NATIVE, T_OBJECT, R0, Address(R0, 0), Rtemp, R1, R2);
__ bind(L_null_jobject);
__ resolve_global_jobject(R0, Rtemp, R1);
__ raw_pop(R1, R2, LR);
__ ret();

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -377,8 +377,8 @@ void G1BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value
__ cmpdi(CCR0, value, 0);
__ beq(CCR0, done); // Use NULL as-is.
__ clrrdi(tmp1, value, JNIHandles::weak_tag_size);
__ andi_(tmp2, value, JNIHandles::weak_tag_mask);
__ clrrdi(tmp1, value, JNIHandles::tag_size);
__ andi_(tmp2, value, JNIHandles::TypeTag::weak_global);
__ ld(value, 0, tmp1); // Resolve (untagged) jobject.
__ beq(CCR0, not_weak); // Test for jweak tag.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -115,31 +115,65 @@ void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators,
void BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value,
Register tmp1, Register tmp2,
MacroAssembler::PreservationLevel preservation_level) {
Label done, not_weak, verify;
Label done, tagged, weak_tagged, verify;
__ cmpdi(CCR0, value, 0);
__ beq(CCR0, done); // Use NULL as-is.
__ andi_(tmp1, value, JNIHandles::weak_tag_mask);
__ beq(CCR0, not_weak); // Test for jweak tag.
__ andi_(tmp1, value, JNIHandles::tag_mask);
__ bne(CCR0, tagged); // Test for tag.
// Resolve (untagged) jobject.
__ clrrdi(value, value, JNIHandles::weak_tag_size);
load_at(masm, IN_NATIVE | ON_PHANTOM_OOP_REF, T_OBJECT,
value, (intptr_t)0, value, tmp1, tmp2, preservation_level);
__ access_load_at(T_OBJECT, IN_NATIVE | AS_RAW, // no uncoloring
value, (intptr_t)0, value, tmp1, tmp2, preservation_level);
__ b(verify);
__ bind(not_weak);
load_at(masm, IN_NATIVE, T_OBJECT,
value, (intptr_t)0, value, tmp1, tmp2, preservation_level);
__ bind(tagged);
__ andi_(tmp1, value, JNIHandles::TypeTag::weak_global);
__ clrrdi(value, value, JNIHandles::tag_size); // Untag.
__ bne(CCR0, weak_tagged); // Test for jweak tag.
__ access_load_at(T_OBJECT, IN_NATIVE,
value, (intptr_t)0, value, tmp1, tmp2, preservation_level);
__ b(verify);
__ bind(weak_tagged);
__ access_load_at(T_OBJECT, IN_NATIVE | ON_PHANTOM_OOP_REF,
value, (intptr_t)0, value, tmp1, tmp2, preservation_level);
__ bind(verify);
__ verify_oop(value, FILE_AND_LINE);
__ bind(done);
}
// Generic implementation. GCs can provide an optimized one.
void BarrierSetAssembler::resolve_global_jobject(MacroAssembler* masm, Register value,
Register tmp1, Register tmp2,
MacroAssembler::PreservationLevel preservation_level) {
Label done;
__ cmpdi(CCR0, value, 0);
__ beq(CCR0, done); // Use NULL as-is.
#ifdef ASSERT
{
Label valid_global_tag;
__ andi_(tmp1, value, JNIHandles::TypeTag::global);
__ bne(CCR0, valid_global_tag); // Test for global tag.
__ stop("non global jobject using resolve_global_jobject");
__ bind(valid_global_tag);
}
#endif
__ clrrdi(value, value, JNIHandles::tag_size); // Untag.
__ access_load_at(T_OBJECT, IN_NATIVE,
value, (intptr_t)0, value, tmp1, tmp2, preservation_level);
__ verify_oop(value, FILE_AND_LINE);
__ bind(done);
}
void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register dst, Register jni_env,
Register obj, Register tmp, Label& slowpath) {
__ clrrdi(dst, obj, JNIHandles::weak_tag_size);
__ clrrdi(dst, obj, JNIHandles::tag_size);
__ ld(dst, 0, dst); // Resolve (untagged) jobject.
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -56,6 +56,9 @@ public:
virtual void resolve_jobject(MacroAssembler* masm, Register value,
Register tmp1, Register tmp2,
MacroAssembler::PreservationLevel preservation_level);
virtual void resolve_global_jobject(MacroAssembler* masm, Register value,
Register tmp1, Register tmp2,
MacroAssembler::PreservationLevel preservation_level);
virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register dst, Register jni_env,
Register obj, Register tmp, Label& slowpath);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -84,7 +84,7 @@ void ModRefBarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register v
__ cmpdi(CCR0, value, 0);
__ beq(CCR0, done); // Use NULL as-is.
__ clrrdi(tmp1, value, JNIHandles::weak_tag_size);
__ clrrdi(tmp1, value, JNIHandles::tag_size);
__ ld(value, 0, tmp1); // Resolve (untagged) jobject.
__ verify_oop(value, FILE_AND_LINE);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2022 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -2892,6 +2892,12 @@ void MacroAssembler::resolve_jobject(Register value, Register tmp1, Register tmp
bs->resolve_jobject(this, value, tmp1, tmp2, preservation_level);
}
void MacroAssembler::resolve_global_jobject(Register value, Register tmp1, Register tmp2,
MacroAssembler::PreservationLevel preservation_level) {
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->resolve_global_jobject(this, value, tmp1, tmp2, preservation_level);
}
// Values for last_Java_pc, and last_Java_sp must comply to the rules
// in frame_ppc.hpp.
void MacroAssembler::set_last_Java_frame(Register last_Java_sp, Register last_Java_pc) {

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2021 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -661,6 +661,8 @@ class MacroAssembler: public Assembler {
void resolve_jobject(Register value, Register tmp1, Register tmp2,
MacroAssembler::PreservationLevel preservation_level);
void resolve_global_jobject(Register value, Register tmp1, Register tmp2,
MacroAssembler::PreservationLevel preservation_level);
// Support for managing the JavaThread pointer (i.e.; the reference to
// thread-local information).
@ -698,7 +700,6 @@ class MacroAssembler: public Assembler {
// Access heap oop, handle encoding and GC barriers.
// Some GC barriers call C so use needs_frame = true if an extra frame is needed at the current call site.
private:
inline void access_store_at(BasicType type, DecoratorSet decorators,
Register base, RegisterOrConstant ind_or_offs, Register val,
Register tmp1, Register tmp2, Register tmp3,

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2022 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -4628,13 +4628,7 @@ class StubGenerator: public StubCodeGenerator {
address calls_return_pc = __ last_calls_return_pc();
__ reset_last_Java_frame();
// The handle is dereferenced through a load barrier.
Label null_jobject;
__ cmpdi(CCR0, R3_RET, 0);
__ beq(CCR0, null_jobject);
DecoratorSet decorators = ACCESS_READ | IN_NATIVE;
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->load_at(_masm, decorators, T_OBJECT, R3_RET /*base*/, (intptr_t)0, R3_RET /*dst*/, tmp1, tmp2, MacroAssembler::PRESERVATION_NONE);
__ bind(null_jobject);
__ resolve_global_jobject(R3_RET, tmp1, tmp2, MacroAssembler::PRESERVATION_NONE);
__ pop_frame();
__ ld(tmp1, _abi0(lr), R1_SP);
__ mtlr(tmp1);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -122,8 +122,8 @@ void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators
void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,
Register obj, Register tmp, Label& slowpath) {
// If mask changes we need to ensure that the inverse is still encodable as an immediate
STATIC_ASSERT(JNIHandles::weak_tag_mask == 1);
__ andi(obj, obj, ~JNIHandles::weak_tag_mask);
STATIC_ASSERT(JNIHandles::tag_mask == 3);
__ andi(obj, obj, ~JNIHandles::tag_mask);
__ ld(obj, Address(obj, 0)); // *obj
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@ -556,23 +556,59 @@ void MacroAssembler::debug64(char* msg, int64_t pc, int64_t regs[])
}
void MacroAssembler::resolve_jobject(Register value, Register tmp1, Register tmp2) {
Label done, not_weak;
assert_different_registers(value, tmp1, tmp2);
Label done, tagged, weak_tagged;
beqz(value, done); // Use NULL as-is.
// Test for tag.
andi(t0, value, JNIHandles::tag_mask);
bnez(t0, tagged);
// Test for jweak tag.
andi(t0, value, JNIHandles::weak_tag_mask);
beqz(t0, not_weak);
// Resolve jweak.
access_load_at(T_OBJECT, IN_NATIVE | ON_PHANTOM_OOP_REF, value,
Address(value, -JNIHandles::weak_tag_value), tmp1, tmp2);
// Resolve local handle
access_load_at(T_OBJECT, IN_NATIVE | AS_RAW, value, Address(value, 0), tmp1, tmp2);
verify_oop(value);
j(done);
bind(not_weak);
// Resolve (untagged) jobject.
access_load_at(T_OBJECT, IN_NATIVE, value, Address(value, 0), tmp1, tmp2);
bind(tagged);
// Test for jweak tag.
andi(t0, value, JNIHandles::TypeTag::weak_global);
bnez(t0, weak_tagged);
// Resolve global handle
access_load_at(T_OBJECT, IN_NATIVE, value,
Address(value, -JNIHandles::TypeTag::global), tmp1, tmp2);
j(done);
bind(weak_tagged);
// Resolve jweak.
access_load_at(T_OBJECT, IN_NATIVE | ON_PHANTOM_OOP_REF, value,
Address(value, -JNIHandles::TypeTag::weak_global), tmp1, tmp2);
verify_oop(value);
bind(done);
}
void MacroAssembler::resolve_global_jobject(Register value, Register tmp1, Register tmp2) {
assert_different_registers(value, tmp1, tmp2);
Label done;
beqz(value, done); // Use NULL as-is.
#ifdef ASSERT
{
Label valid_global_tag;
andi(t0, value, JNIHandles::TypeTag::global); // Test for global tag.
bnez(t0, valid_global_tag);
stop("non global jobject using resolve_global_jobject");
bind(valid_global_tag);
}
#endif
// Resolve global handle
access_load_at(T_OBJECT, IN_NATIVE, value,
Address(value, -JNIHandles::TypeTag::global), tmp1, tmp2);
verify_oop(value);
bind(done);
}

View file

@ -181,6 +181,7 @@ class MacroAssembler: public Assembler {
void resolve_weak_handle(Register result, Register tmp1, Register tmp2);
void resolve_oop_handle(Register result, Register tmp1, Register tmp2);
void resolve_jobject(Register value, Register tmp1, Register tmp2);
void resolve_global_jobject(Register value, Register tmp1, Register tmp2);
void movoop(Register dst, jobject obj);
void mov_metadata(Register dst, Metadata* obj);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
* Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@ -3979,14 +3979,8 @@ class StubGenerator: public StubCodeGenerator {
static void jfr_epilogue(MacroAssembler* _masm) {
__ reset_last_Java_frame(true);
Label null_jobject;
__ beqz(x10, null_jobject);
DecoratorSet decorators = ACCESS_READ | IN_NATIVE;
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->load_at(_masm, decorators, T_OBJECT, x10, Address(x10, 0), t0, t1);
__ bind(null_jobject);
__ resolve_global_jobject(x10, t0, t1);
}
// For c2: c_rarg0 is junk, call to runtime to write a checkpoint.
// It returns a jobject handle to the event writer.
// The handle is dereferenced and the return value is the event writer oop.
@ -4012,6 +4006,7 @@ class StubGenerator: public StubCodeGenerator {
address the_pc = __ pc();
jfr_prologue(the_pc, _masm, xthread);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1);
jfr_epilogue(_masm);
__ leave();
__ ret();

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2019 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -397,10 +397,10 @@ void G1BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value
__ z_ltgr(tmp1, value);
__ z_bre(Ldone); // Use NULL result as-is.
__ z_nill(value, ~JNIHandles::weak_tag_mask);
__ z_nill(value, ~JNIHandles::tag_mask);
__ z_lg(value, 0, value); // Resolve (untagged) jobject.
__ z_tmll(tmp1, JNIHandles::weak_tag_mask); // Test for jweak tag.
__ z_tmll(tmp1, JNIHandles::TypeTag::weak_global); // Test for jweak tag.
__ z_braz(Lnot_weak);
__ verify_oop(value, FILE_AND_LINE);
DecoratorSet decorators = IN_NATIVE | ON_PHANTOM_OOP_REF;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -110,7 +110,7 @@ void BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value,
__ z_ltgr(tmp1, value);
__ z_bre(Ldone); // Use NULL result as-is.
__ z_nill(value, ~JNIHandles::weak_tag_mask);
__ z_nill(value, ~JNIHandles::tag_mask);
__ z_lg(value, 0, value); // Resolve (untagged) jobject.
__ verify_oop(value, FILE_AND_LINE);
@ -119,7 +119,7 @@ void BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value,
void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,
Register obj, Register tmp, Label& slowpath) {
__ z_nill(obj, ~JNIHandles::weak_tag_mask);
__ z_nill(obj, ~JNIHandles::tag_mask);
__ z_lg(obj, 0, obj); // Resolve (untagged) jobject.
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -197,7 +197,7 @@ void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators
void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,
Register obj, Register tmp, Label& slowpath) {
__ clear_jweak_tag(obj);
__ clear_jobject_tag(obj);
__ movptr(obj, Address(obj, 0));
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -93,7 +93,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
// rdx is data dependent on rcx.
__ movptr(rax, Address(rsp, 3*wordSize)); // jfieldID
__ clear_jweak_tag(rdx);
__ clear_jobject_tag(rdx);
__ movptr(rdx, Address(rdx, 0)); // *obj
__ shrptr (rax, 2); // offset
@ -214,7 +214,7 @@ address JNI_FastGetField::generate_fast_get_long_field() {
// rdx is data dependent on rcx.
__ movptr(rsi, Address(rsp, 4*wordSize)); // jfieldID
__ clear_jweak_tag(rdx);
__ clear_jobject_tag(rdx);
__ movptr(rdx, Address(rdx, 0)); // *obj
__ shrptr(rsi, 2); // offset
@ -304,7 +304,7 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) {
// rdx is data dependent on rcx.
__ movptr(rax, Address(rsp, 3*wordSize)); // jfieldID
__ clear_jweak_tag(rdx);
__ clear_jobject_tag(rdx);
__ movptr(rdx, Address(rdx, 0)); // *obj
__ shrptr(rax, 2); // offset

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -35,7 +35,7 @@
#define __ masm->
#define BUFFER_SIZE 30*wordSize
#define BUFFER_SIZE 40*wordSize
// Common register usage:
// rax/xmm0: result

View file

@ -3874,31 +3874,69 @@ void MacroAssembler::vpermd(XMMRegister dst, XMMRegister nds, AddressLiteral sr
}
}
void MacroAssembler::clear_jweak_tag(Register possibly_jweak) {
const int32_t inverted_jweak_mask = ~static_cast<int32_t>(JNIHandles::weak_tag_mask);
STATIC_ASSERT(inverted_jweak_mask == -2); // otherwise check this code
void MacroAssembler::clear_jobject_tag(Register possibly_non_local) {
const int32_t inverted_mask = ~static_cast<int32_t>(JNIHandles::tag_mask);
STATIC_ASSERT(inverted_mask == -4); // otherwise check this code
// The inverted mask is sign-extended
andptr(possibly_jweak, inverted_jweak_mask);
andptr(possibly_non_local, inverted_mask);
}
void MacroAssembler::resolve_jobject(Register value,
Register thread,
Register tmp) {
assert_different_registers(value, thread, tmp);
Label done, not_weak;
Label done, tagged, weak_tagged;
testptr(value, value);
jcc(Assembler::zero, done); // Use NULL as-is.
testptr(value, JNIHandles::weak_tag_mask); // Test for jweak tag.
jcc(Assembler::zero, not_weak);
// Resolve jweak.
access_load_at(T_OBJECT, IN_NATIVE | ON_PHANTOM_OOP_REF,
value, Address(value, -JNIHandles::weak_tag_value), tmp, thread);
jcc(Assembler::zero, done); // Use NULL as-is.
testptr(value, JNIHandles::tag_mask); // Test for tag.
jcc(Assembler::notZero, tagged);
// Resolve local handle
access_load_at(T_OBJECT, IN_NATIVE | AS_RAW, value, Address(value, 0), tmp, thread);
verify_oop(value);
jmp(done);
bind(not_weak);
// Resolve (untagged) jobject.
access_load_at(T_OBJECT, IN_NATIVE, value, Address(value, 0), tmp, thread);
bind(tagged);
testptr(value, JNIHandles::TypeTag::weak_global); // Test for weak tag.
jcc(Assembler::notZero, weak_tagged);
// Resolve global handle
access_load_at(T_OBJECT, IN_NATIVE, value, Address(value, -JNIHandles::TypeTag::global), tmp, thread);
verify_oop(value);
jmp(done);
bind(weak_tagged);
// Resolve jweak.
access_load_at(T_OBJECT, IN_NATIVE | ON_PHANTOM_OOP_REF,
value, Address(value, -JNIHandles::TypeTag::weak_global), tmp, thread);
verify_oop(value);
bind(done);
}
void MacroAssembler::resolve_global_jobject(Register value,
Register thread,
Register tmp) {
assert_different_registers(value, thread, tmp);
Label done;
testptr(value, value);
jcc(Assembler::zero, done); // Use NULL as-is.
#ifdef ASSERT
{
Label valid_global_tag;
testptr(value, JNIHandles::TypeTag::global); // Test for global tag.
jcc(Assembler::notZero, valid_global_tag);
stop("non global jobject using resolve_global_jobject");
bind(valid_global_tag);
}
#endif
// Resolve global handle
access_load_at(T_OBJECT, IN_NATIVE, value, Address(value, -JNIHandles::TypeTag::global), tmp, thread);
verify_oop(value);
bind(done);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -326,8 +326,9 @@ class MacroAssembler: public Assembler {
void reset_last_Java_frame(bool clear_fp);
// jobjects
void clear_jweak_tag(Register possibly_jweak);
void clear_jobject_tag(Register possibly_non_local);
void resolve_jobject(Register value, Register thread, Register tmp);
void resolve_global_jobject(Register value, Register thread, Register tmp);
// C 'boolean' to Java boolean: x == 0 ? 0 : 1
void c2bool(Register x);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -4011,13 +4011,7 @@ class StubGenerator: public StubCodeGenerator {
Register java_thread = rdi;
__ get_thread(java_thread);
__ reset_last_Java_frame(java_thread, true);
Label null_jobject;
__ testptr(rax, rax);
__ jcc(Assembler::zero, null_jobject);
DecoratorSet decorators = ACCESS_READ | IN_NATIVE;
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->load_at(masm, decorators, T_OBJECT, rax, Address(rax, 0), noreg, java_thread);
__ bind(null_jobject);
__ resolve_global_jobject(rax, java_thread, rdx);
}
// For c2: c_rarg0 is junk, call to runtime to write a checkpoint.
@ -4036,7 +4030,7 @@ class StubGenerator: public StubCodeGenerator {
framesize
};
int insts_size = 512;
int insts_size = 1024;
int locs_size = 64;
CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size);
OopMapSet* oop_maps = new OopMapSet();

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -3504,7 +3504,7 @@ RuntimeStub* StubGenerator::generate_jfr_write_checkpoint() {
framesize // inclusive of return address
};
CodeBuffer code("jfr_write_checkpoint", 512, 64);
CodeBuffer code("jfr_write_checkpoint", 1024, 64);
MacroAssembler* _masm = new MacroAssembler(&code);
address start = __ pc();
@ -3519,14 +3519,7 @@ RuntimeStub* StubGenerator::generate_jfr_write_checkpoint() {
__ reset_last_Java_frame(true);
// rax is jobject handle result, unpack and process it through a barrier.
Label L_null_jobject;
__ testptr(rax, rax);
__ jcc(Assembler::zero, L_null_jobject);
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->load_at(_masm, ACCESS_READ | IN_NATIVE, T_OBJECT, rax, Address(rax, 0), c_rarg0, r15_thread);
__ bind(L_null_jobject);
__ resolve_global_jobject(rax, r15_thread, c_rarg0);
__ leave();
__ ret(0);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -1115,7 +1115,8 @@ void nmethod::fix_oop_relocations(address begin, address end, bool initialize_im
oop_Relocation* reloc = iter.oop_reloc();
if (initialize_immediates && reloc->oop_is_immediate()) {
oop* dest = reloc->oop_addr();
initialize_immediate_oop(dest, cast_from_oop<jobject>(*dest));
jobject obj = *reinterpret_cast<jobject*>(dest);
initialize_immediate_oop(dest, obj);
}
// Refresh the oop-related bits of this instruction.
reloc->fix_oop_relocation();

View file

@ -176,7 +176,7 @@ void CompileTask::mark_on_stack() {
}
bool CompileTask::is_unloaded() const {
return _method_holder != NULL && JNIHandles::is_weak_global_handle(_method_holder) && JNIHandles::is_global_weak_cleared(_method_holder);
return _method_holder != NULL && JNIHandles::is_weak_global_handle(_method_holder) && JNIHandles::is_weak_global_cleared(_method_holder);
}
// RedefineClasses support

View file

@ -51,6 +51,7 @@
#include "opto/rootnode.hpp"
#include "opto/subnode.hpp"
#include "prims/unsafe.hpp"
#include "runtime/jniHandles.inline.hpp"
#include "runtime/objectMonitor.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
@ -3124,7 +3125,8 @@ bool LibraryCallKit::inline_native_getEventWriter() {
ciInstanceKlass* const instklass_EventWriter = klass_EventWriter->as_instance_klass();
const TypeKlassPtr* const aklass = TypeKlassPtr::make(instklass_EventWriter);
const TypeOopPtr* const xtype = aklass->as_instance_type();
Node* event_writer = access_load(jobj, xtype, T_OBJECT, IN_NATIVE | C2_CONTROL_DEPENDENT_LOAD);
Node* jobj_untagged = _gvn.transform(new AddPNode(top(), jobj, _gvn.MakeConX(-JNIHandles::TypeTag::global)));
Node* event_writer = access_load(jobj_untagged, xtype, T_OBJECT, IN_NATIVE | C2_CONTROL_DEPENDENT_LOAD);
// Load the current thread id from the event writer object.
Node* const event_writer_tid = load_field_from_object(event_writer, "threadID", "J");

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -66,6 +66,7 @@ jobject JNIHandles::make_local(JavaThread* thread, oop obj, AllocFailType alloc_
} else {
assert(oopDesc::is_oop(obj), "not an oop");
assert(!current_thread_in_native(), "must not be in native");
STATIC_ASSERT(TypeTag::local == 0);
return thread->active_handles()->allocate_handle(thread, obj, alloc_failmode);
}
}
@ -91,9 +92,10 @@ jobject JNIHandles::make_global(Handle obj, AllocFailType alloc_failmode) {
oop* ptr = global_handles()->allocate();
// Return NULL on allocation failure.
if (ptr != NULL) {
assert(*ptr == NULL, "invariant");
assert(NativeAccess<AS_NO_KEEPALIVE>::oop_load(ptr) == oop(NULL), "invariant");
NativeAccess<>::oop_store(ptr, obj());
res = reinterpret_cast<jobject>(ptr);
char* tptr = reinterpret_cast<char*>(ptr) + TypeTag::global;
res = reinterpret_cast<jobject>(tptr);
} else {
report_handle_allocation_failure(alloc_failmode, "global");
}
@ -102,20 +104,20 @@ jobject JNIHandles::make_global(Handle obj, AllocFailType alloc_failmode) {
return res;
}
jobject JNIHandles::make_weak_global(Handle obj, AllocFailType alloc_failmode) {
jweak JNIHandles::make_weak_global(Handle obj, AllocFailType alloc_failmode) {
assert(!Universe::heap()->is_gc_active(), "can't extend the root set during GC");
assert(!current_thread_in_native(), "must not be in native");
jobject res = NULL;
jweak res = NULL;
if (!obj.is_null()) {
// ignore null handles
assert(oopDesc::is_oop(obj()), "not an oop");
oop* ptr = weak_global_handles()->allocate();
// Return NULL on allocation failure.
if (ptr != NULL) {
assert(*ptr == NULL, "invariant");
assert(NativeAccess<AS_NO_KEEPALIVE>::oop_load(ptr) == oop(NULL), "invariant");
NativeAccess<ON_PHANTOM_OOP_REF>::oop_store(ptr, obj());
char* tptr = reinterpret_cast<char*>(ptr) + weak_tag_value;
res = reinterpret_cast<jobject>(tptr);
char* tptr = reinterpret_cast<char*>(ptr) + TypeTag::weak_global;
res = reinterpret_cast<jweak>(tptr);
} else {
report_handle_allocation_failure(alloc_failmode, "weak global");
}
@ -135,28 +137,25 @@ oop JNIHandles::resolve_external_guard(jobject handle) {
return result;
}
bool JNIHandles::is_global_weak_cleared(jweak handle) {
bool JNIHandles::is_weak_global_cleared(jweak handle) {
assert(handle != NULL, "precondition");
assert(is_jweak(handle), "not a weak handle");
oop* oop_ptr = jweak_ptr(handle);
oop* oop_ptr = weak_global_ptr(handle);
oop value = NativeAccess<ON_PHANTOM_OOP_REF | AS_NO_KEEPALIVE>::oop_load(oop_ptr);
return value == NULL;
}
void JNIHandles::destroy_global(jobject handle) {
if (handle != NULL) {
assert(!is_jweak(handle), "wrong method for destroying jweak");
oop* oop_ptr = jobject_ptr(handle);
oop* oop_ptr = global_ptr(handle);
NativeAccess<>::oop_store(oop_ptr, (oop)NULL);
global_handles()->release(oop_ptr);
}
}
void JNIHandles::destroy_weak_global(jobject handle) {
void JNIHandles::destroy_weak_global(jweak handle) {
if (handle != NULL) {
assert(is_jweak(handle), "JNI handle not jweak");
oop* oop_ptr = jweak_ptr(handle);
oop* oop_ptr = weak_global_ptr(handle);
NativeAccess<ON_PHANTOM_OOP_REF>::oop_store(oop_ptr, (oop)NULL);
weak_global_handles()->release(oop_ptr);
}
@ -184,12 +183,12 @@ inline bool is_storage_handle(const OopStorage* storage, const oop* ptr) {
jobjectRefType JNIHandles::handle_type(JavaThread* thread, jobject handle) {
assert(handle != NULL, "precondition");
jobjectRefType result = JNIInvalidRefType;
if (is_jweak(handle)) {
if (is_storage_handle(weak_global_handles(), jweak_ptr(handle))) {
if (is_weak_global_tagged(handle)) {
if (is_storage_handle(weak_global_handles(), weak_global_ptr(handle))) {
result = JNIWeakGlobalRefType;
}
} else {
switch (global_handles()->allocation_status(jobject_ptr(handle))) {
} else if (is_global_tagged(handle)) {
switch (global_handles()->allocation_status(global_ptr(handle))) {
case OopStorage::ALLOCATED_ENTRY:
result = JNIGlobalRefType;
break;
@ -197,16 +196,16 @@ jobjectRefType JNIHandles::handle_type(JavaThread* thread, jobject handle) {
case OopStorage::UNALLOCATED_ENTRY:
break; // Invalid global handle
case OopStorage::INVALID_ENTRY:
// Not in global storage. Might be a local handle.
if (is_local_handle(thread, handle) || is_frame_handle(thread, handle)) {
result = JNILocalRefType;
}
break;
default:
ShouldNotReachHere();
}
} else {
// Not in global storage. Might be a local handle.
if (is_local_handle(thread, handle) || is_frame_handle(thread, handle)) {
result = JNILocalRefType;
} else {
ShouldNotReachHere();
}
}
return result;
}
@ -243,13 +242,15 @@ bool JNIHandles::is_frame_handle(JavaThread* thr, jobject handle) {
bool JNIHandles::is_global_handle(jobject handle) {
assert(handle != NULL, "precondition");
return !is_jweak(handle) && is_storage_handle(global_handles(), jobject_ptr(handle));
assert(!is_global_tagged(handle) || is_storage_handle(global_handles(), global_ptr(handle)), "invalid storage");
return is_global_tagged(handle);
}
bool JNIHandles::is_weak_global_handle(jobject handle) {
assert(handle != NULL, "precondition");
return is_jweak(handle) && is_storage_handle(weak_global_handles(), jweak_ptr(handle));
assert(!is_weak_global_tagged(handle) || is_storage_handle(weak_global_handles(), weak_global_ptr(handle)), "invalid storage");
return is_weak_global_tagged(handle);
}
// We assume this is called at a safepoint: no lock is needed.
@ -455,7 +456,7 @@ jobject JNIHandleBlock::allocate_handle(JavaThread* caller, oop obj, AllocFailTy
// Try last block
if (_last->_top < block_size_in_oops) {
oop* handle = (oop*)&(_last->_handles)[_last->_top++];
NativeAccess<IS_DEST_UNINITIALIZED>::oop_store(handle, obj);
*handle = obj;
return (jobject) handle;
}
@ -463,7 +464,7 @@ jobject JNIHandleBlock::allocate_handle(JavaThread* caller, oop obj, AllocFailTy
if (_free_list != NULL) {
oop* handle = (oop*)_free_list;
_free_list = (uintptr_t*) untag_free_list(*_free_list);
NativeAccess<IS_DEST_UNINITIALIZED>::oop_store(handle, obj);
*handle = obj;
return (jobject) handle;
}
// Check if unused block follow last

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -45,9 +45,12 @@ class JNIHandles : AllStatic {
static OopStorage* global_handles();
static OopStorage* weak_global_handles();
inline static bool is_jweak(jobject handle);
inline static oop* jobject_ptr(jobject handle); // NOT jweak!
inline static oop* jweak_ptr(jobject handle);
inline static bool is_local_tagged(jobject handle);
inline static bool is_weak_global_tagged(jobject handle);
inline static bool is_global_tagged(jobject handle);
inline static oop* local_ptr(jobject handle);
inline static oop* global_ptr(jobject handle);
inline static oop* weak_global_ptr(jweak handle);
template <DecoratorSet decorators, bool external_guard> inline static oop resolve_impl(jobject handle);
@ -59,18 +62,24 @@ class JNIHandles : AllStatic {
static bool current_thread_in_native();
public:
// Low tag bit in jobject used to distinguish a jweak. jweak is
// type equivalent to jobject, but there are places where we need to
// be able to distinguish jweak values from other jobjects, and
// is_weak_global_handle is unsuitable for performance reasons. To
// provide such a test we add weak_tag_value to the (aligned) byte
// address designated by the jobject to produce the corresponding
// jweak. Accessing the value of a jobject must account for it
// being a possibly offset jweak.
static const uintptr_t weak_tag_size = 1;
static const uintptr_t weak_tag_alignment = (1u << weak_tag_size);
static const uintptr_t weak_tag_mask = weak_tag_alignment - 1;
static const int weak_tag_value = 1;
// Low tag bits in jobject used to distinguish its type. Checking
// the underlying storage type is unsuitable for performance reasons.
enum TypeTag {
local = 0b00,
weak_global = 0b01,
global = 0b10,
};
private:
inline static bool is_tagged_with(jobject handle, TypeTag tag);
public:
static const uintptr_t tag_size = 2;
static const uintptr_t tag_mask = ((1u << tag_size) - 1u);
STATIC_ASSERT((TypeTag::local & tag_mask) == TypeTag::local);
STATIC_ASSERT((TypeTag::weak_global & tag_mask) == TypeTag::weak_global);
STATIC_ASSERT((TypeTag::global & tag_mask) == TypeTag::global);
// Resolve handle into oop
inline static oop resolve(jobject handle);
@ -94,10 +103,10 @@ class JNIHandles : AllStatic {
static void destroy_global(jobject handle);
// Weak global handles
static jobject make_weak_global(Handle obj,
AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM);
static void destroy_weak_global(jobject handle);
static bool is_global_weak_cleared(jweak handle); // Test jweak without resolution
static jweak make_weak_global(Handle obj,
AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM);
static void destroy_weak_global(jweak handle);
static bool is_weak_global_cleared(jweak handle); // Test jweak without resolution
// Debugging
static void print_on(outputStream* st);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -32,20 +32,37 @@
#include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp"
inline bool JNIHandles::is_jweak(jobject handle) {
STATIC_ASSERT(weak_tag_size == 1);
STATIC_ASSERT(weak_tag_value == 1);
return (reinterpret_cast<uintptr_t>(handle) & weak_tag_mask) != 0;
inline bool JNIHandles::is_tagged_with(jobject handle, TypeTag tag) {
return (reinterpret_cast<uintptr_t>(handle) & tag_mask) == tag;
}
inline oop* JNIHandles::jobject_ptr(jobject handle) {
assert(!is_jweak(handle), "precondition");
inline bool JNIHandles::is_local_tagged(jobject handle) {
return is_tagged_with(handle, TypeTag::local);
}
inline bool JNIHandles::is_weak_global_tagged(jobject handle) {
return is_tagged_with(handle, TypeTag::weak_global);
}
inline bool JNIHandles::is_global_tagged(jobject handle) {
return is_tagged_with(handle, TypeTag::global);
}
inline oop* JNIHandles::local_ptr(jobject handle) {
assert(is_local_tagged(handle), "precondition");
STATIC_ASSERT(TypeTag::local == 0);
return reinterpret_cast<oop*>(handle);
}
inline oop* JNIHandles::jweak_ptr(jobject handle) {
assert(is_jweak(handle), "precondition");
char* ptr = reinterpret_cast<char*>(handle) - weak_tag_value;
inline oop* JNIHandles::global_ptr(jobject handle) {
assert(is_global_tagged(handle), "precondition");
char* ptr = reinterpret_cast<char*>(handle) - TypeTag::global;
return reinterpret_cast<oop*>(ptr);
}
inline oop* JNIHandles::weak_global_ptr(jweak handle) {
assert(is_weak_global_tagged(handle), "precondition");
char* ptr = reinterpret_cast<char*>(handle) - TypeTag::weak_global;
return reinterpret_cast<oop*>(ptr);
}
@ -55,10 +72,15 @@ inline oop JNIHandles::resolve_impl(jobject handle) {
assert(handle != NULL, "precondition");
assert(!current_thread_in_native(), "must not be in native");
oop result;
if (is_jweak(handle)) { // Unlikely
result = NativeAccess<ON_PHANTOM_OOP_REF|decorators>::oop_load(jweak_ptr(handle));
if (is_weak_global_tagged(handle)) { // Unlikely
result = NativeAccess<ON_PHANTOM_OOP_REF|decorators>::oop_load(weak_global_ptr(handle));
} else if (is_global_tagged(handle)) {
result = NativeAccess<decorators>::oop_load(global_ptr(handle));
// Construction of jobjects canonicalize a null value into a null
// jobject, so for non-jweak the pointee should never be null.
assert(external_guard || result != NULL, "Invalid JNI handle");
} else {
result = NativeAccess<decorators>::oop_load(jobject_ptr(handle));
result = *local_ptr(handle);
// Construction of jobjects canonicalize a null value into a null
// jobject, so for non-jweak the pointee should never be null.
assert(external_guard || result != NULL, "Invalid JNI handle");
@ -97,8 +119,7 @@ inline oop JNIHandles::resolve_non_null(jobject handle) {
inline void JNIHandles::destroy_local(jobject handle) {
if (handle != NULL) {
assert(!is_jweak(handle), "Invalid JNI local handle");
NativeAccess<>::oop_store(jobject_ptr(handle), (oop)NULL);
*local_ptr(handle) = NULL;
}
}

View file

@ -1,4 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019 SAP SE and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -28,20 +29,26 @@
with primitive type are generated.
* @requires vm.jvmti
* @compile FastGetField.java
* @run main/othervm/native -agentlib:FastGetField -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyJNIFields FastGetField
* @run main/othervm/native -agentlib:FastGetField -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyJNIFields -XX:+UnlockDiagnosticVMOptions -XX:+ForceUnreachable -XX:+SafepointALot -XX:GuaranteedSafepointInterval=1 FastGetField
* @run main/othervm/native -agentlib:FastGetField -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyJNIFields FastGetField 0
* @run main/othervm/native -agentlib:FastGetField -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyJNIFields FastGetField 1
* @run main/othervm/native -agentlib:FastGetField -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyJNIFields FastGetField 2
* @run main/othervm/native -agentlib:FastGetField -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyJNIFields -XX:+UnlockDiagnosticVMOptions -XX:+ForceUnreachable -XX:+SafepointALot -XX:GuaranteedSafepointInterval=1 FastGetField 0
* @run main/othervm/native -agentlib:FastGetField -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyJNIFields -XX:+UnlockDiagnosticVMOptions -XX:+ForceUnreachable -XX:+SafepointALot -XX:GuaranteedSafepointInterval=1 FastGetField 1
* @run main/othervm/native -agentlib:FastGetField -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyJNIFields -XX:+UnlockDiagnosticVMOptions -XX:+ForceUnreachable -XX:+SafepointALot -XX:GuaranteedSafepointInterval=1 FastGetField 2
*/
import java.lang.reflect.Field;
public class FastGetField {
private static final String agentLib = "FastGetField";
private native boolean initFieldIDs(Class c);
private native boolean initWatchers(Class c);
public native void registerGlobal(MyItem i);
public native void registerWeak(MyItem i);
public native long accessFields(MyItem i);
public native long accessFieldsViaHandle();
public static native long getFieldAccessCount();
static final int loop_cnt = 10000;
@ -92,16 +99,43 @@ public class FastGetField {
}
}
private int mode;
private MyItem obj;
private FastGetField(int mode) {
this.mode = mode;
this.obj = new MyItem();
if (mode == 0) {
// Direct
} else if (mode == 1) {
registerGlobal(this.obj);
} else if ( mode == 2) {
registerWeak(this.obj);
} else {
throw new IllegalArgumentException("Unexpected mode");
}
}
private long accessFields() {
if (mode == 0) {
return accessFields(obj);
}
// Otherwise through a handle
return accessFieldsViaHandle();
}
public void TestFieldAccess() throws Exception {
MyItem i = new MyItem();
if (!initFieldIDs(MyItem.class)) throw new RuntimeException("FieldID initialization failed!");
long duration = System.nanoTime();
for (int c = 0; c < loop_cnt; ++c) {
if (accessFields(i) != 0l) throw new RuntimeException("Wrong initial result!");
i.change_values();
if (accessFields(i) != 8l) throw new RuntimeException("Wrong result after changing!");
i.reset_values();
if (accessFields() != 0l) throw new RuntimeException("Wrong initial result!");
obj.change_values();
if (accessFields() != 8l) throw new RuntimeException("Wrong result after changing!");
obj.reset_values();
}
duration = System.nanoTime() - duration;
System.out.println(loop_cnt + " iterations took " + duration + "ns.");
@ -112,14 +146,20 @@ public class FastGetField {
if (!initWatchers(MyItem.class)) throw new RuntimeException("JVMTI missing!");
// Try again with watchers.
if (accessFields(i) != 0l) throw new RuntimeException("Wrong initial result!");
i.change_values();
if (accessFields(i) != 8l) throw new RuntimeException("Wrong result after changing!");
if (accessFields() != 0l) throw new RuntimeException("Wrong initial result!");
obj.change_values();
if (accessFields() != 8l) throw new RuntimeException("Wrong result after changing!");
if (getFieldAccessCount() != 16) throw new RuntimeException("Unexpected event count!");
}
public static void main(String[] args) throws Exception {
FastGetField inst = new FastGetField();
if (args.length != 1) {
throw new IllegalArgumentException("Expected one argument");
}
int mode = Integer.parseInt(args[0]);
FastGetField inst = new FastGetField(mode);
inst.TestFieldAccess();
}
}

View file

@ -1,4 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2022 SAP SE and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -32,7 +33,7 @@ static const char* fields[] = { "Z", "B", "C", "S", "I", "J", "F", "D" };
#define NUM_FIELDS (sizeof fields / sizeof fields[0])
static jfieldID fieldIDs[NUM_FIELDS];
static jlong fieldAccessCount = 0;
static jobject objHandle;
JNIEXPORT jboolean JNICALL Java_FastGetField_initFieldIDs(JNIEnv *env, jobject this, jclass c) {
for (int i = 0; i < (int)NUM_FIELDS; ++i) {
@ -63,6 +64,13 @@ JNIEXPORT jboolean JNICALL Java_FastGetField_initWatchers(JNIEnv *env, jobject t
return JNI_TRUE;
}
JNIEXPORT void JNICALL Java_FastGetField_registerGlobal(JNIEnv *env, jobject this, jobject obj) {
objHandle = (*env)->NewGlobalRef(env, obj);
}
JNIEXPORT void JNICALL Java_FastGetField_registerWeak(JNIEnv *env, jobject this, jobject obj) {
objHandle = (*env)->NewWeakGlobalRef(env, obj);
}
JNIEXPORT jlong JNICALL Java_FastGetField_accessFields(JNIEnv *env, jobject this, jobject obj) {
return
@ -76,6 +84,9 @@ JNIEXPORT jlong JNICALL Java_FastGetField_accessFields(JNIEnv *env, jobject this
(jlong)((*env)->GetDoubleField(env, obj, fieldIDs[7]));
}
JNIEXPORT jlong JNICALL Java_FastGetField_accessFieldsViaHandle(JNIEnv *env, jobject this) {
return Java_FastGetField_accessFields(env, this, objHandle);
}
JNIEXPORT jlong JNICALL Java_FastGetField_getFieldAccessCount(JNIEnv *env, jclass c) {
return fieldAccessCount;