aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorphh <unknown>2019-05-07 20:38:26 +0000
committerbell-sw <liberica@bell-sw.com>2019-07-22 19:21:53 +0300
commit83e032cae4741976cbbc69f574bc115ad44fbcdf (patch)
treee93f9c982aba5d92402105a695e81855cf3195e7
parent8f2abffb4feefd6382c387979a901899acbac916 (diff)
downloadjdk8u_hotspot-83e032cae4741976cbbc69f574bc115ad44fbcdf.tar.gz
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
-rw-r--r--src/cpu/ppc/vm/frame_ppc.cpp9
-rw-r--r--src/cpu/ppc/vm/interpreter_ppc.cpp11
-rw-r--r--src/cpu/ppc/vm/macroAssembler_ppc.cpp34
-rw-r--r--src/cpu/ppc/vm/macroAssembler_ppc.hpp4
-rw-r--r--src/cpu/ppc/vm/sharedRuntime_ppc.cpp11
-rw-r--r--src/cpu/sparc/vm/jniFastGetField_sparc.cpp5
-rw-r--r--src/cpu/sparc/vm/sharedRuntime_sparc.cpp31
-rw-r--r--src/cpu/sparc/vm/templateInterpreter_sparc.cpp24
-rw-r--r--src/cpu/x86/vm/jniFastGetField_x86_32.cpp25
-rw-r--r--src/cpu/x86/vm/jniFastGetField_x86_64.cpp20
-rw-r--r--src/cpu/x86/vm/macroAssembler_x86.cpp36
-rw-r--r--src/cpu/x86/vm/macroAssembler_x86.hpp3
-rw-r--r--src/cpu/x86/vm/sharedRuntime_x86_32.cpp11
-rw-r--r--src/cpu/x86/vm/sharedRuntime_x86_64.cpp11
-rw-r--r--src/cpu/x86/vm/templateInterpreter_x86_32.cpp15
-rw-r--r--src/cpu/x86/vm/templateInterpreter_x86_64.cpp12
-rw-r--r--src/cpu/zero/vm/cppInterpreter_zero.cpp10
-rw-r--r--src/share/vm/prims/jni.cpp9
-rw-r--r--src/share/vm/prims/jvmtiEnv.cpp9
-rw-r--r--src/share/vm/runtime/javaCalls.cpp116
-rw-r--r--src/share/vm/runtime/javaCalls.hpp95
-rw-r--r--src/share/vm/runtime/jniHandles.cpp37
-rw-r--r--src/share/vm/runtime/jniHandles.hpp106
-rw-r--r--src/share/vm/shark/sharkNativeWrapper.cpp3
24 files changed, 464 insertions, 183 deletions
diff --git a/src/cpu/ppc/vm/frame_ppc.cpp b/src/cpu/ppc/vm/frame_ppc.cpp
index a4f7bedb0..d56eeb2b3 100644
--- a/src/cpu/ppc/vm/frame_ppc.cpp
+++ b/src/cpu/ppc/vm/frame_ppc.cpp
@@ -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 @@ BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result)
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 --git a/src/cpu/ppc/vm/interpreter_ppc.cpp b/src/cpu/ppc/vm/interpreter_ppc.cpp
index b6b9907df..3505ce734 100644
--- a/src/cpu/ppc/vm/interpreter_ppc.cpp
+++ b/src/cpu/ppc/vm/interpreter_ppc.cpp
@@ -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 @@ address AbstractInterpreterGenerator::generate_result_handler_for(BasicType type
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 --git a/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/src/cpu/ppc/vm/macroAssembler_ppc.cpp
index a140b36bd..d70312706 100644
--- a/src/cpu/ppc/vm/macroAssembler_ppc.cpp
+++ b/src/cpu/ppc/vm/macroAssembler_ppc.cpp
@@ -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 @@ void MacroAssembler::card_table_write(jbyte* byte_map_base, Register Rtmp, Regis
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 @@ void MacroAssembler::g1_write_barrier_pre(Register Robj, RegisterOrConstant offs
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 --git a/src/cpu/ppc/vm/macroAssembler_ppc.hpp b/src/cpu/ppc/vm/macroAssembler_ppc.hpp
index 0f4e8da72..3c6cea51b 100644
--- a/src/cpu/ppc/vm/macroAssembler_ppc.hpp
+++ b/src/cpu/ppc/vm/macroAssembler_ppc.hpp
@@ -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 @@ class MacroAssembler: public Assembler {
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 --git a/src/cpu/ppc/vm/sharedRuntime_ppc.cpp b/src/cpu/ppc/vm/sharedRuntime_ppc.cpp
index 047779e38..404670547 100644
--- a/src/cpu/ppc/vm/sharedRuntime_ppc.cpp
+++ b/src/cpu/ppc/vm/sharedRuntime_ppc.cpp
@@ -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 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
__ 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 --git a/src/cpu/sparc/vm/jniFastGetField_sparc.cpp b/src/cpu/sparc/vm/jniFastGetField_sparc.cpp
index 6d3f05a2a..ff9fcd694 100644
--- a/src/cpu/sparc/vm/jniFastGetField_sparc.cpp
+++ b/src/cpu/sparc/vm/jniFastGetField_sparc.cpp
@@ -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 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
__ 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 @@ address JNI_FastGetField::generate_fast_get_long_field() {
__ 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 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) {
__ 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 --git a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp
index 7e72da895..1cea35f57 100644
--- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp
+++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp
@@ -2706,15 +2706,30 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
__ 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 --git a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
index 5ffaf2faf..83d40496c 100644
--- a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
+++ b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp
@@ -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 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
__ 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 --git a/src/cpu/x86/vm/jniFastGetField_x86_32.cpp b/src/cpu/x86/vm/jniFastGetField_x86_32.cpp
index a45e0eb9a..48c4400e2 100644
--- a/src/cpu/x86/vm/jniFastGetField_x86_32.cpp
+++ b/src/cpu/x86/vm/jniFastGetField_x86_32.cpp
@@ -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 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
__ 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 @@ address JNI_FastGetField::generate_fast_get_long_field() {
__ 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 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) {
__ 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 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) {
__ 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 --git a/src/cpu/x86/vm/jniFastGetField_x86_64.cpp b/src/cpu/x86/vm/jniFastGetField_x86_64.cpp
index 7286fd124..9b538002f 100644
--- a/src/cpu/x86/vm/jniFastGetField_x86_64.cpp
+++ b/src/cpu/x86/vm/jniFastGetField_x86_64.cpp
@@ -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 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
__ 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 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) {
__ 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 --git a/src/cpu/x86/vm/macroAssembler_x86.cpp b/src/cpu/x86/vm/macroAssembler_x86.cpp
index 0e757f29c..1b09514c9 100644
--- a/src/cpu/x86/vm/macroAssembler_x86.cpp
+++ b/src/cpu/x86/vm/macroAssembler_x86.cpp
@@ -4119,6 +4119,42 @@ void MacroAssembler::vxorps(XMMRegister dst, XMMRegister nds, AddressLiteral src
}
}
+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<int32_t>(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 --git a/src/cpu/x86/vm/macroAssembler_x86.hpp b/src/cpu/x86/vm/macroAssembler_x86.hpp
index c3c0a7911..e94fdd7d7 100644
--- a/src/cpu/x86/vm/macroAssembler_x86.hpp
+++ b/src/cpu/x86/vm/macroAssembler_x86.hpp
@@ -298,6 +298,9 @@ class MacroAssembler: public Assembler {
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 --git a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp
index 9debbc118..d701d4495 100644
--- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp
+++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp
@@ -2253,14 +2253,11 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
__ 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 --git a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp
index e50c72218..c2f69f7c3 100644
--- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp
+++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp
@@ -2499,14 +2499,11 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
__ 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 --git a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
index 4d94902ee..b7c515031 100644
--- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
+++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp
@@ -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 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
__ 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 --git a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
index 121738292..209a3f676 100644
--- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
+++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp
@@ -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 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
// 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 --git a/src/cpu/zero/vm/cppInterpreter_zero.cpp b/src/cpu/zero/vm/cppInterpreter_zero.cpp
index 242ce1cfd..525031eb9 100644
--- a/src/cpu/zero/vm/cppInterpreter_zero.cpp
+++ b/src/cpu/zero/vm/cppInterpreter_zero.cpp
@@ -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 @@ int CppInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) {
// 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<jobject>(result[0]);
+ istate->set_oop_temp(JNIHandles::resolve(handle));
+ }
}
// Reset handle block
diff --git a/src/share/vm/prims/jni.cpp b/src/share/vm/prims/jni.cpp
index 9947a2634..b3b102c66 100644
--- a/src/share/vm/prims/jni.cpp
+++ b/src/share/vm/prims/jni.cpp
@@ -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 @@ JNI_ENTRY(jint, jni_Throw(JNIEnv *env, jthrowable obj))
THROW_OOP_(JNIHandles::resolve(obj), JNI_OK);
ShouldNotReachHere();
+ return 0; // Mute compiler.
JNI_END
#ifndef USDT2
@@ -735,6 +736,7 @@ JNI_ENTRY(jint, jni_ThrowNew(JNIEnv *env, jclass clazz, const char *message))
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 @@ class JNI_ArgumentPusherVaArg : public JNI_ArgumentPusher {
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 @@ class JNI_ArgumentPusherArray : public JNI_ArgumentPusher {
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 --git a/src/share/vm/prims/jvmtiEnv.cpp b/src/share/vm/prims/jvmtiEnv.cpp
index d88e39698..344f3d0a4 100644
--- a/src/share/vm/prims/jvmtiEnv.cpp
+++ b/src/share/vm/prims/jvmtiEnv.cpp
@@ -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 @@ JvmtiEnv::FollowReferences(jint heap_filter, jclass klass, jobject initial_objec
}
}
+ 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 --git a/src/share/vm/runtime/javaCalls.cpp b/src/share/vm/runtime/javaCalls.cpp
index 52fe2fb2c..12925a9aa 100644
--- a/src/share/vm/runtime/javaCalls.cpp
+++ b/src/share/vm/runtime/javaCalls.cpp
@@ -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 @@ void JavaCalls::call_helper(JavaValue* result, methodHandle* m, JavaCallArgument
// 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 @@ void JavaCalls::call_helper(JavaValue* result, methodHandle* m, JavaCallArgument
//--------------------------------------------------------------------------------------
// 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<oop*>(value);
+ return Handle::raw_resolve(ptr);
+ }
+
+ case JavaCallArguments::value_state_jobject:
+ {
+ jobject obj = reinterpret_cast<jobject>(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<intptr_t>(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<intptr_t>(obj);
+ _value_state[i] = value_state_oop;
}
}
// Return argument vector
@@ -444,30 +474,40 @@ intptr_t* JavaCallArguments::parameters() {
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 @@ class SignatureChekker : public SignatureIterator {
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 @@ class SignatureChekker : public SignatureIterator {
};
-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 @@ void JavaCallArguments::verify(methodHandle method, BasicType return_type,
// 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 --git a/src/share/vm/runtime/javaCalls.hpp b/src/share/vm/runtime/javaCalls.hpp
index bdf4d34c9..4af6a8c4b 100644
--- a/src/share/vm/runtime/javaCalls.hpp
+++ b/src/share/vm/runtime/javaCalls.hpp
@@ -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 @@ class JavaCallArguments : public StackObj {
_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<typename T>
+ 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 @@ class JavaCallArguments : public StackObj {
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 @@ class JavaCallArguments : public StackObj {
}
}
- 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 @@ class JavaCallArguments : public StackObj {
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 @@ class JavaCallArguments : public StackObj {
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 --git a/src/share/vm/runtime/jniHandles.cpp b/src/share/vm/runtime/jniHandles.cpp
index f10ca0fc2..be8438f29 100644
--- a/src/share/vm/runtime/jniHandles.cpp
+++ b/src/share/vm/runtime/jniHandles.cpp
@@ -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 @@ jobject JNIHandles::make_global(Handle obj) {
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<char*>(res) + weak_tag_value;
+ res = reinterpret_cast<jobject>(tptr);
} else {
CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
}
return res;
}
+template<bool external_guard>
+oop JNIHandles::resolve_jweak(jweak handle) {
+ assert(is_jweak(handle), "precondition");
+ oop result = jweak_ref(handle);
+ result = guard_value<external_guard>(result);
+#if INCLUDE_ALL_GCS
+ if (result != NULL && UseG1GC) {
+ G1SATBCardTableModRefBS::enqueue(result);
+ }
+#endif // INCLUDE_ALL_GCS
+ return result;
+}
+
+template oop JNIHandles::resolve_jweak<true>(jweak);
+template oop JNIHandles::resolve_jweak<false>(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 --git a/src/share/vm/runtime/jniHandles.hpp b/src/share/vm/runtime/jniHandles.hpp
index fe7d92a38..645e45bf9 100644
--- a/src/share/vm/runtime/jniHandles.hpp
+++ b/src/share/vm/runtime/jniHandles.hpp
@@ -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 @@ class JNIHandles : AllStatic {
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<bool external_guard> inline static oop guard_value(oop value);
+ template<bool external_guard> inline static oop resolve_impl(jobject handle);
+ template<bool external_guard> 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 @@ class JNIHandleBlock : public CHeapObj<mtInternal> {
#endif
};
+inline bool JNIHandles::is_jweak(jobject handle) {
+ STATIC_ASSERT(weak_tag_size == 1);
+ STATIC_ASSERT(weak_tag_value == 1);
+ return (reinterpret_cast<uintptr_t>(handle) & weak_tag_mask) != 0;
+}
-inline 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");
+inline oop& JNIHandles::jobject_ref(jobject handle) {
+ assert(!is_jweak(handle), "precondition");
+ return *reinterpret_cast<oop*>(handle);
+}
+
+inline oop& JNIHandles::jweak_ref(jobject handle) {
+ assert(is_jweak(handle), "precondition");
+ char* ptr = reinterpret_cast<char*>(handle) - weak_tag_value;
+ return *reinterpret_cast<oop*>(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<bool external_guard>
+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<bool external_guard>
+inline oop JNIHandles::resolve_impl(jobject handle) {
+ assert(handle != NULL, "precondition");
+ oop result;
+ if (is_jweak(handle)) { // Unlikely
+ result = resolve_jweak<external_guard>(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<external_guard>(result);
+ }
return result;
-};
+}
+inline oop JNIHandles::resolve(jobject handle) {
+ oop result = NULL;
+ if (handle != NULL) {
+ result = resolve_impl<false /* external_guard */ >(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<true /* external_guard */ >(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<false /* external_guard */ >(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 --git a/src/share/vm/shark/sharkNativeWrapper.cpp b/src/share/vm/shark/sharkNativeWrapper.cpp
index 53fea3154..27cb29aa2 100644
--- a/src/share/vm/shark/sharkNativeWrapper.cpp
+++ b/src/share/vm/shark/sharkNativeWrapper.cpp
@@ -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 @@ void SharkNativeWrapper::initialize(const char *name) {
// 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);