# HG changeset patch # User phh # Date 1557261506 0 # Node ID 32bc598624bd33a1a8847e84f791559f18a69a49 # Parent acb9351e3a29dd621935a1723993e44d5975f4b2 8176100: [REDO][REDO] G1 Needs pre barrier on dereference of weak JNI handles Summary: Add tag bit to all JNI weak handles Reviewed-by: kbarrett, coleenp, tschatzl diff -r acb9351e3a29 -r 32bc598624bd src/cpu/ppc/vm/frame_ppc.cpp --- a/src/cpu/ppc/vm/frame_ppc.cpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/cpu/ppc/vm/frame_ppc.cpp Tue May 07 20:38:26 2019 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017 SAP AG. 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 @@ -190,10 +190,7 @@ switch (method->result_type()) { case T_OBJECT: case T_ARRAY: { - oop* obj_p = *(oop**)lresult; - oop obj = (obj_p == NULL) ? (oop)NULL : *obj_p; - assert(obj == NULL || Universe::heap()->is_in(obj), "sanity check"); - *oop_result = obj; + *oop_result = JNIHandles::resolve(*(jobject*)lresult); break; } // We use std/stfd to store the values. diff -r acb9351e3a29 -r 32bc598624bd src/cpu/ppc/vm/interpreter_ppc.cpp --- a/src/cpu/ppc/vm/interpreter_ppc.cpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/cpu/ppc/vm/interpreter_ppc.cpp Tue May 07 20:38:26 2019 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2015 SAP AG. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017 SAP AG. 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 @@ -413,11 +413,8 @@ case T_LONG: break; case T_OBJECT: - // unbox result if not null - __ cmpdi(CCR0, R3_RET, 0); - __ beq(CCR0, done); - __ ld(R3_RET, 0, R3_RET); - __ verify_oop(R3_RET); + // JNIHandles::resolve result. + __ resolve_jobject(R3_RET, R11_scratch1, R12_scratch2, /* needs_frame */ true); // kills R31 break; case T_FLOAT: break; diff -r acb9351e3a29 -r 32bc598624bd src/cpu/ppc/vm/macroAssembler_ppc.cpp --- a/src/cpu/ppc/vm/macroAssembler_ppc.cpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/cpu/ppc/vm/macroAssembler_ppc.cpp Tue May 07 20:38:26 2019 +0000 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2018, SAP SE. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2220,6 +2220,34 @@ stbx(R0, Rtmp, Robj); } +// Kills R31 if value is a volatile register. +void MacroAssembler::resolve_jobject(Register value, Register tmp1, Register tmp2, bool needs_frame) { + Label done; + cmpdi(CCR0, value, 0); + beq(CCR0, done); // Use NULL as-is. + + clrrdi(tmp1, value, JNIHandles::weak_tag_size); +#if INCLUDE_ALL_GCS + if (UseG1GC) { andi_(tmp2, value, JNIHandles::weak_tag_mask); } +#endif + ld(value, 0, tmp1); // Resolve (untagged) jobject. + +#if INCLUDE_ALL_GCS + if (UseG1GC) { + Label not_weak; + beq(CCR0, not_weak); // Test for jweak tag. + verify_oop(value); + g1_write_barrier_pre(noreg, // obj + noreg, // offset + value, // pre_val + tmp1, tmp2, needs_frame); + bind(not_weak); + } +#endif // INCLUDE_ALL_GCS + verify_oop(value); + bind(done); +} + #if INCLUDE_ALL_GCS // General G1 pre-barrier generator. // Goal: record the previous value if it is not null. @@ -2281,7 +2309,7 @@ bind(runtime); - // VM call need frame to access(write) O register. + // May need to preserve LR. Also needed if current frame is not compatible with C calling convention. if (needs_frame) { save_LR_CR(Rtmp1); push_frame_reg_args(0, Rtmp2); diff -r acb9351e3a29 -r 32bc598624bd src/cpu/ppc/vm/macroAssembler_ppc.hpp --- a/src/cpu/ppc/vm/macroAssembler_ppc.hpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/cpu/ppc/vm/macroAssembler_ppc.hpp Tue May 07 20:38:26 2019 +0000 @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2017 SAP AG. All rights reserved. + * Copyright (c) 2012, 2017 SAP AG. 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 @@ -516,6 +516,8 @@ void card_write_barrier_post(Register Rstore_addr, Register Rnew_val, Register Rtmp); void card_table_write(jbyte* byte_map_base, Register Rtmp, Register Robj); + void resolve_jobject(Register value, Register tmp1, Register tmp2, bool needs_frame); + #if INCLUDE_ALL_GCS // General G1 pre-barrier generator. void g1_write_barrier_pre(Register Robj, RegisterOrConstant offset, Register Rpre_val, diff -r acb9351e3a29 -r 32bc598624bd src/cpu/ppc/vm/sharedRuntime_ppc.cpp --- a/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Tue May 07 20:38:26 2019 +0000 @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 2012, 2017 SAP AG. 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 @@ -2513,16 +2513,11 @@ __ reset_last_Java_frame(); - // Unpack oop result. + // Unbox oop result, e.g. JNIHandles::resolve value. // -------------------------------------------------------------------------- if (ret_type == T_OBJECT || ret_type == T_ARRAY) { - Label skip_unboxing; - __ cmpdi(CCR0, R3_RET, 0); - __ beq(CCR0, skip_unboxing); - __ ld(R3_RET, 0, R3_RET); - __ bind(skip_unboxing); - __ verify_oop(R3_RET); + __ resolve_jobject(R3_RET, r_temp_1, r_temp_2, /* needs_frame */ false); // kills R31 } diff -r acb9351e3a29 -r 32bc598624bd src/cpu/sparc/vm/jniFastGetField_sparc.cpp --- a/src/cpu/sparc/vm/jniFastGetField_sparc.cpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/cpu/sparc/vm/jniFastGetField_sparc.cpp Tue May 07 20:38:26 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2017, 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 @@ -68,6 +68,7 @@ __ andcc (G4, 1, G0); __ br (Assembler::notZero, false, Assembler::pn, label1); __ delayed()->srl (O2, 2, O4); + __ andn (O1, JNIHandles::weak_tag_mask, O1); __ ld_ptr (O1, 0, O5); assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); @@ -147,6 +148,7 @@ __ andcc (G4, 1, G0); __ br (Assembler::notZero, false, Assembler::pn, label1); __ delayed()->srl (O2, 2, O4); + __ andn (O1, JNIHandles::weak_tag_mask, O1); __ ld_ptr (O1, 0, O5); __ add (O5, O4, O5); @@ -219,6 +221,7 @@ __ andcc (G4, 1, G0); __ br (Assembler::notZero, false, Assembler::pn, label1); __ delayed()->srl (O2, 2, O4); + __ andn (O1, JNIHandles::weak_tag_mask, O1); __ ld_ptr (O1, 0, O5); assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); diff -r acb9351e3a29 -r 32bc598624bd src/cpu/sparc/vm/sharedRuntime_sparc.cpp --- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Tue May 07 20:38:26 2019 +0000 @@ -2706,15 +2706,30 @@ __ verify_thread(); // G2_thread must be correct __ reset_last_Java_frame(); - // Unpack oop result + // Unbox oop result, e.g. JNIHandles::resolve value in I0. if (ret_type == T_OBJECT || ret_type == T_ARRAY) { - Label L; - __ addcc(G0, I0, G0); - __ brx(Assembler::notZero, true, Assembler::pt, L); - __ delayed()->ld_ptr(I0, 0, I0); - __ mov(G0, I0); - __ bind(L); - __ verify_oop(I0); + Label done, not_weak; + __ br_null(I0, false, Assembler::pn, done); // Use NULL as-is. + __ delayed()->andcc(I0, JNIHandles::weak_tag_mask, G0); // Test for jweak + __ brx(Assembler::zero, true, Assembler::pt, not_weak); + __ delayed()->ld_ptr(I0, 0, I0); // Maybe resolve (untagged) jobject. + // Resolve jweak. + __ ld_ptr(I0, -JNIHandles::weak_tag_value, I0); +#if INCLUDE_ALL_GCS + if (UseG1GC) { + // Copy to O0 because macro doesn't allow pre_val in input reg. + __ mov(I0, O0); + __ g1_write_barrier_pre(noreg /* obj */, + noreg /* index */, + 0 /* offset */, + O0 /* pre_val */, + G3_scratch /* tmp */, + true /* preserve_o_regs */); + } +#endif // INCLUDE_ALL_GCS + __ bind(not_weak); + __ verify_oop(I0); + __ bind(done); } if (!is_critical_native) { diff -r acb9351e3a29 -r 32bc598624bd src/cpu/sparc/vm/templateInterpreter_sparc.cpp --- a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Tue May 07 20:38:26 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, 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 @@ -1160,11 +1160,23 @@ __ set((intptr_t)AbstractInterpreter::result_handler(T_OBJECT), G3_scratch); __ cmp_and_brx_short(G3_scratch, Lscratch, Assembler::notEqual, Assembler::pt, no_oop); - __ addcc(G0, O0, O0); - __ brx(Assembler::notZero, true, Assembler::pt, store_result); // if result is not NULL: - __ delayed()->ld_ptr(O0, 0, O0); // unbox it - __ mov(G0, O0); - + // Unbox oop result, e.g. JNIHandles::resolve value in O0. + __ br_null(O0, false, Assembler::pn, store_result); // Use NULL as-is. + __ delayed()->andcc(O0, JNIHandles::weak_tag_mask, G0); // Test for jweak + __ brx(Assembler::zero, true, Assembler::pt, store_result); + __ delayed()->ld_ptr(O0, 0, O0); // Maybe resolve (untagged) jobject. + // Resolve jweak. + __ ld_ptr(O0, -JNIHandles::weak_tag_value, O0); +#if INCLUDE_ALL_GCS + if (UseG1GC) { + __ g1_write_barrier_pre(noreg /* obj */, + noreg /* index */, + 0 /* offset */, + O0 /* pre_val */, + G3_scratch /* tmp */, + true /* preserve_o_regs */); + } +#endif // INCLUDE_ALL_GCS __ bind(store_result); // Store it where gc will look for it and result handler expects it. __ st_ptr(O0, FP, (frame::interpreter_frame_oop_temp_offset*wordSize) + STACK_BIAS); diff -r acb9351e3a29 -r 32bc598624bd src/cpu/x86/vm/jniFastGetField_x86_32.cpp --- a/src/cpu/x86/vm/jniFastGetField_x86_32.cpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/cpu/x86/vm/jniFastGetField_x86_32.cpp Tue May 07 20:38:26 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2017, 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 @@ -79,14 +79,17 @@ __ mov(rax, rcx); __ andptr(rax, 1); // rax, must end up 0 __ movptr(rdx, Address(rsp, rax, Address::times_1, 2*wordSize)); - // obj, notice rax, is 0. - // rdx is data dependent on rcx. + // obj, notice rax, is 0. + // rdx is data dependent on rcx. } else { - __ movptr (rdx, Address(rsp, 2*wordSize)); // obj + __ movptr (rdx, Address(rsp, 2*wordSize)); // obj } __ movptr(rax, Address(rsp, 3*wordSize)); // jfieldID + + __ clear_jweak_tag(rdx); + __ movptr(rdx, Address(rdx, 0)); // *obj - __ shrptr (rax, 2); // offset + __ shrptr (rax, 2); // offset assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); speculative_load_pclist[count] = __ pc(); @@ -194,14 +197,17 @@ __ jcc (Assembler::notZero, slow); if (os::is_MP()) { __ mov(rax, rcx); - __ andptr(rax, 1); // rax, must end up 0 + __ andptr(rax, 1); // rax, must end up 0 __ movptr(rdx, Address(rsp, rax, Address::times_1, 3*wordSize)); // obj, notice rax, is 0. // rdx is data dependent on rcx. } else { - __ movptr(rdx, Address(rsp, 3*wordSize)); // obj + __ movptr(rdx, Address(rsp, 3*wordSize)); // obj } __ movptr(rsi, Address(rsp, 4*wordSize)); // jfieldID + + __ clear_jweak_tag(rdx); + __ movptr(rdx, Address(rdx, 0)); // *obj __ shrptr(rsi, 2); // offset @@ -283,7 +289,7 @@ __ jcc (Assembler::notZero, slow); if (os::is_MP()) { __ mov(rax, rcx); - __ andptr(rax, 1); // rax, must end up 0 + __ andptr(rax, 1); // rax, must end up 0 __ movptr(rdx, Address(rsp, rax, Address::times_1, 2*wordSize)); // obj, notice rax, is 0. // rdx is data dependent on rcx. @@ -291,6 +297,9 @@ __ movptr(rdx, Address(rsp, 2*wordSize)); // obj } __ movptr(rax, Address(rsp, 3*wordSize)); // jfieldID + + __ clear_jweak_tag(rdx); + __ movptr(rdx, Address(rdx, 0)); // *obj __ shrptr(rax, 2); // offset diff -r acb9351e3a29 -r 32bc598624bd src/cpu/x86/vm/jniFastGetField_x86_64.cpp --- a/src/cpu/x86/vm/jniFastGetField_x86_64.cpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/cpu/x86/vm/jniFastGetField_x86_64.cpp Tue May 07 20:38:26 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,13 +76,16 @@ __ jcc (Assembler::notZero, slow); if (os::is_MP()) { __ xorptr(robj, rcounter); - __ xorptr(robj, rcounter); // obj, since + __ xorptr(robj, rcounter); // obj, since // robj ^ rcounter ^ rcounter == robj // robj is data dependent on rcounter. } - __ movptr(robj, Address(robj, 0)); // *obj + + __ clear_jweak_tag(robj); + + __ movptr(robj, Address(robj, 0)); // *obj __ mov (roffset, c_rarg2); - __ shrptr(roffset, 2); // offset + __ shrptr(roffset, 2); // offset assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); speculative_load_pclist[count] = __ pc(); @@ -174,13 +177,16 @@ __ jcc (Assembler::notZero, slow); if (os::is_MP()) { __ xorptr(robj, rcounter); - __ xorptr(robj, rcounter); // obj, since + __ xorptr(robj, rcounter); // obj, since // robj ^ rcounter ^ rcounter == robj // robj is data dependent on rcounter. } - __ movptr(robj, Address(robj, 0)); // *obj + + __ clear_jweak_tag(robj); + + __ movptr(robj, Address(robj, 0)); // *obj __ mov (roffset, c_rarg2); - __ shrptr(roffset, 2); // offset + __ shrptr(roffset, 2); // offset assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); speculative_load_pclist[count] = __ pc(); diff -r acb9351e3a29 -r 32bc598624bd src/cpu/x86/vm/macroAssembler_x86.cpp --- a/src/cpu/x86/vm/macroAssembler_x86.cpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/cpu/x86/vm/macroAssembler_x86.cpp Tue May 07 20:38:26 2019 +0000 @@ -4119,6 +4119,42 @@ } } +void MacroAssembler::resolve_jobject(Register value, + Register thread, + Register tmp) { + assert_different_registers(value, thread, tmp); + Label done, not_weak; + 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. + movptr(value, Address(value, -JNIHandles::weak_tag_value)); + verify_oop(value); +#if INCLUDE_ALL_GCS + if (UseG1GC) { + g1_write_barrier_pre(noreg /* obj */, + value /* pre_val */, + thread /* thread */, + tmp /* tmp */, + true /* tosca_live */, + true /* expand_call */); + } +#endif // INCLUDE_ALL_GCS + jmp(done); + bind(not_weak); + // Resolve (untagged) jobject. + movptr(value, Address(value, 0)); + verify_oop(value); + bind(done); +} + +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 + // The inverted mask is sign-extended + andptr(possibly_jweak, inverted_jweak_mask); +} ////////////////////////////////////////////////////////////////////////////////// #if INCLUDE_ALL_GCS diff -r acb9351e3a29 -r 32bc598624bd src/cpu/x86/vm/macroAssembler_x86.hpp --- a/src/cpu/x86/vm/macroAssembler_x86.hpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/cpu/x86/vm/macroAssembler_x86.hpp Tue May 07 20:38:26 2019 +0000 @@ -298,6 +298,9 @@ void store_check(Register obj); // store check for obj - register is destroyed afterwards void store_check(Register obj, Address dst); // same as above, dst is exact store location (reg. is destroyed) + void resolve_jobject(Register value, Register thread, Register tmp); + void clear_jweak_tag(Register possibly_jweak); + #if INCLUDE_ALL_GCS void g1_write_barrier_pre(Register obj, diff -r acb9351e3a29 -r 32bc598624bd src/cpu/x86/vm/sharedRuntime_x86_32.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Tue May 07 20:38:26 2019 +0000 @@ -2253,14 +2253,11 @@ __ reset_last_Java_frame(thread, false); - // Unpack oop result + // Unbox oop result, e.g. JNIHandles::resolve value. if (ret_type == T_OBJECT || ret_type == T_ARRAY) { - Label L; - __ cmpptr(rax, (int32_t)NULL_WORD); - __ jcc(Assembler::equal, L); - __ movptr(rax, Address(rax, 0)); - __ bind(L); - __ verify_oop(rax); + __ resolve_jobject(rax /* value */, + thread /* thread */, + rcx /* tmp */); } if (!is_critical_native) { diff -r acb9351e3a29 -r 32bc598624bd src/cpu/x86/vm/sharedRuntime_x86_64.cpp --- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Tue May 07 20:38:26 2019 +0000 @@ -2499,14 +2499,11 @@ __ reset_last_Java_frame(false); - // Unpack oop result + // Unbox oop result, e.g. JNIHandles::resolve value. if (ret_type == T_OBJECT || ret_type == T_ARRAY) { - Label L; - __ testptr(rax, rax); - __ jcc(Assembler::zero, L); - __ movptr(rax, Address(rax, 0)); - __ bind(L); - __ verify_oop(rax); + __ resolve_jobject(rax /* value */, + r15_thread /* thread */, + rcx /* tmp */); } if (!is_critical_native) { diff -r acb9351e3a29 -r 32bc598624bd src/cpu/x86/vm/templateInterpreter_x86_32.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Tue May 07 20:38:26 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, 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 @@ -1296,19 +1296,18 @@ __ movl(Address(t, JNIHandleBlock::top_offset_in_bytes()), NULL_WORD); // If result was an oop then unbox and save it in the frame - { Label L; - Label no_oop, store_result; + { + Label no_oop; ExternalAddress handler(AbstractInterpreter::result_handler(T_OBJECT)); __ cmpptr(Address(rbp, frame::interpreter_frame_result_handler_offset*wordSize), handler.addr()); __ jcc(Assembler::notEqual, no_oop); __ cmpptr(Address(rsp, 0), (int32_t)NULL_WORD); __ pop(ltos); - __ testptr(rax, rax); - __ jcc(Assembler::zero, store_result); - // unbox - __ movptr(rax, Address(rax, 0)); - __ bind(store_result); + // Unbox oop result, e.g. JNIHandles::resolve value. + __ resolve_jobject(rax /* value */, + thread /* thread */, + t /* tmp */); __ movptr(Address(rbp, (frame::interpreter_frame_oop_temp_offset)*wordSize), rax); // keep stack depth as expected by pushing oop which will eventually be discarded __ push(ltos); diff -r acb9351e3a29 -r 32bc598624bd src/cpu/x86/vm/templateInterpreter_x86_64.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Tue May 07 20:38:26 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, 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 @@ -1272,16 +1272,16 @@ // and result handler will pick it up { - Label no_oop, store_result; + Label no_oop; __ lea(t, ExternalAddress(AbstractInterpreter::result_handler(T_OBJECT))); __ cmpptr(t, Address(rbp, frame::interpreter_frame_result_handler_offset*wordSize)); __ jcc(Assembler::notEqual, no_oop); // retrieve result __ pop(ltos); - __ testptr(rax, rax); - __ jcc(Assembler::zero, store_result); - __ movptr(rax, Address(rax, 0)); - __ bind(store_result); + // Unbox oop result, e.g. JNIHandles::resolve value. + __ resolve_jobject(rax /* value */, + r15_thread /* thread */, + t /* tmp */); __ movptr(Address(rbp, frame::interpreter_frame_oop_temp_offset*wordSize), rax); // keep stack depth as expected by pushing oop which will eventually be discarde __ push(ltos); diff -r acb9351e3a29 -r 32bc598624bd src/cpu/zero/vm/cppInterpreter_zero.cpp --- a/src/cpu/zero/vm/cppInterpreter_zero.cpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/cpu/zero/vm/cppInterpreter_zero.cpp Tue May 07 20:38:26 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -405,10 +405,12 @@ // oop_temp where the garbage collector can see it before // we release the handle it might be protected by. if (handler->result_type() == &ffi_type_pointer) { - if (result[0]) - istate->set_oop_temp(*(oop *) result[0]); - else + if (result[0] == 0) { istate->set_oop_temp(NULL); + } else { + jobject handle = reinterpret_cast(result[0]); + istate->set_oop_temp(JNIHandles::resolve(handle)); + } } // Reset handle block diff -r acb9351e3a29 -r 32bc598624bd src/share/vm/prims/jni.cpp --- a/src/share/vm/prims/jni.cpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/share/vm/prims/jni.cpp Tue May 07 20:38:26 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -709,6 +709,7 @@ THROW_OOP_(JNIHandles::resolve(obj), JNI_OK); ShouldNotReachHere(); + return 0; // Mute compiler. JNI_END #ifndef USDT2 @@ -735,6 +736,7 @@ Handle protection_domain (THREAD, k->protection_domain()); THROW_MSG_LOADER_(name, (char *)message, class_loader, protection_domain, JNI_OK); ShouldNotReachHere(); + return 0; // Mute compiler. JNI_END @@ -1140,8 +1142,7 @@ inline void get_long() { _arguments->push_long(va_arg(_ap, jlong)); } inline void get_float() { _arguments->push_float((jfloat)va_arg(_ap, jdouble)); } // float is coerced to double w/ va_arg inline void get_double() { _arguments->push_double(va_arg(_ap, jdouble)); } - inline void get_object() { jobject l = va_arg(_ap, jobject); - _arguments->push_oop(Handle((oop *)l, false)); } + inline void get_object() { _arguments->push_jobject(va_arg(_ap, jobject)); } inline void set_ap(va_list rap) { #ifdef va_copy @@ -1235,7 +1236,7 @@ inline void get_long() { _arguments->push_long((_ap++)->j); } inline void get_float() { _arguments->push_float((_ap++)->f); } inline void get_double() { _arguments->push_double((_ap++)->d);} - inline void get_object() { _arguments->push_oop(Handle((oop *)(_ap++)->l, false)); } + inline void get_object() { _arguments->push_jobject((_ap++)->l); } inline void set_ap(const jvalue *rap) { _ap = rap; } diff -r acb9351e3a29 -r 32bc598624bd src/share/vm/prims/jvmtiEnv.cpp --- a/src/share/vm/prims/jvmtiEnv.cpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/share/vm/prims/jvmtiEnv.cpp Tue May 07 20:38:26 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, 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 @@ -1621,6 +1621,13 @@ } } + if (initial_object != NULL) { + oop init_obj = JNIHandles::resolve_external_guard(initial_object); + if (init_obj == NULL) { + return JVMTI_ERROR_INVALID_OBJECT; + } + } + Thread *thread = Thread::current(); HandleMark hm(thread); KlassHandle kh (thread, k_oop); diff -r acb9351e3a29 -r 32bc598624bd src/share/vm/runtime/javaCalls.cpp --- a/src/share/vm/runtime/javaCalls.cpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/share/vm/runtime/javaCalls.cpp Tue May 07 20:38:26 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, 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 @@ -325,9 +325,9 @@ // Verify the arguments if (CheckJNICalls) { - args->verify(method, result->get_type(), thread); + args->verify(method, result->get_type()); } - else debug_only(args->verify(method, result->get_type(), thread)); + else debug_only(args->verify(method, result->get_type())); // Ignore call if method is empty if (method->is_empty_method()) { @@ -429,12 +429,42 @@ //-------------------------------------------------------------------------------------- // Implementation of JavaCallArguments +inline bool is_value_state_indirect_oop(uint state) { + assert(state != JavaCallArguments::value_state_oop, + "Checking for handles after removal"); + assert(state < JavaCallArguments::value_state_limit, "Invalid value state"); + return state != JavaCallArguments::value_state_primitive; +} + +inline oop resolve_indirect_oop(intptr_t value, uint state) { + switch (state) { + case JavaCallArguments::value_state_handle: + { + oop* ptr = reinterpret_cast(value); + return Handle::raw_resolve(ptr); + } + + case JavaCallArguments::value_state_jobject: + { + jobject obj = reinterpret_cast(value); + return JNIHandles::resolve(obj); + } + + default: + ShouldNotReachHere(); + return NULL; + } +} + intptr_t* JavaCallArguments::parameters() { // First convert all handles to oops for(int i = 0; i < _size; i++) { - if (_is_oop[i]) { - // Handle conversion - _value[i] = cast_from_oop(Handle::raw_resolve((oop *)_value[i])); + uint state = _value_state[i]; + assert(state != value_state_oop, "Multiple handle conversions"); + if (is_value_state_indirect_oop(state)) { + oop obj = resolve_indirect_oop(_value[i], state); + _value[i] = cast_from_oop(obj); + _value_state[i] = value_state_oop; } } // Return argument vector @@ -444,30 +474,40 @@ class SignatureChekker : public SignatureIterator { private: - bool *_is_oop; - int _pos; - BasicType _return_type; - intptr_t* _value; - Thread* _thread; + int _pos; + BasicType _return_type; + u_char* _value_state; + intptr_t* _value; public: bool _is_return; - SignatureChekker(Symbol* signature, BasicType return_type, bool is_static, bool* is_oop, intptr_t* value, Thread* thread) : SignatureIterator(signature) { - _is_oop = is_oop; - _is_return = false; - _return_type = return_type; - _pos = 0; - _value = value; - _thread = thread; - + SignatureChekker(Symbol* signature, + BasicType return_type, + bool is_static, + u_char* value_state, + intptr_t* value) : + SignatureIterator(signature), + _pos(0), + _return_type(return_type), + _value_state(value_state), + _value(value), + _is_return(false) + { if (!is_static) { check_value(true); // Receiver must be an oop } } void check_value(bool type) { - guarantee(_is_oop[_pos++] == type, "signature does not match pushed arguments"); + uint state = _value_state[_pos++]; + if (type) { + guarantee(is_value_state_indirect_oop(state), + "signature does not match pushed arguments"); + } else { + guarantee(state == JavaCallArguments::value_state_primitive, + "signature does not match pushed arguments"); + } } void check_doing_return(bool state) { _is_return = state; } @@ -502,24 +542,19 @@ return; } - // verify handle and the oop pointed to by handle - int p = _pos; - bool bad = false; - // If argument is oop - if (_is_oop[p]) { - intptr_t v = _value[p]; - if (v != 0 ) { - size_t t = (size_t)v; - bad = (t < (size_t)os::vm_page_size() ) || !Handle::raw_resolve((oop *)v)->is_oop_or_null(true); - if (CheckJNICalls && bad) { - ReportJNIFatalError((JavaThread*)_thread, "Bad JNI oop argument"); - } - } - // for the regular debug case. - assert(!bad, "Bad JNI oop argument"); + intptr_t v = _value[_pos]; + if (v != 0) { + // v is a "handle" referring to an oop, cast to integral type. + // There shouldn't be any handles in very low memory. + guarantee((size_t)v >= (size_t)os::vm_page_size(), + "Bad JNI oop argument"); + // Verify the pointee. + oop vv = resolve_indirect_oop(v, _value_state[_pos]); + guarantee(vv->is_oop_or_null(true), + "Bad JNI oop argument"); } - check_value(true); + check_value(true); // Verify value state. } void do_bool() { check_int(T_BOOLEAN); } @@ -536,8 +571,7 @@ }; -void JavaCallArguments::verify(methodHandle method, BasicType return_type, - Thread *thread) { +void JavaCallArguments::verify(methodHandle method, BasicType return_type) { guarantee(method->size_of_parameters() == size_of_parameters(), "wrong no. of arguments pushed"); // Treat T_OBJECT and T_ARRAY as the same @@ -546,7 +580,11 @@ // Check that oop information is correct Symbol* signature = method->signature(); - SignatureChekker sc(signature, return_type, method->is_static(),_is_oop, _value, thread); + SignatureChekker sc(signature, + return_type, + method->is_static(), + _value_state, + _value); sc.iterate_parameters(); sc.check_doing_return(true); sc.iterate_returntype(); diff -r acb9351e3a29 -r 32bc598624bd src/share/vm/runtime/javaCalls.hpp --- a/src/share/vm/runtime/javaCalls.hpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/share/vm/runtime/javaCalls.hpp Tue May 07 20:38:26 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, 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 @@ -92,25 +92,42 @@ _default_size = 8 // Must be at least # of arguments in JavaCalls methods }; - intptr_t _value_buffer [_default_size + 1]; - bool _is_oop_buffer[_default_size + 1]; + intptr_t _value_buffer [_default_size + 1]; + u_char _value_state_buffer[_default_size + 1]; intptr_t* _value; - bool* _is_oop; + u_char* _value_state; int _size; int _max_size; bool _start_at_zero; // Support late setting of receiver void initialize() { // Starts at first element to support set_receiver. - _value = &_value_buffer[1]; - _is_oop = &_is_oop_buffer[1]; + _value = &_value_buffer[1]; + _value_state = &_value_state_buffer[1]; _max_size = _default_size; _size = 0; _start_at_zero = false; } + // Helper for push_oop and the like. The value argument is a + // "handle" that refers to an oop. We record the address of the + // handle rather than the designated oop. The handle is later + // resolved to the oop by parameters(). This delays the exposure of + // naked oops until it is GC-safe. + template + inline int push_oop_impl(T handle, int size) { + // JNITypes::put_obj expects an oop value, so we play fast and + // loose with the type system. The cast from handle type to oop + // *must* use a C-style cast. In a product build it performs a + // reinterpret_cast. In a debug build (more accurately, in a + // CHECK_UNHANDLED_OOPS build) it performs a static_cast, invoking + // the debug-only oop class's conversion from void* constructor. + JNITypes::put_obj((oop)handle, _value, size); // Updates size. + return size; // Return the updated size. + } + public: JavaCallArguments() { initialize(); } @@ -121,11 +138,12 @@ JavaCallArguments(int max_size) { if (max_size > _default_size) { - _value = NEW_RESOURCE_ARRAY(intptr_t, max_size + 1); - _is_oop = NEW_RESOURCE_ARRAY(bool, max_size + 1); + _value = NEW_RESOURCE_ARRAY(intptr_t, max_size + 1); + _value_state = NEW_RESOURCE_ARRAY(u_char, max_size + 1); - // Reserve room for potential receiver in value and is_oop - _value++; _is_oop++; + // Reserve room for potential receiver in value and state + _value++; + _value_state++; _max_size = max_size; _size = 0; @@ -135,25 +153,52 @@ } } - inline void push_oop(Handle h) { _is_oop[_size] = true; - JNITypes::put_obj((oop)h.raw_value(), _value, _size); } + // The possible values for _value_state elements. + enum { + value_state_primitive, + value_state_oop, + value_state_handle, + value_state_jobject, + value_state_limit + }; - inline void push_int(int i) { _is_oop[_size] = false; - JNITypes::put_int(i, _value, _size); } + inline void push_oop(Handle h) { + _value_state[_size] = value_state_handle; + _size = push_oop_impl(h.raw_value(), _size); + } - inline void push_double(double d) { _is_oop[_size] = false; _is_oop[_size + 1] = false; - JNITypes::put_double(d, _value, _size); } + inline void push_jobject(jobject h) { + _value_state[_size] = value_state_jobject; + _size = push_oop_impl(h, _size); + } - inline void push_long(jlong l) { _is_oop[_size] = false; _is_oop[_size + 1] = false; - JNITypes::put_long(l, _value, _size); } + inline void push_int(int i) { + _value_state[_size] = value_state_primitive; + JNITypes::put_int(i, _value, _size); + } - inline void push_float(float f) { _is_oop[_size] = false; - JNITypes::put_float(f, _value, _size); } + inline void push_double(double d) { + _value_state[_size] = value_state_primitive; + _value_state[_size + 1] = value_state_primitive; + JNITypes::put_double(d, _value, _size); + } + + inline void push_long(jlong l) { + _value_state[_size] = value_state_primitive; + _value_state[_size + 1] = value_state_primitive; + JNITypes::put_long(l, _value, _size); + } + + inline void push_float(float f) { + _value_state[_size] = value_state_primitive; + JNITypes::put_float(f, _value, _size); + } // receiver Handle receiver() { assert(_size > 0, "must at least be one argument"); - assert(_is_oop[0], "first argument must be an oop"); + assert(_value_state[0] == value_state_handle, + "first argument must be an oop"); assert(_value[0] != 0, "receiver must be not-null"); return Handle((oop*)_value[0], false); } @@ -161,11 +206,11 @@ void set_receiver(Handle h) { assert(_start_at_zero == false, "can only be called once"); _start_at_zero = true; - _is_oop--; + _value_state--; _value--; _size++; - _is_oop[0] = true; - _value[0] = (intptr_t)h.raw_value(); + _value_state[0] = value_state_handle; + push_oop_impl(h.raw_value(), 0); } // Converts all Handles to oops, and returns a reference to parameter vector @@ -173,7 +218,7 @@ int size_of_parameters() const { return _size; } // Verify that pushed arguments fits a given method - void verify(methodHandle method, BasicType return_type, Thread *thread); + void verify(methodHandle method, BasicType return_type); }; // All calls to Java have to go via JavaCalls. Sets up the stack frame diff -r acb9351e3a29 -r 32bc598624bd src/share/vm/runtime/jniHandles.cpp --- a/src/share/vm/runtime/jniHandles.cpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/share/vm/runtime/jniHandles.cpp Tue May 07 20:38:26 2019 +0000 @@ -30,6 +30,9 @@ #include "runtime/jniHandles.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/thread.inline.hpp" +#if INCLUDE_ALL_GCS +#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" +#endif PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC @@ -87,34 +90,52 @@ return res; } - jobject JNIHandles::make_weak_global(Handle obj) { assert(!Universe::heap()->is_gc_active(), "can't extend the root set during GC"); jobject res = NULL; if (!obj.is_null()) { // ignore null handles - MutexLocker ml(JNIGlobalHandle_lock); - assert(Universe::heap()->is_in_reserved(obj()), "sanity check"); - res = _weak_global_handles->allocate_handle(obj()); + { + MutexLocker ml(JNIGlobalHandle_lock); + assert(Universe::heap()->is_in_reserved(obj()), "sanity check"); + res = _weak_global_handles->allocate_handle(obj()); + } + // Add weak tag. + assert(is_ptr_aligned(res, weak_tag_alignment), "invariant"); + char* tptr = reinterpret_cast(res) + weak_tag_value; + res = reinterpret_cast(tptr); } else { CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops()); } return res; } +template +oop JNIHandles::resolve_jweak(jweak handle) { + assert(is_jweak(handle), "precondition"); + oop result = jweak_ref(handle); + result = guard_value(result); +#if INCLUDE_ALL_GCS + if (result != NULL && UseG1GC) { + G1SATBCardTableModRefBS::enqueue(result); + } +#endif // INCLUDE_ALL_GCS + return result; +} + +template oop JNIHandles::resolve_jweak(jweak); +template oop JNIHandles::resolve_jweak(jweak); void JNIHandles::destroy_global(jobject handle) { if (handle != NULL) { assert(is_global_handle(handle), "Invalid delete of global JNI handle"); - *((oop*)handle) = deleted_handle(); // Mark the handle as deleted, allocate will reuse it + jobject_ref(handle) = deleted_handle(); } } - void JNIHandles::destroy_weak_global(jobject handle) { if (handle != NULL) { - assert(!CheckJNICalls || is_weak_global_handle(handle), "Invalid delete of weak global JNI handle"); - *((oop*)handle) = deleted_handle(); // Mark the handle as deleted, allocate will reuse it + jweak_ref(handle) = deleted_handle(); } } diff -r acb9351e3a29 -r 32bc598624bd src/share/vm/runtime/jniHandles.hpp --- a/src/share/vm/runtime/jniHandles.hpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/share/vm/runtime/jniHandles.hpp Tue May 07 20:38:26 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,28 @@ static JNIHandleBlock* _weak_global_handles; // First weak global handle block static oop _deleted_handle; // Sentinel marking deleted handles + inline static bool is_jweak(jobject handle); + inline static oop& jobject_ref(jobject handle); // NOT jweak! + inline static oop& jweak_ref(jobject handle); + + template inline static oop guard_value(oop value); + template inline static oop resolve_impl(jobject handle); + template static oop resolve_jweak(jweak handle); + 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; + // Resolve handle into oop inline static oop resolve(jobject handle); // Resolve externally provided handle into oop with some guards @@ -173,36 +194,85 @@ #endif }; +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 oop& JNIHandles::jobject_ref(jobject handle) { + assert(!is_jweak(handle), "precondition"); + return *reinterpret_cast(handle); +} + +inline oop& JNIHandles::jweak_ref(jobject handle) { + assert(is_jweak(handle), "precondition"); + char* ptr = reinterpret_cast(handle) - weak_tag_value; + return *reinterpret_cast(ptr); +} + +// external_guard is true if called from resolve_external_guard. +// Treat deleted (and possibly zapped) as NULL for external_guard, +// else as (asserted) error. +template +inline oop JNIHandles::guard_value(oop value) { + if (!external_guard) { + assert(value != badJNIHandle, "Pointing to zapped jni handle area"); + assert(value != deleted_handle(), "Used a deleted global handle"); + } else if ((value == badJNIHandle) || (value == deleted_handle())) { + value = NULL; + } + return value; +} + +// external_guard is true if called from resolve_external_guard. +template +inline oop JNIHandles::resolve_impl(jobject handle) { + assert(handle != NULL, "precondition"); + oop result; + if (is_jweak(handle)) { // Unlikely + result = resolve_jweak(handle); + } else { + result = jobject_ref(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 value read from jni handle"); + result = guard_value(result); + } + return result; +} inline oop JNIHandles::resolve(jobject handle) { - oop result = (handle == NULL ? (oop)NULL : *(oop*)handle); - assert(result != NULL || (handle == NULL || !CheckJNICalls || is_weak_global_handle(handle)), "Invalid value read from jni handle"); - assert(result != badJNIHandle, "Pointing to zapped jni handle area"); + oop result = NULL; + if (handle != NULL) { + result = resolve_impl(handle); + } return result; -}; +} - +// Resolve some erroneous cases to NULL, rather than treating them as +// possibly unchecked errors. In particular, deleted handles are +// treated as NULL (though a deleted and later reallocated handle +// isn't detected). inline oop JNIHandles::resolve_external_guard(jobject handle) { - if (handle == NULL) return NULL; - oop result = *(oop*)handle; - if (result == NULL || result == badJNIHandle) return NULL; + oop result = NULL; + if (handle != NULL) { + result = resolve_impl(handle); + } return result; -}; - +} inline oop JNIHandles::resolve_non_null(jobject handle) { assert(handle != NULL, "JNI handle should not be null"); - oop result = *(oop*)handle; - assert(result != NULL, "Invalid value read from jni handle"); - assert(result != badJNIHandle, "Pointing to zapped jni handle area"); - // Don't let that private _deleted_handle object escape into the wild. - assert(result != deleted_handle(), "Used a deleted global handle."); + oop result = resolve_impl(handle); + assert(result != NULL, "NULL read from jni handle"); return result; -}; +} inline void JNIHandles::destroy_local(jobject handle) { if (handle != NULL) { - *((oop*)handle) = deleted_handle(); // Mark the handle as deleted, allocate will reuse it + jobject_ref(handle) = deleted_handle(); } } diff -r acb9351e3a29 -r 32bc598624bd src/share/vm/shark/sharkNativeWrapper.cpp --- a/src/share/vm/shark/sharkNativeWrapper.cpp Thu Nov 05 11:42:42 2015 +0100 +++ b/src/share/vm/shark/sharkNativeWrapper.cpp Tue May 07 20:38:26 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright 2009, 2010 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -50,6 +50,7 @@ // Create and push our stack frame builder()->SetInsertPoint(CreateBlock()); +#error Needs to be updated for tagged jweak; see JNIHandles. _stack = SharkStack::CreateBuildAndPushFrame(this, method); NOT_PRODUCT(method = NULL);