changeset 8974:32bc598624bd jdk8u222-b02

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
author phh
date Tue, 07 May 2019 20:38:26 +0000
parents acb9351e3a29
children e86bc9786d83 884a9feb3bb8
files src/cpu/ppc/vm/frame_ppc.cpp src/cpu/ppc/vm/interpreter_ppc.cpp src/cpu/ppc/vm/macroAssembler_ppc.cpp src/cpu/ppc/vm/macroAssembler_ppc.hpp src/cpu/ppc/vm/sharedRuntime_ppc.cpp src/cpu/sparc/vm/jniFastGetField_sparc.cpp src/cpu/sparc/vm/sharedRuntime_sparc.cpp src/cpu/sparc/vm/templateInterpreter_sparc.cpp src/cpu/x86/vm/jniFastGetField_x86_32.cpp src/cpu/x86/vm/jniFastGetField_x86_64.cpp src/cpu/x86/vm/macroAssembler_x86.cpp src/cpu/x86/vm/macroAssembler_x86.hpp src/cpu/x86/vm/sharedRuntime_x86_32.cpp src/cpu/x86/vm/sharedRuntime_x86_64.cpp src/cpu/x86/vm/templateInterpreter_x86_32.cpp src/cpu/x86/vm/templateInterpreter_x86_64.cpp src/cpu/zero/vm/cppInterpreter_zero.cpp src/share/vm/prims/jni.cpp src/share/vm/prims/jvmtiEnv.cpp src/share/vm/runtime/javaCalls.cpp src/share/vm/runtime/javaCalls.hpp src/share/vm/runtime/jniHandles.cpp src/share/vm/runtime/jniHandles.hpp src/share/vm/shark/sharkNativeWrapper.cpp
diffstat 24 files changed, 464 insertions(+), 183 deletions(-) [+]
line wrap: on
line diff
--- 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.
--- 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;
--- 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);
--- 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,
--- 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
   }
 
 
--- 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");
--- 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) {
--- 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);
--- 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
 
--- 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();
--- 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<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
--- 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,
--- 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) {
--- 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) {
--- 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);
--- 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);
--- 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<jobject>(result[0]);
+      istate->set_oop_temp(JNIHandles::resolve(handle));
+    }
   }
 
   // Reset handle block
--- 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; }
 
--- 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);
--- 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<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 @@
 
 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();
--- 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<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 @@
 
   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
--- 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<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();
   }
 }
 
--- 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<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 @@
   #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::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 = (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<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();
   }
 }
 
--- 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);