From c7056737e33d3d5a6ec24639d46b9e3e7a8da01a Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Wed, 18 Jan 2023 09:21:08 +0000 Subject: [PATCH] 8299089: Instrument global jni handles with tag to make them distinguishable Co-authored-by: Stefan Karlsson Co-authored-by: Martin Doerr Co-authored-by: Leslie Zhai Reviewed-by: eosterlund, stefank, ayang --- .../gc/shared/barrierSetAssembler_aarch64.cpp | 6 +- .../cpu/aarch64/macroAssembler_aarch64.cpp | 54 +++++++++++++--- .../cpu/aarch64/macroAssembler_aarch64.hpp | 1 + .../cpu/aarch64/stubGenerator_aarch64.cpp | 9 +-- src/hotspot/cpu/arm/jniFastGetField_arm.cpp | 4 +- src/hotspot/cpu/arm/macroAssembler_arm.cpp | 59 +++++++++++++---- src/hotspot/cpu/arm/macroAssembler_arm.hpp | 3 +- src/hotspot/cpu/arm/stubGenerator_arm.cpp | 10 +-- .../ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp | 6 +- .../ppc/gc/shared/barrierSetAssembler_ppc.cpp | 58 +++++++++++++---- .../ppc/gc/shared/barrierSetAssembler_ppc.hpp | 5 +- .../shared/modRefBarrierSetAssembler_ppc.cpp | 4 +- src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 8 ++- src/hotspot/cpu/ppc/macroAssembler_ppc.hpp | 5 +- src/hotspot/cpu/ppc/stubGenerator_ppc.cpp | 10 +-- .../gc/shared/barrierSetAssembler_riscv.cpp | 6 +- .../cpu/riscv/macroAssembler_riscv.cpp | 54 +++++++++++++--- .../cpu/riscv/macroAssembler_riscv.hpp | 1 + src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 11 +--- .../s390/gc/g1/g1BarrierSetAssembler_s390.cpp | 6 +- .../gc/shared/barrierSetAssembler_s390.cpp | 6 +- .../x86/gc/shared/barrierSetAssembler_x86.cpp | 4 +- .../cpu/x86/jniFastGetField_x86_32.cpp | 8 +-- .../cpu/x86/jniFastGetField_x86_64.cpp | 4 +- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 64 +++++++++++++++---- src/hotspot/cpu/x86/macroAssembler_x86.hpp | 5 +- src/hotspot/cpu/x86/stubGenerator_x86_32.cpp | 12 +--- src/hotspot/cpu/x86/stubGenerator_x86_64.cpp | 13 +--- src/hotspot/share/code/nmethod.cpp | 5 +- src/hotspot/share/compiler/compileTask.cpp | 2 +- src/hotspot/share/opto/library_call.cpp | 4 +- src/hotspot/share/runtime/jniHandles.cpp | 63 +++++++++--------- src/hotspot/share/runtime/jniHandles.hpp | 49 ++++++++------ .../share/runtime/jniHandles.inline.hpp | 51 ++++++++++----- .../jni/FastGetField/FastGetField.java | 64 +++++++++++++++---- .../jni/FastGetField/libFastGetField.c | 13 +++- 36 files changed, 465 insertions(+), 222 deletions(-) diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp index 4d82b40484584..90b9b64e699e3 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp @@ -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 } diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index bfda0d54d87cd..8cd6d8039f102 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -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); + + // Resolve local handle + access_load_at(T_OBJECT, IN_NATIVE | AS_RAW, value, Address(value, 0), tmp1, tmp2); + verify_oop(value); + b(done); - STATIC_ASSERT(JNIHandles::weak_tag_mask == 1u); - tbz(value, 0, not_weak); // Test for jweak tag. + bind(tagged); + STATIC_ASSERT(JNIHandles::TypeTag::weak_global == 0b1); + tbnz(value, 0, weak_tagged); // Test for weak tag. - // Resolve jweak. - access_load_at(T_OBJECT, IN_NATIVE | ON_PHANTOM_OOP_REF, value, - Address(value, -JNIHandles::weak_tag_value), tmp1, tmp2); + // Resolve global handle + access_load_at(T_OBJECT, IN_NATIVE, value, Address(value, -JNIHandles::TypeTag::global), 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(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); } diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index e376d35f1e47d..3a016552676fc 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -823,6 +823,7 @@ class MacroAssembler: public Assembler { 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); diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 96b067b0ca2fe..34fc3eff9ad4c 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -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(); diff --git a/src/hotspot/cpu/arm/jniFastGetField_arm.cpp b/src/hotspot/cpu/arm/jniFastGetField_arm.cpp index 22f09392317cb..45211e0d72122 100644 --- a/src/hotspot/cpu/arm/jniFastGetField_arm.cpp +++ b/src/hotspot/cpu/arm/jniFastGetField_arm.cpp @@ -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. diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.cpp b/src/hotspot/cpu/arm/macroAssembler_arm.cpp index 8744ac6dedd65..a45387d8cfeef 100644 --- a/src/hotspot/cpu/arm/macroAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/macroAssembler_arm.cpp @@ -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); } diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.hpp b/src/hotspot/cpu/arm/macroAssembler_arm.hpp index 50b56bfe79aec..9b56912b8865b 100644 --- a/src/hotspot/cpu/arm/macroAssembler_arm.hpp +++ b/src/hotspot/cpu/arm/macroAssembler_arm.hpp @@ -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 @@ class MacroAssembler: public Assembler { } void resolve_jobject(Register value, Register tmp1, Register tmp2); + void resolve_global_jobject(Register value, Register tmp1, Register tmp2); void nop() { mov(R0, R0); diff --git a/src/hotspot/cpu/arm/stubGenerator_arm.cpp b/src/hotspot/cpu/arm/stubGenerator_arm.cpp index d520491561904..c970681873eef 100644 --- a/src/hotspot/cpu/arm/stubGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/stubGenerator_arm.cpp @@ -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(); diff --git a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp index 85c24eb37f57c..bda0cff342914 100644 --- a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp @@ -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. diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp index 9e87148109078..051e1d08aec8b 100644 --- a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp @@ -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. } diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.hpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.hpp index cf20f1ac4f40c..9ad474961cb0b 100644 --- a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.hpp @@ -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 @@ class BarrierSetAssembler: public CHeapObj { 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); diff --git a/src/hotspot/cpu/ppc/gc/shared/modRefBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/modRefBarrierSetAssembler_ppc.cpp index dad919ef1ce19..baa7a117b62e0 100644 --- a/src/hotspot/cpu/ppc/gc/shared/modRefBarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shared/modRefBarrierSetAssembler_ppc.cpp @@ -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); diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index fb6ec91161b58..99c73c45adc90 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -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) { diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index 9c0269cb259e6..06c9c297aa2fa 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -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, diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index 602d034f07bb0..97b84d85ca395 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -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); diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp index 60b5ffa41f848..d8d0beeadfa03 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp @@ -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 } diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index ebdb5f04dcef9..b79d115ce0b1a 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -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); + // Resolve local handle + access_load_at(T_OBJECT, IN_NATIVE | AS_RAW, value, Address(value, 0), tmp1, tmp2); + verify_oop(value); + j(done); + + bind(tagged); // Test for jweak tag. - andi(t0, value, JNIHandles::weak_tag_mask); - beqz(t0, not_weak); + 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::weak_tag_value), tmp1, tmp2); + Address(value, -JNIHandles::TypeTag::weak_global), 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(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); } diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 18c0e7057c490..79ecb7c510013 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -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); diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 4f34f824bd5ae..080f1956d5069 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -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(); diff --git a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp index cf8d424c24e71..8cb4b444ab729 100644 --- a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp @@ -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; diff --git a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp index 97df78d12d880..31fb02ebc6633 100644 --- a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp @@ -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. } diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp index 58df83d4e4df3..348fd00c9d409 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp @@ -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)); } diff --git a/src/hotspot/cpu/x86/jniFastGetField_x86_32.cpp b/src/hotspot/cpu/x86/jniFastGetField_x86_32.cpp index ae39adf8430e1..ae4215ccc4f16 100644 --- a/src/hotspot/cpu/x86/jniFastGetField_x86_32.cpp +++ b/src/hotspot/cpu/x86/jniFastGetField_x86_32.cpp @@ -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 diff --git a/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp b/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp index c79cce0d4b76d..b63218e04319f 100644 --- a/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp +++ b/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp @@ -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 diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index b3aab73913ada..cc08898374037 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -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(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(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); + 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(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::weak_tag_value), tmp, thread); + value, Address(value, -JNIHandles::TypeTag::weak_global), 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(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); } diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 2baff498df6ee..1c89191930604 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -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); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp index 028d04b86e49b..08b1faba32782 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp @@ -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(); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index d7a613052a32f..c3c2a59cf9a77 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -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); diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 64e2f575d68d4..508764f42d73e 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -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(*dest)); + jobject obj = *reinterpret_cast(dest); + initialize_immediate_oop(dest, obj); } // Refresh the oop-related bits of this instruction. reloc->fix_oop_relocation(); diff --git a/src/hotspot/share/compiler/compileTask.cpp b/src/hotspot/share/compiler/compileTask.cpp index c7ae68f2c0da7..d0181b636115b 100644 --- a/src/hotspot/share/compiler/compileTask.cpp +++ b/src/hotspot/share/compiler/compileTask.cpp @@ -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 diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 7108de9d73078..aeee633f51160 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -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"); diff --git a/src/hotspot/share/runtime/jniHandles.cpp b/src/hotspot/share/runtime/jniHandles.cpp index 9c5e675db5f57..4f89f0beab9b8 100644 --- a/src/hotspot/share/runtime/jniHandles.cpp +++ b/src/hotspot/share/runtime/jniHandles.cpp @@ -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::oop_load(ptr) == oop(NULL), "invariant"); NativeAccess<>::oop_store(ptr, obj()); - res = reinterpret_cast(ptr); + char* tptr = reinterpret_cast(ptr) + TypeTag::global; + res = reinterpret_cast(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::oop_load(ptr) == oop(NULL), "invariant"); NativeAccess::oop_store(ptr, obj()); - char* tptr = reinterpret_cast(ptr) + weak_tag_value; - res = reinterpret_cast(tptr); + char* tptr = reinterpret_cast(ptr) + TypeTag::weak_global; + res = reinterpret_cast(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::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::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::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::oop_store(handle, obj); + *handle = obj; return (jobject) handle; } // Check if unused block follow last diff --git a/src/hotspot/share/runtime/jniHandles.hpp b/src/hotspot/share/runtime/jniHandles.hpp index 9d5d4627960e4..367beca660005 100644 --- a/src/hotspot/share/runtime/jniHandles.hpp +++ b/src/hotspot/share/runtime/jniHandles.hpp @@ -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 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); diff --git a/src/hotspot/share/runtime/jniHandles.inline.hpp b/src/hotspot/share/runtime/jniHandles.inline.hpp index 48f11af3e5072..e77264fcd16a6 100644 --- a/src/hotspot/share/runtime/jniHandles.inline.hpp +++ b/src/hotspot/share/runtime/jniHandles.inline.hpp @@ -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(handle) & weak_tag_mask) != 0; +inline bool JNIHandles::is_tagged_with(jobject handle, TypeTag tag) { + return (reinterpret_cast(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(handle); } -inline oop* JNIHandles::jweak_ptr(jobject handle) { - assert(is_jweak(handle), "precondition"); - char* ptr = reinterpret_cast(handle) - weak_tag_value; +inline oop* JNIHandles::global_ptr(jobject handle) { + assert(is_global_tagged(handle), "precondition"); + char* ptr = reinterpret_cast(handle) - TypeTag::global; + return reinterpret_cast(ptr); +} + +inline oop* JNIHandles::weak_global_ptr(jweak handle) { + assert(is_weak_global_tagged(handle), "precondition"); + char* ptr = reinterpret_cast(handle) - TypeTag::weak_global; return reinterpret_cast(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::oop_load(jweak_ptr(handle)); + if (is_weak_global_tagged(handle)) { // Unlikely + result = NativeAccess::oop_load(weak_global_ptr(handle)); + } else if (is_global_tagged(handle)) { + result = NativeAccess::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::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; } } diff --git a/test/hotspot/jtreg/runtime/jni/FastGetField/FastGetField.java b/test/hotspot/jtreg/runtime/jni/FastGetField/FastGetField.java index b67cc28ce9301..fe55d8d4e8aff 100644 --- a/test/hotspot/jtreg/runtime/jni/FastGetField/FastGetField.java +++ b/test/hotspot/jtreg/runtime/jni/FastGetField/FastGetField.java @@ -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 void reset_values() { } } + 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 void TestFieldAccess() throws Exception { 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(); } } diff --git a/test/hotspot/jtreg/runtime/jni/FastGetField/libFastGetField.c b/test/hotspot/jtreg/runtime/jni/FastGetField/libFastGetField.c index 8d0b04fdad5dc..3ef1ada8e77a8 100644 --- a/test/hotspot/jtreg/runtime/jni/FastGetField/libFastGetField.c +++ b/test/hotspot/jtreg/runtime/jni/FastGetField/libFastGetField.c @@ -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;