From 69c0f2aba4cbf189c4c8ada30a43afe5999622e4 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Mon, 27 Feb 2017 15:59:22 -0800 Subject: [PATCH 01/11] 8175516: JNI exception pending in jdk_tools_jaotc_jnilibelf_JNILibELFAPI.c:97 Add missing NULL checks Reviewed-by: iveresov --- .../jdk_tools_jaotc_jnilibelf_JNILibELFAPI.c | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/hotspot/src/jdk.aot/unix/native/libjelfshim/jdk_tools_jaotc_jnilibelf_JNILibELFAPI.c b/hotspot/src/jdk.aot/unix/native/libjelfshim/jdk_tools_jaotc_jnilibelf_JNILibELFAPI.c index d6d69cb439a..b64bc2dfdbc 100644 --- a/hotspot/src/jdk.aot/unix/native/libjelfshim/jdk_tools_jaotc_jnilibelf_JNILibELFAPI.c +++ b/hotspot/src/jdk.aot/unix/native/libjelfshim/jdk_tools_jaotc_jnilibelf_JNILibELFAPI.c @@ -70,18 +70,17 @@ JNIEXPORT jint JNICALL Java_jdk_tools_jaotc_jnilibelf_JNILibELFAPI_elf_1version */ static jlong getNativeAddress(JNIEnv* env, jobject ptrObj) { - jclass ptrClass; - jfieldID fidNumber; jlong nativeAddress = -1; - assert (ptrObj != NULL); + assert (ptrObj != NULL); // Get a reference to ptr object's class - ptrClass = (*env)->GetObjectClass(env, ptrObj); - - // Get the Field ID of the instance variables "address" - fidNumber = (*env)->GetFieldID(env, ptrClass, "address", "J"); - if (fidNumber != NULL) { - // Get the long given the Field ID - nativeAddress = (*env)->GetLongField(env, ptrObj, fidNumber); + jclass ptrClass = (*env)->GetObjectClass(env, ptrObj); + if (ptrClass != NULL) { + // Get the Field ID of the instance variables "address" + jfieldID fidNumber = (*env)->GetFieldID(env, ptrClass, "address", "J"); + if (fidNumber != NULL) { + // Get the long given the Field ID + nativeAddress = (*env)->GetLongField(env, ptrObj, fidNumber); + } } // fprintf(stderr, "Native address : %lx\n", nativeAddress); return nativeAddress; @@ -91,10 +90,15 @@ static jlong getNativeAddress(JNIEnv* env, jobject ptrObj) { * Box the nativeAddress as a Pointer object. */ static jobject makePointerObject(JNIEnv* env, jlong nativeAddr) { + jobject retObj = NULL; jclass ptrClass = (*env)->FindClass(env, "jdk/tools/jaotc/jnilibelf/Pointer"); - // Call back constructor to allocate a Pointer object, with an int argument - jmethodID constructorId = (*env)->GetMethodID(env, ptrClass, "", "(J)V"); - jobject retObj = (*env)->NewObject(env, ptrClass, constructorId, nativeAddr); + if (ptrClass != NULL) { + // Call back constructor to allocate a Pointer object, with an int argument + jmethodID constructorId = (*env)->GetMethodID(env, ptrClass, "", "(J)V"); + if (constructorId != NULL) { + retObj = (*env)->NewObject(env, ptrClass, constructorId, nativeAddr); + } + } return retObj; } From 1830b30f19cff2181bde870a445ad54369dc70da Mon Sep 17 00:00:00 2001 From: Jini George Date: Tue, 28 Feb 2017 10:10:14 +0530 Subject: [PATCH 02/11] 8175512: new TestPrintMdo.java fails with -XX:TieredStopAtLevel=1 Avoid running the test for -XX:TieredStopAtLevel=1 due to the lack of mdo data from JIT in this case. Reviewed-by: dsamersoff, sspitsyn --- hotspot/test/serviceability/sa/TestPrintMdo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/test/serviceability/sa/TestPrintMdo.java b/hotspot/test/serviceability/sa/TestPrintMdo.java index 0681aa02514..48b0b0840b8 100644 --- a/hotspot/test/serviceability/sa/TestPrintMdo.java +++ b/hotspot/test/serviceability/sa/TestPrintMdo.java @@ -39,7 +39,7 @@ import jdk.test.lib.Asserts; /* * @test * @library /test/lib - * @requires vm.flavor == "server" & !vm.emulatedClient + * @requires vm.flavor == "server" & !vm.emulatedClient & !(vm.opt.TieredStopAtLevel == 1) * @build jdk.test.lib.apps.* * @run main/othervm TestPrintMdo */ From 90fdff0e704ce15abcf2f985f8bfc3a766a397c1 Mon Sep 17 00:00:00 2001 From: Mikael Gerdin Date: Fri, 17 Feb 2017 13:16:54 +0100 Subject: [PATCH 03/11] 8175085: [REDO] G1 Needs pre barrier on dereference of weak JNI handles Reviewed-by: kbarrett, dcubed, tschatzl --- hotspot/make/test/JtregNative.gmk | 4 +- .../aarch64/vm/jniFastGetField_aarch64.cpp | 7 +- .../cpu/aarch64/vm/sharedRuntime_aarch64.cpp | 32 ++- .../templateInterpreterGenerator_aarch64.cpp | 27 ++- hotspot/src/cpu/arm/vm/interp_masm_arm.cpp | 181 +-------------- hotspot/src/cpu/arm/vm/interp_masm_arm.hpp | 23 +- .../src/cpu/arm/vm/jniFastGetField_arm.cpp | 10 +- hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp | 215 +++++++++++++++++- hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp | 25 +- hotspot/src/cpu/arm/vm/sharedRuntime_arm.cpp | 24 +- .../vm/templateInterpreterGenerator_arm.cpp | 35 ++- hotspot/src/cpu/ppc/vm/frame_ppc.cpp | 9 +- hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp | 34 ++- hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp | 6 +- hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp | 13 +- .../vm/templateInterpreterGenerator_ppc.cpp | 11 +- .../src/cpu/s390/vm/macroAssembler_s390.cpp | 28 +++ .../src/cpu/s390/vm/macroAssembler_s390.hpp | 2 + .../src/cpu/s390/vm/sharedRuntime_s390.cpp | 12 +- .../vm/templateInterpreterGenerator_s390.cpp | 11 +- .../cpu/sparc/vm/jniFastGetField_sparc.cpp | 5 +- .../src/cpu/sparc/vm/sharedRuntime_sparc.cpp | 33 ++- .../vm/templateInterpreterGenerator_sparc.cpp | 24 +- .../src/cpu/x86/vm/jniFastGetField_x86_32.cpp | 11 +- .../src/cpu/x86/vm/jniFastGetField_x86_64.cpp | 8 +- hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp | 39 +++- hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp | 5 +- .../src/cpu/x86/vm/sharedRuntime_x86_32.cpp | 13 +- .../src/cpu/x86/vm/sharedRuntime_x86_64.cpp | 13 +- .../vm/templateInterpreterGenerator_x86.cpp | 12 +- .../src/cpu/zero/vm/cppInterpreter_zero.cpp | 10 +- hotspot/src/share/vm/prims/jni.cpp | 7 +- hotspot/src/share/vm/prims/jvmtiEnv.cpp | 9 +- hotspot/src/share/vm/runtime/javaCalls.cpp | 118 ++++++---- hotspot/src/share/vm/runtime/javaCalls.hpp | 95 ++++++-- hotspot/src/share/vm/runtime/jniHandles.cpp | 37 ++- hotspot/src/share/vm/runtime/jniHandles.hpp | 106 +++++++-- .../src/share/vm/shark/sharkNativeWrapper.cpp | 3 +- .../jni/CallWithJNIWeak/CallWithJNIWeak.java | 72 ++++++ .../jni/CallWithJNIWeak/libCallWithJNIWeak.c | 142 ++++++++++++ .../jni/ReturnJNIWeak/ReturnJNIWeak.java | 132 +++++++++++ .../jni/ReturnJNIWeak/libReturnJNIWeak.c | 52 +++++ 42 files changed, 1221 insertions(+), 434 deletions(-) create mode 100644 hotspot/test/runtime/jni/CallWithJNIWeak/CallWithJNIWeak.java create mode 100644 hotspot/test/runtime/jni/CallWithJNIWeak/libCallWithJNIWeak.c create mode 100644 hotspot/test/runtime/jni/ReturnJNIWeak/ReturnJNIWeak.java create mode 100644 hotspot/test/runtime/jni/ReturnJNIWeak/libReturnJNIWeak.c diff --git a/hotspot/make/test/JtregNative.gmk b/hotspot/make/test/JtregNative.gmk index 7223733367a..42eb76af57e 100644 --- a/hotspot/make/test/JtregNative.gmk +++ b/hotspot/make/test/JtregNative.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 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 @@ -48,6 +48,8 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC := \ $(HOTSPOT_TOPDIR)/test/runtime/jni/PrivateInterfaceMethods \ $(HOTSPOT_TOPDIR)/test/runtime/jni/ToStringInInterfaceTest \ $(HOTSPOT_TOPDIR)/test/runtime/jni/CalleeSavedRegisters \ + $(HOTSPOT_TOPDIR)/test/runtime/jni/CallWithJNIWeak \ + $(HOTSPOT_TOPDIR)/test/runtime/jni/ReturnJNIWeak \ $(HOTSPOT_TOPDIR)/test/runtime/modules/getModuleJNI \ $(HOTSPOT_TOPDIR)/test/runtime/SameObject \ $(HOTSPOT_TOPDIR)/test/runtime/BoolReturn \ diff --git a/hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.cpp index b2f21031f18..a09c5230dc4 100644 --- a/hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.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. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -82,6 +82,11 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { __ eor(robj, robj, rcounter); // obj, since // robj ^ rcounter ^ rcounter == robj // robj is address dependent on rcounter. + + // If mask changes we need to ensure that the inverse is still encodable as an immediate + STATIC_ASSERT(JNIHandles::weak_tag_mask == 1); + __ andr(robj, robj, ~JNIHandles::weak_tag_mask); + __ ldr(robj, Address(robj, 0)); // *obj __ lsr(roffset, c_rarg2, 2); // offset diff --git a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp index 01e0eeb1fc1..a286102e7b1 100644 --- a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.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 (c) 2014, 2015, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -2052,13 +2052,31 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ reset_last_Java_frame(false); - // Unpack oop result + // Unbox oop result, e.g. JNIHandles::resolve result. if (ret_type == T_OBJECT || ret_type == T_ARRAY) { - Label L; - __ cbz(r0, L); - __ ldr(r0, Address(r0, 0)); - __ bind(L); - __ verify_oop(r0); + Label done, not_weak; + __ cbz(r0, done); // Use NULL as-is. + STATIC_ASSERT(JNIHandles::weak_tag_mask == 1u); + __ tbz(r0, 0, not_weak); // Test for jweak tag. + // Resolve jweak. + __ ldr(r0, Address(r0, -JNIHandles::weak_tag_value)); + __ verify_oop(r0); +#if INCLUDE_ALL_GCS + if (UseG1GC) { + __ g1_write_barrier_pre(noreg /* obj */, + r0 /* pre_val */, + rthread /* thread */, + rscratch1 /* tmp */, + true /* tosca_live */, + true /* expand_call */); + } +#endif // INCLUDE_ALL_GCS + __ b(done); + __ bind(not_weak); + // Resolve (untagged) jobject. + __ ldr(r0, Address(r0, 0)); + __ verify_oop(r0); + __ bind(done); } if (CheckJNICalls) { diff --git a/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp index 90dcd6c1a2c..6f44292c55a 100644 --- a/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.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 (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1399,13 +1399,32 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // and result handler will pick it up { - Label no_oop, store_result; + Label no_oop, not_weak, store_result; __ adr(t, ExternalAddress(AbstractInterpreter::result_handler(T_OBJECT))); __ cmp(t, result_handler); __ br(Assembler::NE, no_oop); - // retrieve result + // Unbox oop result, e.g. JNIHandles::resolve result. __ pop(ltos); - __ cbz(r0, store_result); + __ cbz(r0, store_result); // Use NULL as-is. + STATIC_ASSERT(JNIHandles::weak_tag_mask == 1u); + __ tbz(r0, 0, not_weak); // Test for jweak tag. + // Resolve jweak. + __ ldr(r0, Address(r0, -JNIHandles::weak_tag_value)); +#if INCLUDE_ALL_GCS + if (UseG1GC) { + __ enter(); // Barrier may call runtime. + __ g1_write_barrier_pre(noreg /* obj */, + r0 /* pre_val */, + rthread /* thread */, + t /* tmp */, + true /* tosca_live */, + true /* expand_call */); + __ leave(); + } +#endif // INCLUDE_ALL_GCS + __ b(store_result); + __ bind(not_weak); + // Resolve (untagged) jobject. __ ldr(r0, Address(r0, 0)); __ bind(store_result); __ str(r0, Address(rfp, frame::interpreter_frame_oop_temp_offset*wordSize)); diff --git a/hotspot/src/cpu/arm/vm/interp_masm_arm.cpp b/hotspot/src/cpu/arm/vm/interp_masm_arm.cpp index 2f41b102a85..96df37c275e 100644 --- a/hotspot/src/cpu/arm/vm/interp_masm_arm.cpp +++ b/hotspot/src/cpu/arm/vm/interp_masm_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -476,185 +476,6 @@ void InterpreterMacroAssembler::set_card(Register card_table_base, Address card_ } ////////////////////////////////////////////////////////////////////////////////// -#if INCLUDE_ALL_GCS - -// G1 pre-barrier. -// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR). -// If store_addr != noreg, then previous value is loaded from [store_addr]; -// in such case store_addr and new_val registers are preserved; -// otherwise pre_val register is preserved. -void InterpreterMacroAssembler::g1_write_barrier_pre(Register store_addr, - Register new_val, - Register pre_val, - Register tmp1, - Register tmp2) { - Label done; - Label runtime; - - if (store_addr != noreg) { - assert_different_registers(store_addr, new_val, pre_val, tmp1, tmp2, noreg); - } else { - assert (new_val == noreg, "should be"); - assert_different_registers(pre_val, tmp1, tmp2, noreg); - } - - Address in_progress(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + - SATBMarkQueue::byte_offset_of_active())); - Address index(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + - SATBMarkQueue::byte_offset_of_index())); - Address buffer(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + - SATBMarkQueue::byte_offset_of_buf())); - - // Is marking active? - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "adjust this code"); - ldrb(tmp1, in_progress); - cbz(tmp1, done); - - // Do we need to load the previous value? - if (store_addr != noreg) { - load_heap_oop(pre_val, Address(store_addr, 0)); - } - - // Is the previous value null? - cbz(pre_val, done); - - // Can we store original value in the thread's buffer? - // Is index == 0? - // (The index field is typed as size_t.) - - ldr(tmp1, index); // tmp1 := *index_adr - ldr(tmp2, buffer); - - subs(tmp1, tmp1, wordSize); // tmp1 := tmp1 - wordSize - b(runtime, lt); // If negative, goto runtime - - str(tmp1, index); // *index_adr := tmp1 - - // Record the previous value - str(pre_val, Address(tmp2, tmp1)); - b(done); - - bind(runtime); - - // save the live input values -#ifdef AARCH64 - if (store_addr != noreg) { - raw_push(store_addr, new_val); - } else { - raw_push(pre_val, ZR); - } -#else - if (store_addr != noreg) { - // avoid raw_push to support any ordering of store_addr and new_val - push(RegisterSet(store_addr) | RegisterSet(new_val)); - } else { - push(pre_val); - } -#endif // AARCH64 - - if (pre_val != R0) { - mov(R0, pre_val); - } - mov(R1, Rthread); - - call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), R0, R1); - -#ifdef AARCH64 - if (store_addr != noreg) { - raw_pop(store_addr, new_val); - } else { - raw_pop(pre_val, ZR); - } -#else - if (store_addr != noreg) { - pop(RegisterSet(store_addr) | RegisterSet(new_val)); - } else { - pop(pre_val); - } -#endif // AARCH64 - - bind(done); -} - -// G1 post-barrier. -// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR). -void InterpreterMacroAssembler::g1_write_barrier_post(Register store_addr, - Register new_val, - Register tmp1, - Register tmp2, - Register tmp3) { - - Address queue_index(Rthread, in_bytes(JavaThread::dirty_card_queue_offset() + - DirtyCardQueue::byte_offset_of_index())); - Address buffer(Rthread, in_bytes(JavaThread::dirty_card_queue_offset() + - DirtyCardQueue::byte_offset_of_buf())); - - BarrierSet* bs = Universe::heap()->barrier_set(); - CardTableModRefBS* ct = (CardTableModRefBS*)bs; - Label done; - Label runtime; - - // Does store cross heap regions? - - eor(tmp1, store_addr, new_val); -#ifdef AARCH64 - logical_shift_right(tmp1, tmp1, HeapRegion::LogOfHRGrainBytes); - cbz(tmp1, done); -#else - movs(tmp1, AsmOperand(tmp1, lsr, HeapRegion::LogOfHRGrainBytes)); - b(done, eq); -#endif - - // crosses regions, storing NULL? - - cbz(new_val, done); - - // storing region crossing non-NULL, is card already dirty? - const Register card_addr = tmp1; - assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code"); - - mov_address(tmp2, (address)ct->byte_map_base, symbolic_Relocation::card_table_reference); - add(card_addr, tmp2, AsmOperand(store_addr, lsr, CardTableModRefBS::card_shift)); - - ldrb(tmp2, Address(card_addr)); - cmp(tmp2, (int)G1SATBCardTableModRefBS::g1_young_card_val()); - b(done, eq); - - membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp2); - - assert(CardTableModRefBS::dirty_card_val() == 0, "adjust this code"); - ldrb(tmp2, Address(card_addr)); - cbz(tmp2, done); - - // storing a region crossing, non-NULL oop, card is clean. - // dirty card and log. - - strb(zero_register(tmp2), Address(card_addr)); - - ldr(tmp2, queue_index); - ldr(tmp3, buffer); - - subs(tmp2, tmp2, wordSize); - b(runtime, lt); // go to runtime if now negative - - str(tmp2, queue_index); - - str(card_addr, Address(tmp3, tmp2)); - b(done); - - bind(runtime); - - if (card_addr != R0) { - mov(R0, card_addr); - } - mov(R1, Rthread); - call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), R0, R1); - - bind(done); -} - -#endif // INCLUDE_ALL_GCS -////////////////////////////////////////////////////////////////////////////////// // Java Expression Stack diff --git a/hotspot/src/cpu/arm/vm/interp_masm_arm.hpp b/hotspot/src/cpu/arm/vm/interp_masm_arm.hpp index 5c753753f95..39e60226bf6 100644 --- a/hotspot/src/cpu/arm/vm/interp_masm_arm.hpp +++ b/hotspot/src/cpu/arm/vm/interp_masm_arm.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -146,27 +146,6 @@ class InterpreterMacroAssembler: public MacroAssembler { void set_card(Register card_table_base, Address card_table_addr, Register tmp); -#if INCLUDE_ALL_GCS - // G1 pre-barrier. - // Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR). - // If store_addr != noreg, then previous value is loaded from [store_addr]; - // in such case store_addr and new_val registers are preserved; - // otherwise pre_val register is preserved. - void g1_write_barrier_pre(Register store_addr, - Register new_val, - Register pre_val, - Register tmp1, - Register tmp2); - - // G1 post-barrier. - // Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR). - void g1_write_barrier_post(Register store_addr, - Register new_val, - Register tmp1, - Register tmp2, - Register tmp3); -#endif // INCLUDE_ALL_GCS - void pop_ptr(Register r); void pop_i(Register r = R0_tos); #ifdef AARCH64 diff --git a/hotspot/src/cpu/arm/vm/jniFastGetField_arm.cpp b/hotspot/src/cpu/arm/vm/jniFastGetField_arm.cpp index f9bd9f37970..65f929b1025 100644 --- a/hotspot/src/cpu/arm/vm/jniFastGetField_arm.cpp +++ b/hotspot/src/cpu/arm/vm/jniFastGetField_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -119,6 +119,14 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { __ ldr_s32(Rsafept_cnt, Address(Rsafepoint_counter_addr)); __ tbnz(Rsafept_cnt, 0, slow_case); +#ifdef AARCH64 + // If mask changes we need to ensure that the inverse is still encodable as an immediate + STATIC_ASSERT(JNIHandles::weak_tag_mask == 1); + __ andr(R1, R1, ~JNIHandles::weak_tag_mask); +#else + __ bic(R1, R1, JNIHandles::weak_tag_mask); +#endif + if (os::is_MP()) { // Address dependency restricts memory access ordering. It's cheaper than explicit LoadLoad barrier __ andr(Rtmp1, Rsafept_cnt, (unsigned)1); diff --git a/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp b/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp index ada7d3fc485..2eb2a551002 100644 --- a/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp +++ b/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -2211,6 +2211,219 @@ void MacroAssembler::biased_locking_exit(Register obj_reg, Register tmp_reg, Lab b(done, eq); } + +void MacroAssembler::resolve_jobject(Register value, + Register tmp1, + Register tmp2) { + assert_different_registers(value, tmp1, tmp2); + Label done, not_weak; + cbz(value, done); // Use NULL as-is. + STATIC_ASSERT(JNIHandles::weak_tag_mask == 1u); + tbz(value, 0, not_weak); // Test for jweak tag. + // Resolve jweak. + ldr(value, Address(value, -JNIHandles::weak_tag_value)); + verify_oop(value); +#if INCLUDE_ALL_GCS + if (UseG1GC) { + g1_write_barrier_pre(noreg, // store_addr + noreg, // new_val + value, // pre_val + tmp1, // tmp1 + tmp2); // tmp2 + } +#endif // INCLUDE_ALL_GCS + b(done); + bind(not_weak); + // Resolve (untagged) jobject. + ldr(value, Address(value)); + verify_oop(value); + bind(done); +} + + +////////////////////////////////////////////////////////////////////////////////// + +#if INCLUDE_ALL_GCS + +// G1 pre-barrier. +// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR). +// If store_addr != noreg, then previous value is loaded from [store_addr]; +// in such case store_addr and new_val registers are preserved; +// otherwise pre_val register is preserved. +void MacroAssembler::g1_write_barrier_pre(Register store_addr, + Register new_val, + Register pre_val, + Register tmp1, + Register tmp2) { + Label done; + Label runtime; + + if (store_addr != noreg) { + assert_different_registers(store_addr, new_val, pre_val, tmp1, tmp2, noreg); + } else { + assert (new_val == noreg, "should be"); + assert_different_registers(pre_val, tmp1, tmp2, noreg); + } + + Address in_progress(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_active())); + Address index(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_index())); + Address buffer(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_buf())); + + // Is marking active? + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "adjust this code"); + ldrb(tmp1, in_progress); + cbz(tmp1, done); + + // Do we need to load the previous value? + if (store_addr != noreg) { + load_heap_oop(pre_val, Address(store_addr, 0)); + } + + // Is the previous value null? + cbz(pre_val, done); + + // Can we store original value in the thread's buffer? + // Is index == 0? + // (The index field is typed as size_t.) + + ldr(tmp1, index); // tmp1 := *index_adr + ldr(tmp2, buffer); + + subs(tmp1, tmp1, wordSize); // tmp1 := tmp1 - wordSize + b(runtime, lt); // If negative, goto runtime + + str(tmp1, index); // *index_adr := tmp1 + + // Record the previous value + str(pre_val, Address(tmp2, tmp1)); + b(done); + + bind(runtime); + + // save the live input values +#ifdef AARCH64 + if (store_addr != noreg) { + raw_push(store_addr, new_val); + } else { + raw_push(pre_val, ZR); + } +#else + if (store_addr != noreg) { + // avoid raw_push to support any ordering of store_addr and new_val + push(RegisterSet(store_addr) | RegisterSet(new_val)); + } else { + push(pre_val); + } +#endif // AARCH64 + + if (pre_val != R0) { + mov(R0, pre_val); + } + mov(R1, Rthread); + + call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), R0, R1); + +#ifdef AARCH64 + if (store_addr != noreg) { + raw_pop(store_addr, new_val); + } else { + raw_pop(pre_val, ZR); + } +#else + if (store_addr != noreg) { + pop(RegisterSet(store_addr) | RegisterSet(new_val)); + } else { + pop(pre_val); + } +#endif // AARCH64 + + bind(done); +} + +// G1 post-barrier. +// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR). +void MacroAssembler::g1_write_barrier_post(Register store_addr, + Register new_val, + Register tmp1, + Register tmp2, + Register tmp3) { + + Address queue_index(Rthread, in_bytes(JavaThread::dirty_card_queue_offset() + + DirtyCardQueue::byte_offset_of_index())); + Address buffer(Rthread, in_bytes(JavaThread::dirty_card_queue_offset() + + DirtyCardQueue::byte_offset_of_buf())); + + BarrierSet* bs = Universe::heap()->barrier_set(); + CardTableModRefBS* ct = (CardTableModRefBS*)bs; + Label done; + Label runtime; + + // Does store cross heap regions? + + eor(tmp1, store_addr, new_val); +#ifdef AARCH64 + logical_shift_right(tmp1, tmp1, HeapRegion::LogOfHRGrainBytes); + cbz(tmp1, done); +#else + movs(tmp1, AsmOperand(tmp1, lsr, HeapRegion::LogOfHRGrainBytes)); + b(done, eq); +#endif + + // crosses regions, storing NULL? + + cbz(new_val, done); + + // storing region crossing non-NULL, is card already dirty? + const Register card_addr = tmp1; + assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code"); + + mov_address(tmp2, (address)ct->byte_map_base, symbolic_Relocation::card_table_reference); + add(card_addr, tmp2, AsmOperand(store_addr, lsr, CardTableModRefBS::card_shift)); + + ldrb(tmp2, Address(card_addr)); + cmp(tmp2, (int)G1SATBCardTableModRefBS::g1_young_card_val()); + b(done, eq); + + membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp2); + + assert(CardTableModRefBS::dirty_card_val() == 0, "adjust this code"); + ldrb(tmp2, Address(card_addr)); + cbz(tmp2, done); + + // storing a region crossing, non-NULL oop, card is clean. + // dirty card and log. + + strb(zero_register(tmp2), Address(card_addr)); + + ldr(tmp2, queue_index); + ldr(tmp3, buffer); + + subs(tmp2, tmp2, wordSize); + b(runtime, lt); // go to runtime if now negative + + str(tmp2, queue_index); + + str(card_addr, Address(tmp3, tmp2)); + b(done); + + bind(runtime); + + if (card_addr != R0) { + mov(R0, card_addr); + } + mov(R1, Rthread); + call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), R0, R1); + + bind(done); +} + +#endif // INCLUDE_ALL_GCS + +////////////////////////////////////////////////////////////////////////////////// + #ifdef AARCH64 void MacroAssembler::load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed) { diff --git a/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp b/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp index 770bba6c8a1..e6f73353cb9 100644 --- a/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp +++ b/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -402,6 +402,29 @@ public: void biased_locking_enter_with_cas(Register obj_reg, Register old_mark_reg, Register new_mark_reg, Register tmp, Label& slow_case, int* counter_addr); + void resolve_jobject(Register value, Register tmp1, Register tmp2); + +#if INCLUDE_ALL_GCS + // G1 pre-barrier. + // Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR). + // If store_addr != noreg, then previous value is loaded from [store_addr]; + // in such case store_addr and new_val registers are preserved; + // otherwise pre_val register is preserved. + void g1_write_barrier_pre(Register store_addr, + Register new_val, + Register pre_val, + Register tmp1, + Register tmp2); + + // G1 post-barrier. + // Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR). + void g1_write_barrier_post(Register store_addr, + Register new_val, + Register tmp1, + Register tmp2, + Register tmp3); +#endif // INCLUDE_ALL_GCS + #ifndef AARCH64 void nop() { mov(R0, R0); diff --git a/hotspot/src/cpu/arm/vm/sharedRuntime_arm.cpp b/hotspot/src/cpu/arm/vm/sharedRuntime_arm.cpp index 9b37b4fe6dc..48f096473c3 100644 --- a/hotspot/src/cpu/arm/vm/sharedRuntime_arm.cpp +++ b/hotspot/src/cpu/arm/vm/sharedRuntime_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -1732,14 +1732,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, case T_FLOAT : // fall through case T_DOUBLE : /* nothing to do */ break; case T_OBJECT : // fall through - case T_ARRAY : { - Label L; - __ cbz(R0, L); - __ ldr(R0, Address(R0)); - __ verify_oop(R0); - __ bind(L); - break; - } + case T_ARRAY : break; // See JNIHandles::resolve below default: ShouldNotReachHere(); } @@ -1748,14 +1741,15 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, if (CheckJNICalls) { __ str(__ zero_register(Rtemp), Address(Rthread, JavaThread::pending_jni_exception_check_fn_offset())); } - - // Unhandle the result - if (ret_type == T_OBJECT || ret_type == T_ARRAY) { - __ cmp(R0, 0); - __ ldr(R0, Address(R0), ne); - } #endif // AARCH64 + // Unbox oop result, e.g. JNIHandles::resolve value in R0. + if (ret_type == T_OBJECT || ret_type == T_ARRAY) { + __ resolve_jobject(R0, // value + Rtemp, // tmp1 + R1_tmp); // tmp2 + } + // Any exception pending? __ ldr(Rtemp, Address(Rthread, Thread::pending_exception_offset())); __ mov(SP, FP); diff --git a/hotspot/src/cpu/arm/vm/templateInterpreterGenerator_arm.cpp b/hotspot/src/cpu/arm/vm/templateInterpreterGenerator_arm.cpp index 743510e09a7..7fda747ad48 100644 --- a/hotspot/src/cpu/arm/vm/templateInterpreterGenerator_arm.cpp +++ b/hotspot/src/cpu/arm/vm/templateInterpreterGenerator_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -1240,28 +1240,25 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ str(__ zero_register(Rtemp), Address(Rthread, JavaThread::pending_jni_exception_check_fn_offset())); } - // Unbox if the result is non-zero object -#ifdef AARCH64 + // Unbox oop result, e.g. JNIHandles::resolve result if it's an oop. { - Label L, Lnull; + Label Lnot_oop; +#ifdef AARCH64 __ mov_slow(Rtemp, AbstractInterpreter::result_handler(T_OBJECT)); __ cmp(Rresult_handler, Rtemp); - __ b(L, ne); - __ cbz(Rsaved_result, Lnull); - __ ldr(Rsaved_result, Address(Rsaved_result)); - __ bind(Lnull); - // Store oop on the stack for GC - __ str(Rsaved_result, Address(FP, frame::interpreter_frame_oop_temp_offset * wordSize)); - __ bind(L); + __ b(Lnot_oop, ne); +#else // !AARCH64 + // For ARM32, Rresult_handler is -1 for oop result, 0 otherwise. + __ cbz(Rresult_handler, Lnot_oop); +#endif // !AARCH64 + Register value = AARCH64_ONLY(Rsaved_result) NOT_AARCH64(Rsaved_result_lo); + __ resolve_jobject(value, // value + Rtemp, // tmp1 + R1_tmp); // tmp2 + // Store resolved result in frame for GC visibility. + __ str(value, Address(FP, frame::interpreter_frame_oop_temp_offset * wordSize)); + __ bind(Lnot_oop); } -#else - __ tst(Rsaved_result_lo, Rresult_handler); - __ ldr(Rsaved_result_lo, Address(Rsaved_result_lo), ne); - - // Store oop on the stack for GC - __ cmp(Rresult_handler, 0); - __ str(Rsaved_result_lo, Address(FP, frame::interpreter_frame_oop_temp_offset * wordSize), ne); -#endif // AARCH64 #ifdef AARCH64 // Restore SP (drop native parameters area), to keep SP in sync with extended_sp in frame diff --git a/hotspot/src/cpu/ppc/vm/frame_ppc.cpp b/hotspot/src/cpu/ppc/vm/frame_ppc.cpp index 131a931c2c1..b6a538681f6 100644 --- a/hotspot/src/cpu/ppc/vm/frame_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/frame_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 SAP SE. All rights reserved. + * Copyright (c) 2000, 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 @@ -171,10 +171,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/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp index a5d5613a414..6eb27c78f17 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2016 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 @@ -3033,6 +3033,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. @@ -3094,7 +3122,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/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp index 11b966a82c9..0b1b2a0befa 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2016 SAP SE. All rights reserved. + * Copyright (c) 2002, 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 @@ -649,6 +649,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/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp index 784595f11be..dc36aa77da2 100644 --- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2016 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 @@ -2477,16 +2477,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 } if (CheckJNICalls) { diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp index 56810938a53..ab87c204018 100644 --- a/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2015, 2016 SAP SE. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -401,11 +401,8 @@ address TemplateInterpreterGenerator::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/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp b/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp index 0f78e5a6250..d5776117436 100644 --- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp +++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp @@ -3439,6 +3439,34 @@ void MacroAssembler::card_write_barrier_post(Register store_addr, Register tmp) z_mvi(0, store_addr, 0); // Store byte 0. } +void MacroAssembler::resolve_jobject(Register value, Register tmp1, Register tmp2) { + NearLabel Ldone; + z_ltgr(tmp1, value); + z_bre(Ldone); // Use NULL result as-is. + + z_nill(value, ~JNIHandles::weak_tag_mask); + z_lg(value, 0, value); // Resolve (untagged) jobject. + +#if INCLUDE_ALL_GCS + if (UseG1GC) { + NearLabel Lnot_weak; + z_tmll(tmp1, JNIHandles::weak_tag_mask); // Test for jweak tag. + z_braz(Lnot_weak); + verify_oop(value); + g1_write_barrier_pre(noreg /* obj */, + noreg /* offset */, + value /* pre_val */, + noreg /* val */, + tmp1 /* tmp1 */, + tmp2 /* tmp2 */, + true /* pre_val_needed */); + bind(Lnot_weak); + } +#endif // INCLUDE_ALL_GCS + verify_oop(value); + bind(Ldone); +} + #if INCLUDE_ALL_GCS //------------------------------------------------------ diff --git a/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp b/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp index 588bde6207e..2b4002a3bf4 100644 --- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp +++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp @@ -726,6 +726,8 @@ class MacroAssembler: public Assembler { // Write to card table for modification at store_addr - register is destroyed afterwards. void card_write_barrier_post(Register store_addr, Register tmp); + void resolve_jobject(Register value, Register tmp1, Register tmp2); + #if INCLUDE_ALL_GCS // General G1 pre-barrier generator. // Purpose: record the previous value if it is not null. diff --git a/hotspot/src/cpu/s390/vm/sharedRuntime_s390.cpp b/hotspot/src/cpu/s390/vm/sharedRuntime_s390.cpp index ea498e3399c..89c3ae4032a 100644 --- a/hotspot/src/cpu/s390/vm/sharedRuntime_s390.cpp +++ b/hotspot/src/cpu/s390/vm/sharedRuntime_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016 SAP SE. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -2272,13 +2272,9 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ reset_last_Java_frame(); - // Unpack oop result + // Unpack oop result, e.g. JNIHandles::resolve result. if (ret_type == T_OBJECT || ret_type == T_ARRAY) { - NearLabel L; - __ compare64_and_branch(Z_RET, (RegisterOrConstant)0L, Assembler::bcondEqual, L); - __ z_lg(Z_RET, 0, Z_RET); - __ bind(L); - __ verify_oop(Z_RET); + __ resolve_jobject(Z_RET, /* tmp1 */ Z_R13, /* tmp2 */ Z_R7); } if (CheckJNICalls) { diff --git a/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp b/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp index 2084f36006f..20a9a3e9571 100644 --- a/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp +++ b/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016 SAP SE. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -1695,14 +1695,11 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // from the jni handle to z_ijava_state.oop_temp. This is // necessary, because we reset the jni handle block below. // NOTE: frame::interpreter_frame_result() depends on this, too. - { NearLabel no_oop_result, store_oop_result; + { NearLabel no_oop_result; __ load_absolute_address(Z_R1, AbstractInterpreter::result_handler(T_OBJECT)); __ compareU64_and_branch(Z_R1, Rresult_handler, Assembler::bcondNotEqual, no_oop_result); - __ compareU64_and_branch(Rlresult, (intptr_t)0L, Assembler::bcondEqual, store_oop_result); - __ z_lg(Rlresult, 0, Rlresult); // unbox - __ bind(store_oop_result); + __ resolve_jobject(Rlresult, /* tmp1 */ Rmethod, /* tmp2 */ Z_R1); __ z_stg(Rlresult, oop_tmp_offset, Z_fp); - __ verify_oop(Rlresult); __ bind(no_oop_result); } diff --git a/hotspot/src/cpu/sparc/vm/jniFastGetField_sparc.cpp b/hotspot/src/cpu/sparc/vm/jniFastGetField_sparc.cpp index 6d3f05a2aab..ff9fcd69472 100644 --- a/hotspot/src/cpu/sparc/vm/jniFastGetField_sparc.cpp +++ b/hotspot/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/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp index 7b4dcf193d3..613e662d65c 100644 --- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.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 @@ -2754,15 +2754,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 (CheckJNICalls) { diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp index b677a1dd662..fd4e3ffd149 100644 --- a/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_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 @@ -1516,11 +1516,23 @@ address TemplateInterpreterGenerator::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/hotspot/src/cpu/x86/vm/jniFastGetField_x86_32.cpp b/hotspot/src/cpu/x86/vm/jniFastGetField_x86_32.cpp index a45e0eb9aa3..719bf8ce560 100644 --- a/hotspot/src/cpu/x86/vm/jniFastGetField_x86_32.cpp +++ b/hotspot/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 @@ -85,6 +85,9 @@ address JNI_FastGetField::generate_fast_get_int_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 @@ -202,6 +205,9 @@ address JNI_FastGetField::generate_fast_get_long_field() { __ 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 @@ -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/hotspot/src/cpu/x86/vm/jniFastGetField_x86_64.cpp b/hotspot/src/cpu/x86/vm/jniFastGetField_x86_64.cpp index 7286fd124b8..f18aa684266 100644 --- a/hotspot/src/cpu/x86/vm/jniFastGetField_x86_64.cpp +++ b/hotspot/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 @@ -80,6 +80,9 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { // robj ^ rcounter ^ rcounter == robj // robj is data dependent on rcounter. } + + __ clear_jweak_tag(robj); + __ movptr(robj, Address(robj, 0)); // *obj __ mov (roffset, c_rarg2); __ shrptr(roffset, 2); // offset @@ -178,6 +181,9 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) { // robj ^ rcounter ^ rcounter == robj // robj is data dependent on rcounter. } + + __ clear_jweak_tag(robj); + __ movptr(robj, Address(robj, 0)); // *obj __ mov (roffset, c_rarg2); __ shrptr(roffset, 2); // offset diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index b6d32631582..f2c8393fb12 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.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 @@ -5129,6 +5129,43 @@ 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(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/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp index a3e81e58dc5..39b2e1a5305 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -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 @@ -297,6 +297,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/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp index ed317550e08..47b9fe5c627 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.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 @@ -2226,14 +2226,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 (CheckJNICalls) { diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp index 4587b8caba6..d81e965d05d 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_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 @@ -2579,14 +2579,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 (CheckJNICalls) { diff --git a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp index eb5661bee00..9c02d44cdb8 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.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 @@ -1193,16 +1193,16 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // and result handler will pick it up { - Label no_oop, store_result; + Label no_oop, not_weak, store_result; __ 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 */, + 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/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp index 1fcf7d9984b..f7c51092c82 100644 --- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp +++ b/hotspot/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. * @@ -406,10 +406,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(result[0]); + istate->set_oop_temp(JNIHandles::resolve(handle)); + } } // Reset handle block diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index f519e5e2788..acda443267a 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.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. * Copyright (c) 2012 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -935,8 +935,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) { va_copy(_ap, rap); @@ -1025,7 +1024,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/hotspot/src/share/vm/prims/jvmtiEnv.cpp b/hotspot/src/share/vm/prims/jvmtiEnv.cpp index f9dc315a552..57292a2c8bc 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp +++ b/hotspot/src/share/vm/prims/jvmtiEnv.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 @@ -1796,6 +1796,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/hotspot/src/share/vm/runtime/javaCalls.cpp b/hotspot/src/share/vm/runtime/javaCalls.cpp index 5874699a1fc..d91a32a9f08 100644 --- a/hotspot/src/share/vm/runtime/javaCalls.cpp +++ b/hotspot/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 @@ -328,9 +328,9 @@ void JavaCalls::call_helper(JavaValue* result, const methodHandle& method, JavaC // 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())); #if INCLUDE_JVMCI } #else @@ -442,12 +442,43 @@ void JavaCalls::call_helper(JavaValue* result, const methodHandle& method, JavaC //-------------------------------------------------------------------------------------- // 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 %u", state); + return state != JavaCallArguments::value_state_primitive; +} + +inline oop resolve_indirect_oop(intptr_t value, uint state) { + switch (state) { + case JavaCallArguments::value_state_handle: + { + oop* ptr = reinterpret_cast(value); + return Handle::raw_resolve(ptr); + } + + case JavaCallArguments::value_state_jobject: + { + jobject obj = reinterpret_cast(value); + return JNIHandles::resolve(obj); + } + + default: + ShouldNotReachHere(); + return NULL; + } +} + intptr_t* JavaCallArguments::parameters() { // First convert all handles to oops for(int i = 0; i < _size; i++) { - if (_is_oop[i]) { - // Handle conversion - _value[i] = cast_from_oop(Handle::raw_resolve((oop *)_value[i])); + uint state = _value_state[i]; + assert(state != value_state_oop, "Multiple handle conversions"); + if (is_value_state_indirect_oop(state)) { + oop obj = resolve_indirect_oop(_value[i], state); + _value[i] = cast_from_oop(obj); + _value_state[i] = value_state_oop; } } // Return argument vector @@ -457,30 +488,42 @@ intptr_t* JavaCallArguments::parameters() { class SignatureChekker : public SignatureIterator { private: - bool *_is_oop; - int _pos; + int _pos; BasicType _return_type; - intptr_t* _value; - Thread* _thread; + 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: %u at %d", + state, _pos - 1); + } else { + guarantee(state == JavaCallArguments::value_state_primitive, + "signature does not match pushed arguments: %u at %d", + state, _pos - 1); + } } void check_doing_return(bool state) { _is_return = state; } @@ -515,24 +558,20 @@ 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 %d: " PTR_FORMAT, _pos, v); + // Verify the pointee. + oop vv = resolve_indirect_oop(v, _value_state[_pos]); + guarantee(vv->is_oop_or_null(true), + "Bad JNI oop argument %d: " PTR_FORMAT " -> " PTR_FORMAT, + _pos, v, p2i(vv)); } - check_value(true); + check_value(true); // Verify value state. } void do_bool() { check_int(T_BOOLEAN); } @@ -549,8 +588,7 @@ class SignatureChekker : public SignatureIterator { }; -void JavaCallArguments::verify(const methodHandle& method, BasicType return_type, - Thread *thread) { +void JavaCallArguments::verify(const 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 @@ -559,7 +597,11 @@ void JavaCallArguments::verify(const 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/hotspot/src/share/vm/runtime/javaCalls.hpp b/hotspot/src/share/vm/runtime/javaCalls.hpp index efe1f8b9813..e77abf7d36b 100644 --- a/hotspot/src/share/vm/runtime/javaCalls.hpp +++ b/hotspot/src/share/vm/runtime/javaCalls.hpp @@ -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 @@ -80,11 +80,11 @@ 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 @@ -92,8 +92,8 @@ class JavaCallArguments : public StackObj { 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; @@ -101,6 +101,23 @@ class JavaCallArguments : public StackObj { JVMCI_ONLY(_alternative_target = NULL;) } + // Helper for push_oop and the like. The value argument is a + // "handle" that refers to an oop. We record the address of the + // handle rather than the designated oop. The handle is later + // resolved to the oop by parameters(). This delays the exposure of + // naked oops until it is GC-safe. + template + inline int push_oop_impl(T handle, int size) { + // JNITypes::put_obj expects an oop value, so we play fast and + // loose with the type system. The cast from handle type to oop + // *must* use a C-style cast. In a product build it performs a + // reinterpret_cast. In a debug build (more accurately, in a + // CHECK_UNHANDLED_OOPS build) it performs a static_cast, invoking + // the debug-only oop class's conversion from void* constructor. + JNITypes::put_obj((oop)handle, _value, size); // Updates size. + return size; // Return the updated size. + } + public: JavaCallArguments() { initialize(); } @@ -111,11 +128,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; @@ -136,25 +154,52 @@ class JavaCallArguments : public StackObj { } #endif - 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); } @@ -162,11 +207,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 @@ -174,7 +219,7 @@ class JavaCallArguments : public StackObj { int size_of_parameters() const { return _size; } // Verify that pushed arguments fits a given method - void verify(const methodHandle& method, BasicType return_type, Thread *thread); + void verify(const methodHandle& method, BasicType return_type); }; // All calls to Java have to go via JavaCalls. Sets up the stack frame diff --git a/hotspot/src/share/vm/runtime/jniHandles.cpp b/hotspot/src/share/vm/runtime/jniHandles.cpp index 679ade0eaca..f4aae3c20bf 100644 --- a/hotspot/src/share/vm/runtime/jniHandles.cpp +++ b/hotspot/src/share/vm/runtime/jniHandles.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2016, 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 @@ -31,6 +31,9 @@ #include "runtime/jniHandles.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/thread.inline.hpp" +#if INCLUDE_ALL_GCS +#include "gc/g1/g1SATBCardTableModRefBS.hpp" +#endif JNIHandleBlock* JNIHandles::_global_handles = NULL; JNIHandleBlock* JNIHandles::_weak_global_handles = NULL; @@ -92,28 +95,48 @@ jobject JNIHandles::make_weak_global(Handle obj) { jobject res = NULL; if (!obj.is_null()) { // ignore null handles - MutexLocker ml(JNIGlobalHandle_lock); - assert(Universe::heap()->is_in_reserved(obj()), "sanity check"); - res = _weak_global_handles->allocate_handle(obj()); + { + MutexLocker ml(JNIGlobalHandle_lock); + assert(Universe::heap()->is_in_reserved(obj()), "sanity check"); + res = _weak_global_handles->allocate_handle(obj()); + } + // Add weak tag. + assert(is_ptr_aligned(res, weak_tag_alignment), "invariant"); + char* tptr = reinterpret_cast(res) + weak_tag_value; + res = reinterpret_cast(tptr); } else { CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops()); } return res; } +template +oop JNIHandles::resolve_jweak(jweak handle) { + assert(is_jweak(handle), "precondition"); + oop result = jweak_ref(handle); + result = guard_value(result); +#if INCLUDE_ALL_GCS + if (result != NULL && UseG1GC) { + G1SATBCardTableModRefBS::enqueue(result); + } +#endif // INCLUDE_ALL_GCS + return result; +} + +template oop JNIHandles::resolve_jweak(jweak); +template oop JNIHandles::resolve_jweak(jweak); void JNIHandles::destroy_global(jobject handle) { if (handle != NULL) { assert(is_global_handle(handle), "Invalid delete of global JNI handle"); - *((oop*)handle) = deleted_handle(); // Mark the handle as deleted, allocate will reuse it + jobject_ref(handle) = deleted_handle(); } } void JNIHandles::destroy_weak_global(jobject handle) { if (handle != NULL) { - assert(!CheckJNICalls || is_weak_global_handle(handle), "Invalid delete of weak global JNI handle"); - *((oop*)handle) = deleted_handle(); // Mark the handle as deleted, allocate will reuse it + jweak_ref(handle) = deleted_handle(); } } diff --git a/hotspot/src/share/vm/runtime/jniHandles.hpp b/hotspot/src/share/vm/runtime/jniHandles.hpp index ce37d940d7c..13e0e155740 100644 --- a/hotspot/src/share/vm/runtime/jniHandles.hpp +++ b/hotspot/src/share/vm/runtime/jniHandles.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, 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 inline static oop guard_value(oop value); + template inline static oop resolve_impl(jobject handle); + template static oop resolve_jweak(jweak handle); + public: + // Low tag bit in jobject used to distinguish a jweak. jweak is + // type equivalent to jobject, but there are places where we need to + // be able to distinguish jweak values from other jobjects, and + // is_weak_global_handle is unsuitable for performance reasons. To + // provide such a test we add weak_tag_value to the (aligned) byte + // address designated by the jobject to produce the corresponding + // jweak. Accessing the value of a jobject must account for it + // being a possibly offset jweak. + static const uintptr_t weak_tag_size = 1; + static const uintptr_t weak_tag_alignment = (1u << weak_tag_size); + static const uintptr_t weak_tag_mask = weak_tag_alignment - 1; + static const int weak_tag_value = 1; + // Resolve handle into oop inline static oop resolve(jobject handle); // Resolve externally provided handle into oop with some guards @@ -176,36 +197,85 @@ class JNIHandleBlock : public CHeapObj { #endif }; +inline bool JNIHandles::is_jweak(jobject handle) { + STATIC_ASSERT(weak_tag_size == 1); + STATIC_ASSERT(weak_tag_value == 1); + return (reinterpret_cast(handle) & weak_tag_mask) != 0; +} + +inline oop& JNIHandles::jobject_ref(jobject handle) { + assert(!is_jweak(handle), "precondition"); + return *reinterpret_cast(handle); +} + +inline oop& JNIHandles::jweak_ref(jobject handle) { + assert(is_jweak(handle), "precondition"); + char* ptr = reinterpret_cast(handle) - weak_tag_value; + return *reinterpret_cast(ptr); +} + +// external_guard is true if called from resolve_external_guard. +// Treat deleted (and possibly zapped) as NULL for external_guard, +// else as (asserted) error. +template +inline oop JNIHandles::guard_value(oop value) { + if (!external_guard) { + assert(value != badJNIHandle, "Pointing to zapped jni handle area"); + assert(value != deleted_handle(), "Used a deleted global handle"); + } else if ((value == badJNIHandle) || (value == deleted_handle())) { + value = NULL; + } + return value; +} + +// external_guard is true if called from resolve_external_guard. +template +inline oop JNIHandles::resolve_impl(jobject handle) { + assert(handle != NULL, "precondition"); + oop result; + if (is_jweak(handle)) { // Unlikely + result = resolve_jweak(handle); + } else { + result = jobject_ref(handle); + // Construction of jobjects canonicalize a null value into a null + // jobject, so for non-jweak the pointee should never be null. + assert(external_guard || result != NULL, + "Invalid value read from jni handle"); + result = guard_value(result); + } + return result; +} inline oop JNIHandles::resolve(jobject handle) { - oop result = (handle == NULL ? (oop)NULL : *(oop*)handle); - assert(result != NULL || (handle == NULL || !CheckJNICalls || is_weak_global_handle(handle)), "Invalid value read from jni handle"); - assert(result != badJNIHandle, "Pointing to zapped jni handle area"); + oop result = NULL; + if (handle != NULL) { + result = resolve_impl(handle); + } return result; -}; - +} +// Resolve some erroneous cases to NULL, rather than treating them as +// possibly unchecked errors. In particular, deleted handles are +// treated as NULL (though a deleted and later reallocated handle +// isn't detected). inline oop JNIHandles::resolve_external_guard(jobject handle) { - if (handle == NULL) return NULL; - oop result = *(oop*)handle; - if (result == NULL || result == badJNIHandle) return NULL; + oop result = NULL; + if (handle != NULL) { + result = resolve_impl(handle); + } return result; -}; - +} inline oop JNIHandles::resolve_non_null(jobject handle) { assert(handle != NULL, "JNI handle should not be null"); - oop result = *(oop*)handle; - assert(result != NULL, "Invalid value read from jni handle"); - assert(result != badJNIHandle, "Pointing to zapped jni handle area"); - // Don't let that private _deleted_handle object escape into the wild. - assert(result != deleted_handle(), "Used a deleted global handle."); + oop result = resolve_impl(handle); + assert(result != NULL, "NULL read from jni handle"); return result; -}; +} inline void JNIHandles::destroy_local(jobject handle) { if (handle != NULL) { - *((oop*)handle) = deleted_handle(); // Mark the handle as deleted, allocate will reuse it + jobject_ref(handle) = deleted_handle(); } } diff --git a/hotspot/src/share/vm/shark/sharkNativeWrapper.cpp b/hotspot/src/share/vm/shark/sharkNativeWrapper.cpp index 53fea3154b8..b9ac6a3ebf5 100644 --- a/hotspot/src/share/vm/shark/sharkNativeWrapper.cpp +++ b/hotspot/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. * @@ -300,6 +300,7 @@ void SharkNativeWrapper::initialize(const char *name) { not_null, merge); builder()->SetInsertPoint(not_null); +#error Needs to be updated for tagged jweak; see JNIHandles. Value *unboxed_result = builder()->CreateLoad(result); builder()->CreateBr(merge); diff --git a/hotspot/test/runtime/jni/CallWithJNIWeak/CallWithJNIWeak.java b/hotspot/test/runtime/jni/CallWithJNIWeak/CallWithJNIWeak.java new file mode 100644 index 00000000000..3aaec5e4fd5 --- /dev/null +++ b/hotspot/test/runtime/jni/CallWithJNIWeak/CallWithJNIWeak.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8166188 + * @summary Test call of native function with JNI weak global ref. + * @modules java.base + * @run main/othervm/native CallWithJNIWeak + */ + +public class CallWithJNIWeak { + static { + System.loadLibrary("CallWithJNIWeak"); + } + + private static native void testJNIFieldAccessors(CallWithJNIWeak o); + + // The field initializations must be kept in sync with the JNI code + // which reads verifies the values of these fields. + private int i = 1; + private long j = 2; + private boolean z = true; + private char c = 'a'; + private short s = 3; + private float f = 1.0f; + private double d = 2.0; + private Object l; + + private CallWithJNIWeak() { + this.l = this; + } + + private native void weakReceiverTest0(); + private void weakReceiverTest() { + weakReceiverTest0(); + } + + private synchronized void synchonizedWeakReceiverTest() { + this.notifyAll(); + } + + + private static native void runTests(CallWithJNIWeak o); + + public static void main(String[] args) { + CallWithJNIWeak w = new CallWithJNIWeak(); + for (int i = 0; i < 20000; i++) { + runTests(w); + } + } +} diff --git a/hotspot/test/runtime/jni/CallWithJNIWeak/libCallWithJNIWeak.c b/hotspot/test/runtime/jni/CallWithJNIWeak/libCallWithJNIWeak.c new file mode 100644 index 00000000000..83a5784c1e8 --- /dev/null +++ b/hotspot/test/runtime/jni/CallWithJNIWeak/libCallWithJNIWeak.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include + +/* + * Class: CallWithJNIWeak + * Method: testJNIFieldAccessors + * Signature: (LCallWithJNIWeak;)V + */ +JNIEXPORT void JNICALL +Java_CallWithJNIWeak_testJNIFieldAccessors(JNIEnv *env, jclass clazz, jobject this) { + // Make sure that we have a weak reference to the receiver + + jweak self = (*env)->NewWeakGlobalRef(env, this); + + jclass this_class = (*env)->GetObjectClass(env, self); + + jclass exception = (*env)->FindClass(env, "java/lang/RuntimeException"); + + jfieldID id_i = (*env)->GetFieldID(env, this_class, "i", "I"); + jfieldID id_j = (*env)->GetFieldID(env, this_class, "j", "J"); + jfieldID id_z = (*env)->GetFieldID(env, this_class, "z", "Z"); + jfieldID id_c = (*env)->GetFieldID(env, this_class, "c", "C"); + jfieldID id_s = (*env)->GetFieldID(env, this_class, "s", "S"); + jfieldID id_f = (*env)->GetFieldID(env, this_class, "f", "F"); + jfieldID id_d = (*env)->GetFieldID(env, this_class, "d", "D"); + jfieldID id_l = (*env)->GetFieldID(env, this_class, "l", "Ljava/lang/Object;"); + jvalue v; + +#define CHECK(variable, expected) \ + do { \ + if ((variable) != (expected)) { \ + (*env)->ThrowNew(env, exception, #variable" != " #expected); \ + return; \ + } \ + } while(0) + + // The values checked below must be kept in sync with the Java source file. + + v.i = (*env)->GetIntField(env, self, id_i); + CHECK(v.i, 1); + + v.j = (*env)->GetLongField(env, self, id_j); + CHECK(v.j, 2); + + v.z = (*env)->GetBooleanField(env, self, id_z); + CHECK(v.z, JNI_TRUE); + + v.c = (*env)->GetCharField(env, self, id_c); + CHECK(v.c, 'a'); + + v.s = (*env)->GetShortField(env, self, id_s); + CHECK(v.s, 3); + + v.f = (*env)->GetFloatField(env, self, id_f); + CHECK(v.f, 1.0f); + + v.d = (*env)->GetDoubleField(env, self, id_d); + CHECK(v.d, 2.0); + +#undef CHECK + + v.l = (*env)->GetObjectField(env, self, id_l); + if (v.l == NULL) { + (*env)->ThrowNew(env, exception, "Object field was null"); + return; + } + { + jclass clz = (*env)->GetObjectClass(env, v.l); + if (!(*env)->IsSameObject(env, clazz, clz)) { + (*env)->ThrowNew(env, exception, "Bad object class"); + } + } + + (*env)->DeleteWeakGlobalRef(env, self); +} + +/* + * Class: CallWithJNIWeak + * Method: runTests + * Signature: (LCallWithJNIWeak;)V + */ +JNIEXPORT void JNICALL +Java_CallWithJNIWeak_runTests(JNIEnv *env, jclass clazz, jobject this) { + jweak that = (*env)->NewWeakGlobalRef(env, this); + { + jmethodID method = (*env)->GetStaticMethodID(env, + clazz, "testJNIFieldAccessors", "(LCallWithJNIWeak;)V"); + (*env)->CallStaticVoidMethod(env, clazz, method, that); + if ((*env)->ExceptionCheck(env)) { + return; + } + } + + { + jmethodID method = (*env)->GetMethodID(env, clazz, "weakReceiverTest", "()V"); + (*env)->CallVoidMethod(env, that, method); + if ((*env)->ExceptionCheck(env)) { + return; + } + } + + { + jmethodID method = (*env)->GetMethodID(env, clazz, "synchonizedWeakReceiverTest", "()V"); + (*env)->CallVoidMethod(env, that, method); + if ((*env)->ExceptionCheck(env)) { + return; + } + } + (*env)->DeleteWeakGlobalRef(env, that); +} + +/* + * Class: CallWithJNIWeak + * Method: weakReceiverTest0 + * Signature: ()V + */ +JNIEXPORT void JNICALL +Java_CallWithJNIWeak_weakReceiverTest0(JNIEnv *env, jobject obj) { + (*env)->GetObjectClass(env, obj); +} diff --git a/hotspot/test/runtime/jni/ReturnJNIWeak/ReturnJNIWeak.java b/hotspot/test/runtime/jni/ReturnJNIWeak/ReturnJNIWeak.java new file mode 100644 index 00000000000..6d581000fb8 --- /dev/null +++ b/hotspot/test/runtime/jni/ReturnJNIWeak/ReturnJNIWeak.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8166188 + * @requires vm.opt.ExplicitGCInvokesConcurrent != true + * @summary Test return of JNI weak global refs from native calls. + * @modules java.base + * @run main/othervm/native -Xint ReturnJNIWeak + * @run main/othervm/native -Xcomp ReturnJNIWeak + */ + +public final class ReturnJNIWeak { + + static { + System.loadLibrary("ReturnJNIWeak"); + } + + private static final class TestObject { + public final int value; + + public TestObject(int value) { + this.value = value; + } + } + + private static volatile TestObject testObject = null; + + private static native void registerObject(Object o); + private static native void unregisterObject(); + private static native Object getObject(); + + // Create the test object and record it both strongly and weakly. + private static void remember(int value) { + TestObject o = new TestObject(value); + registerObject(o); + testObject = o; + } + + // Remove both strong and weak references to the current test object. + private static void forget() { + unregisterObject(); + testObject = null; + } + + // Verify the weakly recorded object + private static void checkValue(int value) throws Exception { + Object o = getObject(); + if (o == null) { + throw new RuntimeException("Weak reference unexpectedly null"); + } + TestObject t = (TestObject)o; + if (t.value != value) { + throw new RuntimeException("Incorrect value"); + } + } + + // Verify we can create a weak reference and get it back. + private static void testSanity() throws Exception { + System.out.println("running testSanity"); + int value = 5; + try { + remember(value); + checkValue(value); + } finally { + forget(); + } + } + + // Verify weak ref value survives across collection if strong ref exists. + private static void testSurvival() throws Exception { + System.out.println("running testSurvival"); + int value = 10; + try { + remember(value); + checkValue(value); + System.gc(); + // Verify weak ref still has expected value. + checkValue(value); + } finally { + forget(); + } + } + + // Verify weak ref cleared if no strong ref exists. + private static void testClear() throws Exception { + System.out.println("running testClear"); + int value = 15; + try { + remember(value); + checkValue(value); + // Verify still good. + checkValue(value); + // Drop reference. + testObject = null; + System.gc(); + // Verify weak ref cleared as expected. + Object recorded = getObject(); + if (recorded != null) { + throw new RuntimeException("expected clear"); + } + } finally { + forget(); + } + } + + public static void main(String[] args) throws Exception { + testSanity(); + testSurvival(); + testClear(); + } +} diff --git a/hotspot/test/runtime/jni/ReturnJNIWeak/libReturnJNIWeak.c b/hotspot/test/runtime/jni/ReturnJNIWeak/libReturnJNIWeak.c new file mode 100644 index 00000000000..12d7ae92e6e --- /dev/null +++ b/hotspot/test/runtime/jni/ReturnJNIWeak/libReturnJNIWeak.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * Native support for ReturnJNIWeak test. + */ + +#include "jni.h" + +static jweak registered = NULL; + +JNIEXPORT void JNICALL +Java_ReturnJNIWeak_registerObject(JNIEnv* env, + jclass jclazz, + jobject value) { + // assert registered == NULL + registered = (*env)->NewWeakGlobalRef(env, value); +} + +JNIEXPORT void JNICALL +Java_ReturnJNIWeak_unregisterObject(JNIEnv* env, jclass jclazz) { + if (registered != NULL) { + (*env)->DeleteWeakGlobalRef(env, registered); + registered = NULL; + } +} + +JNIEXPORT jobject JNICALL +Java_ReturnJNIWeak_getObject(JNIEnv* env, jclass jclazz) { + // assert registered != NULL + return registered; +} From 5b097b494dac819dc34bc08c8f4a06bc59adca4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rickard=20B=C3=A4ckman?= Date: Thu, 23 Feb 2017 10:08:51 +0100 Subject: [PATCH 04/11] 8175336: [TESTBUG] aot junit tests added by 8169588 are not executed Reviewed-by: kvn --- .../jaotc/test/collect/ClassSearchTest.java | 103 +++++++++++++++--- .../jaotc/test/collect/ClassSourceTest.java | 8 ++ .../jaotc/test/collect/FakeFileSupport.java | 2 + .../jaotc/test/collect/FakeSearchPath.java | 2 + .../jaotc/test/collect/SearchPathTest.java | 13 +++ .../DirectorySourceProviderTest.java | 13 ++- .../collect/jar/JarSourceProviderTest.java | 14 +++ .../module/ModuleSourceProviderTest.java | 62 ++++++++--- 8 files changed, 182 insertions(+), 35 deletions(-) diff --git a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSearchTest.java b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSearchTest.java index b212fc3139c..18983b351c6 100644 --- a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSearchTest.java +++ b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSearchTest.java @@ -20,10 +20,19 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + +/** + * @test + * @modules jdk.aot/jdk.tools.jaotc + * jdk.aot/jdk.tools.jaotc.collect + * @run junit/othervm jdk.tools.jaotc.test.collect.ClassSearchTest + */ + package jdk.tools.jaotc.test.collect; import jdk.tools.jaotc.LoadedClass; +import jdk.tools.jaotc.collect.*; import org.junit.Assert; import org.junit.Test; @@ -32,45 +41,90 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.BiConsumer; +import java.util.function.BiFunction; public class ClassSearchTest { @Test(expected = InternalError.class) public void itShouldThrowExceptionIfNoProvidersAvailable() { ClassSearch target = new ClassSearch(); SearchPath searchPath = new SearchPath(); - target.search(list("foo"), searchPath); + target.search(list(new SearchFor("foo")), searchPath); } @Test public void itShouldFindAProviderForEachEntry() { Set searched = new HashSet<>(); ClassSearch target = new ClassSearch(); - target.addProvider(new SourceProvider() { - @Override - public ClassSource findSource(String name, SearchPath searchPath) { + target.addProvider(provider("", (name, searchPath) -> { searched.add(name); return new NoopSource(); - } - }); - target.search(list("foo", "bar", "foobar"), null); + })); + target.search(searchForList("foo", "bar", "foobar"), null); Assert.assertEquals(hashset("foo", "bar", "foobar"), searched); } + private SourceProvider provider(String supports, BiFunction fn) { + return new SourceProvider() { + @Override + public ClassSource findSource(String name, SearchPath searchPath) { + return fn.apply(name, searchPath); + } + + @Override + public boolean supports(String type) { + return supports.equals(type); + } + }; + } + @Test - public void itShouldSearchAllProviders() { + public void itShouldOnlySearchSupportedProvidersForKnownType() { Set visited = new HashSet<>(); ClassSearch target = new ClassSearch(); - target.addProvider((name, searchPath) -> { - visited.add("1"); + + target.addProvider(provider("jar", (name, searchPath) -> { + visited.add("jar"); return null; - }); - target.addProvider((name, searchPath) -> { - visited.add("2"); + })); + + target.addProvider(provider("dir", (name, searchPath) -> { + visited.add("dir"); return null; - }); + })); try { - target.search(list("foo"), null); + target.search(list(new SearchFor("some", "dir")), null); + } catch (InternalError e) { + // throws because no provider gives a source + } + + Assert.assertEquals(hashset("dir"), visited); + } + + @Test(expected = InternalError.class) + public void itShouldThrowErrorIfMultipleSourcesAreAvailable() { + ClassSearch target = new ClassSearch(); + target.addProvider(provider("", (name, searchPath) -> consumer -> Assert.fail())); + target.addProvider(provider("", (name, searchPath) -> consumer -> Assert.fail())); + + target.search(searchForList("somethign"), null); + } + + @Test + public void itShouldSearchAllProvidersForUnknownType() { + Set visited = new HashSet<>(); + ClassSearch target = new ClassSearch(); + target.addProvider(provider("", (name, searchPath) -> { + visited.add("1"); + return null; + })); + target.addProvider(provider("", (name, searchPath) -> { + visited.add("2"); + return null; + })); + + try { + target.search(searchForList("foo"), null); } catch (InternalError e) { // throws because no provider gives a source } @@ -84,6 +138,11 @@ public class ClassSearchTest { ClassSearch target = new ClassSearch(); target.addProvider(new SourceProvider() { + @Override + public boolean supports(String type) { + return true; + } + @Override public ClassSource findSource(String name, SearchPath searchPath) { return new ClassSource() { @@ -101,7 +160,7 @@ public class ClassSearchTest { } }); - java.util.List search = target.search(list("/tmp/something"), null); + java.util.List search = target.search(searchForList("/tmp/something"), null); Assert.assertEquals(list(new LoadedClass("foo.Bar", null)), search); } @@ -115,8 +174,16 @@ public class ClassSearchTest { }; ClassSearch target = new ClassSearch(); - target.addProvider((name, searchPath) -> consumer -> consumer.accept("foo.Bar", classLoader)); - target.search(list("foobar"), null); + target.addProvider(provider("", (name, searchPath) -> consumer -> consumer.accept("foo.Bar", classLoader))); + target.search(searchForList("foobar"), null); + } + + private List searchForList(String... entries) { + List list = new ArrayList<>(); + for (String entry : entries) { + list.add(new SearchFor(entry)); + } + return list; } private List list(T... entries) { diff --git a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSourceTest.java b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSourceTest.java index 5fad5f57d76..ac9b8c9d12a 100644 --- a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSourceTest.java +++ b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSourceTest.java @@ -20,6 +20,14 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + +/** + * @test + * @modules jdk.aot/jdk.tools.jaotc + * jdk.aot/jdk.tools.jaotc.collect + * @run junit/othervm jdk.tools.jaotc.test.collect.ClassSourceTest + */ + package jdk.tools.jaotc.test.collect; import org.junit.Assert; diff --git a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeFileSupport.java b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeFileSupport.java index 178c3d47353..0e9011ac4f3 100644 --- a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeFileSupport.java +++ b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeFileSupport.java @@ -27,6 +27,8 @@ import java.nio.file.Path; import java.util.HashSet; import java.util.Set; +import jdk.tools.jaotc.collect.FileSupport; + public class FakeFileSupport extends FileSupport { private final Set exists = new HashSet<>(); private final Set directories = new HashSet<>(); diff --git a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeSearchPath.java b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeSearchPath.java index 9a7873ccf96..899d89f6228 100644 --- a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeSearchPath.java +++ b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/FakeSearchPath.java @@ -22,6 +22,8 @@ */ package jdk.tools.jaotc.test.collect; +import jdk.tools.jaotc.collect.SearchPath; + import java.nio.file.FileSystem; import java.nio.file.Path; import java.nio.file.Paths; diff --git a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/SearchPathTest.java b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/SearchPathTest.java index 8ceca8dc5cf..f3d3f56051d 100644 --- a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/SearchPathTest.java +++ b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/SearchPathTest.java @@ -20,6 +20,17 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + +/** + * @test + * @modules jdk.aot/jdk.tools.jaotc + * jdk.aot/jdk.tools.jaotc.collect + * + * @build jdk.tools.jaotc.test.collect.Utils + * @build jdk.tools.jaotc.test.collect.FakeFileSupport + * @run junit/othervm jdk.tools.jaotc.test.collect.SearchPathTest + */ + package jdk.tools.jaotc.test.collect; import org.junit.Before; @@ -30,6 +41,8 @@ import java.nio.file.FileSystems; import java.nio.file.Path; import java.nio.file.Paths; +import jdk.tools.jaotc.collect.*; + import static jdk.tools.jaotc.test.collect.Utils.set; import static org.junit.Assert.*; diff --git a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/directory/DirectorySourceProviderTest.java b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/directory/DirectorySourceProviderTest.java index 6608c01ab50..66ed4e234e2 100644 --- a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/directory/DirectorySourceProviderTest.java +++ b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/directory/DirectorySourceProviderTest.java @@ -21,11 +21,22 @@ * questions. */ +/** + * @test + * @modules jdk.aot/jdk.tools.jaotc + * jdk.aot/jdk.tools.jaotc.collect + * jdk.aot/jdk.tools.jaotc.collect.directory + * @compile ../Utils.java + * @compile ../FakeFileSupport.java + * @run junit/othervm jdk.tools.jaotc.test.collect.directory.DirectorySourceProviderTest + */ + package jdk.tools.jaotc.test.collect.directory; import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.directory.DirectorySourceProvider; import jdk.tools.jaotc.test.collect.FakeFileSupport; -import jdk.tools.jaotc.test.collect.FileSupport; +import jdk.tools.jaotc.collect.FileSupport; import org.junit.Assert; import org.junit.Test; diff --git a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/jar/JarSourceProviderTest.java b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/jar/JarSourceProviderTest.java index 14059883538..a6b687fdad4 100644 --- a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/jar/JarSourceProviderTest.java +++ b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/jar/JarSourceProviderTest.java @@ -20,9 +20,23 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + +/** + * @test + * @modules jdk.aot/jdk.tools.jaotc + * jdk.aot/jdk.tools.jaotc.collect + * jdk.aot/jdk.tools.jaotc.collect.jar + * @compile ../Utils.java + * @compile ../FakeFileSupport.java + * @compile ../FakeSearchPath.java + * + * @run junit/othervm jdk.tools.jaotc.test.collect.jar.JarSourceProviderTest + */ + package jdk.tools.jaotc.test.collect.jar; import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.jar.JarSourceProvider; import jdk.tools.jaotc.test.collect.FakeFileSupport; import jdk.tools.jaotc.test.collect.FakeSearchPath; import org.junit.Assert; diff --git a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/module/ModuleSourceProviderTest.java b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/module/ModuleSourceProviderTest.java index 80f06913269..b8a44041b19 100644 --- a/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/module/ModuleSourceProviderTest.java +++ b/hotspot/test/compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/module/ModuleSourceProviderTest.java @@ -20,15 +20,31 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + +/** + * @test + * @modules jdk.aot/jdk.tools.jaotc + * jdk.aot/jdk.tools.jaotc.collect + * jdk.aot/jdk.tools.jaotc.collect.module + * @compile ../Utils.java + * @run junit/othervm jdk.tools.jaotc.test.collect.module.ModuleSourceProviderTest + */ + package jdk.tools.jaotc.test.collect.module; -import jdk.tools.jaotc.*; -import jdk.tools.jaotc.test.collect.FakeSearchPath; +import jdk.tools.jaotc.collect.FileSupport; +import jdk.tools.jaotc.collect.module.ModuleSource; +import jdk.tools.jaotc.collect.module.ModuleSourceProvider; import jdk.tools.jaotc.test.collect.Utils; import org.junit.Before; import org.junit.Test; +import java.io.IOException; +import java.nio.file.FileSystem; import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.function.BiFunction; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -36,28 +52,42 @@ import static org.junit.Assert.assertNull; public class ModuleSourceProviderTest { private ClassLoader classLoader; private ModuleSourceProvider target; + private FileSupport fileSupport; + private BiFunction getSubDirectory = null; @Before public void setUp() { classLoader = new FakeClassLoader(); - target = new ModuleSourceProvider(FileSystems.getDefault(), classLoader); + fileSupport = new FileSupport() { + + @Override + public boolean isDirectory(Path path) { + return true; + } + + @Override + public Path getSubDirectory(FileSystem fileSystem, Path root, Path path) throws IOException { + if (getSubDirectory == null) { + throw new IOException("Nope"); + } + return getSubDirectory.apply(root, path); + } + }; + target = new ModuleSourceProvider(FileSystems.getDefault(), classLoader, fileSupport); } @Test - public void itShouldUseSearchPath() { - FakeSearchPath searchPath = new FakeSearchPath("blah/java.base"); - ModuleSource source = (ModuleSource) target.findSource("java.base", searchPath); - assertEquals(Utils.set("java.base"), searchPath.entries); - assertEquals("blah/java.base", source.getModulePath().toString()); - assertEquals("module:blah/java.base", source.toString()); - } + public void itShouldUseFileSupport() { + getSubDirectory = (root, path) -> { + if (root.toString().equals("modules") && path.toString().equals("test.module")) { + return Paths.get("modules/test.module"); + } + return null; + }; - @Test - public void itShouldReturnNullIfSearchPathReturnsNull() { - FakeSearchPath searchPath = new FakeSearchPath(null); - ModuleSource source = (ModuleSource) target.findSource("jdk.base", searchPath); - assertEquals(Utils.set("jdk.base"), searchPath.entries); - assertNull(source); + ModuleSource source = (ModuleSource) target.findSource("test.module", null); + assertEquals("modules/test.module", source.getModulePath().toString()); + assertEquals("module:modules/test.module", source.toString()); } private static class FakeClassLoader extends ClassLoader { From c7de967bcb7457e1caa94aefd6f26eea538ea223 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Fri, 24 Feb 2017 11:52:04 +0100 Subject: [PATCH 05/11] 8139906: assert(src->section_index_of(target) == CodeBuffer::SECT_NONE) failed: sanity The card table address used in the g1_post_barrier_slow stub should not be marked as relocatable. Reviewed-by: kvn --- hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp b/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp index 9f17c8fc810..5e793e16bd7 100644 --- a/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp +++ b/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp @@ -618,7 +618,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Address buffer(Rthread, in_bytes(JavaThread::dirty_card_queue_offset() + DirtyCardQueue::byte_offset_of_buf())); - AddressLiteral cardtable((address)ct->byte_map_base); + AddressLiteral cardtable((address)ct->byte_map_base, relocInfo::none); assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code"); // save at least the registers that need saving if the runtime is called @@ -645,7 +645,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { // Note: there is a comment in x86 code about not using // ExternalAddress / lea, due to relocation not working // properly for that address. Should be OK for arm, where we - // explicitly specify that 'cartable' has a relocInfo::none + // explicitly specify that 'cardtable' has a relocInfo::none // type. __ lea(r_card_base_1, cardtable); __ add(r_card_addr_0, r_card_base_1, AsmOperand(r_obj_0, lsr, CardTableModRefBS::card_shift)); From 86a9ef8d83ed9b90d365e10a59abaa9f9de2573c Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Fri, 24 Feb 2017 04:32:11 -0800 Subject: [PATCH 06/11] 8175811: [JVMCI] StubRoutines::_multiplyToLen symbol needs to exported Reviewed-by: thartmann --- hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp index 1cfc1021b39..0ce9816890a 100644 --- a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp +++ b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp @@ -305,6 +305,7 @@ static_field(StubRoutines, _crc32c_table_addr, address) \ static_field(StubRoutines, _updateBytesCRC32C, address) \ static_field(StubRoutines, _updateBytesAdler32, address) \ + static_field(StubRoutines, _multiplyToLen, address) \ static_field(StubRoutines, _squareToLen, address) \ static_field(StubRoutines, _mulAdd, address) \ static_field(StubRoutines, _montgomeryMultiply, address) \ From 4145e90718bf59004fd8cc6904e0dfd2c5254034 Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Thu, 23 Feb 2017 18:57:10 +0100 Subject: [PATCH 07/11] 8168914: Crash in ClassLoaderData/JNIHandleBlock::oops_do during concurrent marking Reviewed-by: dholmes, tschatzl, coleenp, kbarrett, eosterlund, stefank --- .../share/vm/classfile/classLoaderData.cpp | 100 ++++++++++++++---- .../share/vm/classfile/classLoaderData.hpp | 40 +++++-- .../src/share/vm/classfile/moduleEntry.cpp | 8 +- 3 files changed, 115 insertions(+), 33 deletions(-) diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp index d1e37d82761..c7b26613d07 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -93,7 +93,7 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Depen _keep_alive((is_anonymous || h_class_loader.is_null()) ? 1 : 0), _metaspace(NULL), _unloading(false), _klasses(NULL), _modules(NULL), _packages(NULL), - _claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL), + _claimed(0), _jmethod_ids(NULL), _handles(), _deallocate_list(NULL), _next(NULL), _dependencies(dependencies), _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true, Monitor::_safepoint_check_never)) { @@ -112,6 +112,76 @@ void ClassLoaderData::Dependencies::init(TRAPS) { _list_head = oopFactory::new_objectArray(2, CHECK); } +ClassLoaderData::ChunkedHandleList::~ChunkedHandleList() { + Chunk* c = _head; + while (c != NULL) { + Chunk* next = c->_next; + delete c; + c = next; + } +} + +oop* ClassLoaderData::ChunkedHandleList::add(oop o) { + if (_head == NULL || _head->_size == Chunk::CAPACITY) { + Chunk* next = new Chunk(_head); + OrderAccess::release_store_ptr(&_head, next); + } + oop* handle = &_head->_data[_head->_size]; + *handle = o; + OrderAccess::release_store(&_head->_size, _head->_size + 1); + return handle; +} + +inline void ClassLoaderData::ChunkedHandleList::oops_do_chunk(OopClosure* f, Chunk* c, const juint size) { + for (juint i = 0; i < size; i++) { + if (c->_data[i] != NULL) { + f->do_oop(&c->_data[i]); + } + } +} + +void ClassLoaderData::ChunkedHandleList::oops_do(OopClosure* f) { + Chunk* head = (Chunk*) OrderAccess::load_ptr_acquire(&_head); + if (head != NULL) { + // Must be careful when reading size of head + oops_do_chunk(f, head, OrderAccess::load_acquire(&head->_size)); + for (Chunk* c = head->_next; c != NULL; c = c->_next) { + oops_do_chunk(f, c, c->_size); + } + } +} + +#ifdef ASSERT +class VerifyContainsOopClosure : public OopClosure { + oop* _target; + bool _found; + + public: + VerifyContainsOopClosure(oop* target) : _target(target), _found(false) {} + + void do_oop(oop* p) { + if (p == _target) { + _found = true; + } + } + + void do_oop(narrowOop* p) { + // The ChunkedHandleList should not contain any narrowOop + ShouldNotReachHere(); + } + + bool found() const { + return _found; + } +}; + +bool ClassLoaderData::ChunkedHandleList::contains(oop* p) { + VerifyContainsOopClosure cl(p); + oops_do(&cl); + return cl.found(); +} +#endif + bool ClassLoaderData::claim() { if (_claimed == 1) { return false; @@ -146,9 +216,9 @@ void ClassLoaderData::oops_do(OopClosure* f, KlassClosure* klass_closure, bool m f->do_oop(&_class_loader); _dependencies.oops_do(f); - if (_handles != NULL) { - _handles->oops_do(f); - } + + _handles.oops_do(f); + if (klass_closure != NULL) { classes_do(klass_closure); } @@ -484,12 +554,6 @@ ClassLoaderData::~ClassLoaderData() { _metaspace = NULL; delete m; } - // release the handles - if (_handles != NULL) { - JNIHandleBlock::release_block(_handles); - _handles = NULL; - } - // Clear all the JNI handles for methods // These aren't deallocated and are going to look like a leak, but that's // needed because we can't really get rid of jmethodIDs because we don't @@ -563,19 +627,14 @@ Metaspace* ClassLoaderData::metaspace_non_null() { return metaspace; } -JNIHandleBlock* ClassLoaderData::handles() const { return _handles; } -void ClassLoaderData::set_handles(JNIHandleBlock* handles) { _handles = handles; } - jobject ClassLoaderData::add_handle(Handle h) { MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); - if (handles() == NULL) { - set_handles(JNIHandleBlock::allocate_block()); - } - return handles()->allocate_handle(h()); + return (jobject) _handles.add(h()); } -void ClassLoaderData::remove_handle(jobject h) { - _handles->release_handle(h); +void ClassLoaderData::remove_handle_unsafe(jobject h) { + assert(_handles.contains((oop*) h), "Got unexpected handle " PTR_FORMAT, p2i((oop*) h)); + *((oop*) h) = NULL; } // Add this metadata pointer to be freed when it's safe. This is only during @@ -645,7 +704,6 @@ void ClassLoaderData::dump(outputStream * const out) { p2i(class_loader() != NULL ? class_loader()->klass() : NULL), loader_name()); if (claimed()) out->print(" claimed "); if (is_unloading()) out->print(" unloading "); - out->print(" handles " INTPTR_FORMAT, p2i(handles())); out->cr(); if (metaspace_or_null() != NULL) { out->print_cr("metaspace: " INTPTR_FORMAT, p2i(metaspace_or_null())); diff --git a/hotspot/src/share/vm/classfile/classLoaderData.hpp b/hotspot/src/share/vm/classfile/classLoaderData.hpp index 8c8df5187a7..3c0aba64992 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.hpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -52,7 +52,6 @@ class ClassLoaderData; class JNIMethodBlock; -class JNIHandleBlock; class Metadebug; class ModuleEntry; class PackageEntry; @@ -160,6 +159,34 @@ class ClassLoaderData : public CHeapObj { void oops_do(OopClosure* f); }; + class ChunkedHandleList VALUE_OBJ_CLASS_SPEC { + struct Chunk : public CHeapObj { + static const size_t CAPACITY = 32; + + oop _data[CAPACITY]; + volatile juint _size; + Chunk* _next; + + Chunk(Chunk* c) : _next(c), _size(0) { } + }; + + Chunk* _head; + + void oops_do_chunk(OopClosure* f, Chunk* c, const juint size); + + public: + ChunkedHandleList() : _head(NULL) {} + ~ChunkedHandleList(); + + // Only one thread at a time can add, guarded by ClassLoaderData::metaspace_lock(). + // However, multiple threads can execute oops_do concurrently with add. + oop* add(oop o); +#ifdef ASSERT + bool contains(oop* p); +#endif + void oops_do(OopClosure* f); + }; + friend class ClassLoaderDataGraph; friend class ClassLoaderDataGraphKlassIteratorAtomic; friend class ClassLoaderDataGraphMetaspaceIterator; @@ -185,8 +212,8 @@ class ClassLoaderData : public CHeapObj { volatile int _claimed; // true if claimed, for example during GC traces. // To avoid applying oop closure more than once. // Has to be an int because we cas it. - JNIHandleBlock* _handles; // Handles to constant pool arrays, Modules, etc, which - // have the same life cycle of the corresponding ClassLoader. + ChunkedHandleList _handles; // Handles to constant pool arrays, Modules, etc, which + // have the same life cycle of the corresponding ClassLoader. Klass* volatile _klasses; // The classes defined by the class loader. PackageEntryTable* volatile _packages; // The packages defined by the class loader. @@ -217,9 +244,6 @@ class ClassLoaderData : public CHeapObj { ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies); ~ClassLoaderData(); - JNIHandleBlock* handles() const; - void set_handles(JNIHandleBlock* handles); - // GC interface. void clear_claimed() { _claimed = 0; } bool claimed() const { return _claimed == 1; } @@ -312,7 +336,7 @@ class ClassLoaderData : public CHeapObj { const char* loader_name(); jobject add_handle(Handle h); - void remove_handle(jobject h); + void remove_handle_unsafe(jobject h); void add_class(Klass* k, bool publicize = true); void remove_class(Klass* k); bool contains_klass(Klass* k); diff --git a/hotspot/src/share/vm/classfile/moduleEntry.cpp b/hotspot/src/share/vm/classfile/moduleEntry.cpp index 9402f5d91e1..42384cbacd2 100644 --- a/hotspot/src/share/vm/classfile/moduleEntry.cpp +++ b/hotspot/src/share/vm/classfile/moduleEntry.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -87,11 +87,11 @@ Handle ModuleEntry::shared_protection_domain() { // Set the shared ProtectionDomain atomically void ModuleEntry::set_shared_protection_domain(ClassLoaderData *loader_data, Handle pd_h) { - // Create a JNI handle for the shared ProtectionDomain and save it atomically. - // If someone beats us setting the _pd cache, the created JNI handle is destroyed. + // Create a handle for the shared ProtectionDomain and save it atomically. + // If someone beats us setting the _pd cache, the created handle is destroyed. jobject obj = loader_data->add_handle(pd_h); if (Atomic::cmpxchg_ptr(obj, &_pd, NULL) != NULL) { - loader_data->remove_handle(obj); + loader_data->remove_handle_unsafe(obj); } } From b9854ff95a819fa0c638ae75456aec216dc55a20 Mon Sep 17 00:00:00 2001 From: Bob Vandette Date: Tue, 28 Feb 2017 10:44:49 -0500 Subject: [PATCH 08/11] 8175567: Build of hotspot for arm-vfp-sflt fails Reviewed-by: kvn, cjplummer --- hotspot/src/share/vm/c1/c1_LIR.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/c1/c1_LIR.hpp b/hotspot/src/share/vm/c1/c1_LIR.hpp index 5046a76b13f..a9c073d32b0 100644 --- a/hotspot/src/share/vm/c1/c1_LIR.hpp +++ b/hotspot/src/share/vm/c1/c1_LIR.hpp @@ -613,7 +613,7 @@ class LIR_OprFact: public AllStatic { // Platform dependant. static LIR_Opr double_fpu(int reg1, int reg2 = -1 /*fnoreg*/); -#ifdef __SOFTFP__ +#ifdef ARM32 static LIR_Opr single_softfp(int reg) { return (LIR_Opr)(intptr_t)((reg << LIR_OprDesc::reg1_shift) | LIR_OprDesc::float_type | @@ -627,7 +627,7 @@ class LIR_OprFact: public AllStatic { LIR_OprDesc::cpu_register | LIR_OprDesc::double_size); } -#endif // __SOFTFP__ +#endif // ARM32 #if defined(X86) static LIR_Opr single_xmm(int reg) { From 9e4e386872770e605a4a5dc7d3daee074db0f830 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 1 Mar 2017 14:51:12 +0300 Subject: [PATCH 09/11] 8175887: C1 value numbering handling of Unsafe.get*Volatile is incorrect Reviewed-by: vlivanov --- hotspot/src/share/vm/c1/c1_ValueMap.hpp | 8 ++- .../compiler/c1/UnsafeVolatileGuardTest.java | 69 +++++++++++++++++++ .../test/compiler/c1/VolatileGuardTest.java | 52 ++++++++++++++ 3 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 hotspot/test/compiler/c1/UnsafeVolatileGuardTest.java create mode 100644 hotspot/test/compiler/c1/VolatileGuardTest.java diff --git a/hotspot/src/share/vm/c1/c1_ValueMap.hpp b/hotspot/src/share/vm/c1/c1_ValueMap.hpp index e2e1c1b15fe..5b1342ede66 100644 --- a/hotspot/src/share/vm/c1/c1_ValueMap.hpp +++ b/hotspot/src/share/vm/c1/c1_ValueMap.hpp @@ -157,6 +157,12 @@ class ValueNumberingVisitor: public InstructionVisitor { void do_UnsafePutRaw (UnsafePutRaw* x) { kill_memory(); } void do_UnsafePutObject(UnsafePutObject* x) { kill_memory(); } void do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) { kill_memory(); } + void do_UnsafeGetRaw (UnsafeGetRaw* x) { /* nothing to do */ } + void do_UnsafeGetObject(UnsafeGetObject* x) { + if (x->is_volatile()) { // the JMM requires this + kill_memory(); + } + } void do_Intrinsic (Intrinsic* x) { if (!x->preserves_state()) kill_memory(); } void do_Phi (Phi* x) { /* nothing to do */ } @@ -197,8 +203,6 @@ class ValueNumberingVisitor: public InstructionVisitor { void do_OsrEntry (OsrEntry* x) { /* nothing to do */ } void do_ExceptionObject(ExceptionObject* x) { /* nothing to do */ } void do_RoundFP (RoundFP* x) { /* nothing to do */ } - void do_UnsafeGetRaw (UnsafeGetRaw* x) { /* nothing to do */ } - void do_UnsafeGetObject(UnsafeGetObject* x) { /* nothing to do */ } void do_ProfileCall (ProfileCall* x) { /* nothing to do */ } void do_ProfileReturnType (ProfileReturnType* x) { /* nothing to do */ } void do_ProfileInvoke (ProfileInvoke* x) { /* nothing to do */ }; diff --git a/hotspot/test/compiler/c1/UnsafeVolatileGuardTest.java b/hotspot/test/compiler/c1/UnsafeVolatileGuardTest.java new file mode 100644 index 00000000000..b10c4a6285c --- /dev/null +++ b/hotspot/test/compiler/c1/UnsafeVolatileGuardTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2017, Red Hat Inc. 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.reflect.Field; + +/** + * @test + * @bug 8175887 + * @summary C1 value numbering handling of Unsafe.get*Volatile is incorrect + * @modules java.base/jdk.internal.misc + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:TieredStopAtLevel=1 UnsafeVolatileGuardTest + */ +public class UnsafeVolatileGuardTest { + volatile static private int a; + static private int b; + + static final jdk.internal.misc.Unsafe UNSAFE = jdk.internal.misc.Unsafe.getUnsafe(); + + static final Object BASE; + static final long OFFSET; + + static { + try { + Field f = UnsafeVolatileGuardTest.class.getDeclaredField("a"); + BASE = UNSAFE.staticFieldBase(f); + OFFSET = UNSAFE.staticFieldOffset(f); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + static void test() { + int tt = b; // makes the JVM CSE the value of b + + while (UNSAFE.getIntVolatile(BASE, OFFSET) == 0) {} // burn + if (b == 0) { + System.err.println("wrong value of b"); + System.exit(1); // fail hard to report the error + } + } + + public static void main(String [] args) throws Exception { + for (int i = 0; i < 10; i++) { + new Thread(UnsafeVolatileGuardTest::test).start(); + } + b = 1; + a = 1; + } +} diff --git a/hotspot/test/compiler/c1/VolatileGuardTest.java b/hotspot/test/compiler/c1/VolatileGuardTest.java new file mode 100644 index 00000000000..44b603160ad --- /dev/null +++ b/hotspot/test/compiler/c1/VolatileGuardTest.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017, Red Hat Inc. 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8175887 + * @summary C1 doesn't respect the JMM with volatile field loads + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:TieredStopAtLevel=1 VolatileGuardTest + */ +public class VolatileGuardTest { + volatile static private int a; + static private int b; + + static void test() { + int tt = b; // makes the JVM CSE the value of b + + while (a == 0) {} // burn + if (b == 0) { + System.err.println("wrong value of b"); + System.exit(1); // fail hard to report the error + } + } + + public static void main(String [] args) throws Exception { + for (int i = 0; i < 10; i++) { + new Thread(VolatileGuardTest::test).start(); + } + b = 1; + a = 1; + } +} From 5bd3dfadc65496785f160c066f8a24c8cea10c2e Mon Sep 17 00:00:00 2001 From: Christian Haeubl Date: Mon, 27 Feb 2017 17:36:36 +0100 Subject: [PATCH 10/11] 8175917: [JVMCI] Avoid long JNI handle chains Reviewed-by: never, kvn --- .../src/share/vm/jvmci/jvmciCompilerToVM.cpp | 28 +++++++++++++++++++ .../src/share/vm/jvmci/jvmciCompilerToVM.hpp | 10 +++++++ 2 files changed, 38 insertions(+) diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp index 66b7936d3c8..6f02a6ce79e 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp @@ -56,6 +56,31 @@ #include "utilities/resourceHash.hpp" +void JNIHandleMark::push_jni_handle_block() { + JavaThread* thread = JavaThread::current(); + if (thread != NULL) { + // Allocate a new block for JNI handles. + // Inlined code from jni_PushLocalFrame() + JNIHandleBlock* java_handles = ((JavaThread*)thread)->active_handles(); + JNIHandleBlock* compile_handles = JNIHandleBlock::allocate_block(thread); + assert(compile_handles != NULL && java_handles != NULL, "should not be NULL"); + compile_handles->set_pop_frame_link(java_handles); + thread->set_active_handles(compile_handles); + } +} + +void JNIHandleMark::pop_jni_handle_block() { + JavaThread* thread = JavaThread::current(); + if (thread != NULL) { + // Release our JNI handle block + JNIHandleBlock* compile_handles = thread->active_handles(); + JNIHandleBlock* java_handles = compile_handles->pop_frame_link(); + thread->set_active_handles(java_handles); + compile_handles->set_pop_frame_link(NULL); + JNIHandleBlock::release_block(compile_handles, thread); // may block + } +} + // Entry to native method implementation that transitions current thread to '_thread_in_vm'. #define C2V_VMENTRY(result_type, name, signature) \ JNIEXPORT result_type JNICALL c2v_ ## name signature { \ @@ -89,6 +114,7 @@ oop CompilerToVM::get_jvmci_type(KlassHandle klass, TRAPS) { return NULL; } + int CompilerToVM::Data::Klass_vtable_start_offset; int CompilerToVM::Data::Klass_vtable_length_offset; @@ -985,6 +1011,8 @@ C2V_END C2V_VMENTRY(jint, installCode, (JNIEnv *jniEnv, jobject, jobject target, jobject compiled_code, jobject installed_code, jobject speculation_log)) ResourceMark rm; HandleMark hm; + JNIHandleMark jni_hm; + Handle target_handle = JNIHandles::resolve(target); Handle compiled_code_handle = JNIHandles::resolve(compiled_code); CodeBlob* cb = NULL; diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp index 500cdfec829..036ffdd3249 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp @@ -206,4 +206,14 @@ class JavaArgumentUnboxer : public SignatureIterator { inline void do_void() { } }; +class JNIHandleMark : public StackObj { + public: + JNIHandleMark() { push_jni_handle_block(); } + ~JNIHandleMark() { pop_jni_handle_block(); } + + private: + static void push_jni_handle_block(); + static void pop_jni_handle_block(); +}; + #endif // SHARE_VM_JVMCI_JVMCI_COMPILER_TO_VM_HPP From ca341236caaab8908871bd174f4865e87033385e Mon Sep 17 00:00:00 2001 From: Jesper Wilhelmsson Date: Thu, 2 Mar 2017 17:46:59 +0100 Subject: [PATCH 11/11] 8176054: [BACKOUT][REDO] G1 Needs pre barrier on dereference of weak JNI handles Reviewed-by: kbarrett, mgerdin --- hotspot/make/test/JtregNative.gmk | 4 +- .../aarch64/vm/jniFastGetField_aarch64.cpp | 7 +- .../cpu/aarch64/vm/sharedRuntime_aarch64.cpp | 32 +-- .../templateInterpreterGenerator_aarch64.cpp | 27 +-- hotspot/src/cpu/arm/vm/interp_masm_arm.cpp | 181 ++++++++++++++- hotspot/src/cpu/arm/vm/interp_masm_arm.hpp | 23 +- .../src/cpu/arm/vm/jniFastGetField_arm.cpp | 10 +- hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp | 215 +----------------- hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp | 25 +- hotspot/src/cpu/arm/vm/sharedRuntime_arm.cpp | 20 +- .../vm/templateInterpreterGenerator_arm.cpp | 35 +-- hotspot/src/cpu/ppc/vm/frame_ppc.cpp | 9 +- hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp | 34 +-- hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp | 6 +- hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp | 13 +- .../vm/templateInterpreterGenerator_ppc.cpp | 11 +- .../src/cpu/s390/vm/macroAssembler_s390.cpp | 28 --- .../src/cpu/s390/vm/macroAssembler_s390.hpp | 2 - .../src/cpu/s390/vm/sharedRuntime_s390.cpp | 12 +- .../vm/templateInterpreterGenerator_s390.cpp | 11 +- .../cpu/sparc/vm/jniFastGetField_sparc.cpp | 5 +- .../src/cpu/sparc/vm/sharedRuntime_sparc.cpp | 33 +-- .../vm/templateInterpreterGenerator_sparc.cpp | 24 +- .../src/cpu/x86/vm/jniFastGetField_x86_32.cpp | 11 +- .../src/cpu/x86/vm/jniFastGetField_x86_64.cpp | 8 +- hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp | 39 +--- hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp | 5 +- .../src/cpu/x86/vm/sharedRuntime_x86_32.cpp | 13 +- .../src/cpu/x86/vm/sharedRuntime_x86_64.cpp | 13 +- .../vm/templateInterpreterGenerator_x86.cpp | 12 +- .../src/cpu/zero/vm/cppInterpreter_zero.cpp | 10 +- hotspot/src/share/vm/prims/jni.cpp | 7 +- hotspot/src/share/vm/prims/jvmtiEnv.cpp | 9 +- hotspot/src/share/vm/runtime/javaCalls.cpp | 118 ++++------ hotspot/src/share/vm/runtime/javaCalls.hpp | 95 ++------ hotspot/src/share/vm/runtime/jniHandles.cpp | 37 +-- hotspot/src/share/vm/runtime/jniHandles.hpp | 106 ++------- .../src/share/vm/shark/sharkNativeWrapper.cpp | 3 +- .../jni/CallWithJNIWeak/CallWithJNIWeak.java | 72 ------ .../jni/CallWithJNIWeak/libCallWithJNIWeak.c | 142 ------------ .../jni/ReturnJNIWeak/ReturnJNIWeak.java | 132 ----------- .../jni/ReturnJNIWeak/libReturnJNIWeak.c | 52 ----- 42 files changed, 432 insertions(+), 1219 deletions(-) delete mode 100644 hotspot/test/runtime/jni/CallWithJNIWeak/CallWithJNIWeak.java delete mode 100644 hotspot/test/runtime/jni/CallWithJNIWeak/libCallWithJNIWeak.c delete mode 100644 hotspot/test/runtime/jni/ReturnJNIWeak/ReturnJNIWeak.java delete mode 100644 hotspot/test/runtime/jni/ReturnJNIWeak/libReturnJNIWeak.c diff --git a/hotspot/make/test/JtregNative.gmk b/hotspot/make/test/JtregNative.gmk index 42eb76af57e..7223733367a 100644 --- a/hotspot/make/test/JtregNative.gmk +++ b/hotspot/make/test/JtregNative.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2016, 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 @@ -48,8 +48,6 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC := \ $(HOTSPOT_TOPDIR)/test/runtime/jni/PrivateInterfaceMethods \ $(HOTSPOT_TOPDIR)/test/runtime/jni/ToStringInInterfaceTest \ $(HOTSPOT_TOPDIR)/test/runtime/jni/CalleeSavedRegisters \ - $(HOTSPOT_TOPDIR)/test/runtime/jni/CallWithJNIWeak \ - $(HOTSPOT_TOPDIR)/test/runtime/jni/ReturnJNIWeak \ $(HOTSPOT_TOPDIR)/test/runtime/modules/getModuleJNI \ $(HOTSPOT_TOPDIR)/test/runtime/SameObject \ $(HOTSPOT_TOPDIR)/test/runtime/BoolReturn \ diff --git a/hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.cpp index a09c5230dc4..b2f21031f18 100644 --- a/hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -82,11 +82,6 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { __ eor(robj, robj, rcounter); // obj, since // robj ^ rcounter ^ rcounter == robj // robj is address dependent on rcounter. - - // If mask changes we need to ensure that the inverse is still encodable as an immediate - STATIC_ASSERT(JNIHandles::weak_tag_mask == 1); - __ andr(robj, robj, ~JNIHandles::weak_tag_mask); - __ ldr(robj, Address(robj, 0)); // *obj __ lsr(roffset, c_rarg2, 2); // offset diff --git a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp index a286102e7b1..01e0eeb1fc1 100644 --- a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -2052,31 +2052,13 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ reset_last_Java_frame(false); - // Unbox oop result, e.g. JNIHandles::resolve result. + // Unpack oop result if (ret_type == T_OBJECT || ret_type == T_ARRAY) { - Label done, not_weak; - __ cbz(r0, done); // Use NULL as-is. - STATIC_ASSERT(JNIHandles::weak_tag_mask == 1u); - __ tbz(r0, 0, not_weak); // Test for jweak tag. - // Resolve jweak. - __ ldr(r0, Address(r0, -JNIHandles::weak_tag_value)); - __ verify_oop(r0); -#if INCLUDE_ALL_GCS - if (UseG1GC) { - __ g1_write_barrier_pre(noreg /* obj */, - r0 /* pre_val */, - rthread /* thread */, - rscratch1 /* tmp */, - true /* tosca_live */, - true /* expand_call */); - } -#endif // INCLUDE_ALL_GCS - __ b(done); - __ bind(not_weak); - // Resolve (untagged) jobject. - __ ldr(r0, Address(r0, 0)); - __ verify_oop(r0); - __ bind(done); + Label L; + __ cbz(r0, L); + __ ldr(r0, Address(r0, 0)); + __ bind(L); + __ verify_oop(r0); } if (CheckJNICalls) { diff --git a/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp index 6f44292c55a..90dcd6c1a2c 100644 --- a/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1399,32 +1399,13 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // and result handler will pick it up { - Label no_oop, not_weak, store_result; + Label no_oop, store_result; __ adr(t, ExternalAddress(AbstractInterpreter::result_handler(T_OBJECT))); __ cmp(t, result_handler); __ br(Assembler::NE, no_oop); - // Unbox oop result, e.g. JNIHandles::resolve result. + // retrieve result __ pop(ltos); - __ cbz(r0, store_result); // Use NULL as-is. - STATIC_ASSERT(JNIHandles::weak_tag_mask == 1u); - __ tbz(r0, 0, not_weak); // Test for jweak tag. - // Resolve jweak. - __ ldr(r0, Address(r0, -JNIHandles::weak_tag_value)); -#if INCLUDE_ALL_GCS - if (UseG1GC) { - __ enter(); // Barrier may call runtime. - __ g1_write_barrier_pre(noreg /* obj */, - r0 /* pre_val */, - rthread /* thread */, - t /* tmp */, - true /* tosca_live */, - true /* expand_call */); - __ leave(); - } -#endif // INCLUDE_ALL_GCS - __ b(store_result); - __ bind(not_weak); - // Resolve (untagged) jobject. + __ cbz(r0, store_result); __ ldr(r0, Address(r0, 0)); __ bind(store_result); __ str(r0, Address(rfp, frame::interpreter_frame_oop_temp_offset*wordSize)); diff --git a/hotspot/src/cpu/arm/vm/interp_masm_arm.cpp b/hotspot/src/cpu/arm/vm/interp_masm_arm.cpp index 96df37c275e..2f41b102a85 100644 --- a/hotspot/src/cpu/arm/vm/interp_masm_arm.cpp +++ b/hotspot/src/cpu/arm/vm/interp_masm_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, 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 @@ -476,6 +476,185 @@ void InterpreterMacroAssembler::set_card(Register card_table_base, Address card_ } ////////////////////////////////////////////////////////////////////////////////// +#if INCLUDE_ALL_GCS + +// G1 pre-barrier. +// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR). +// If store_addr != noreg, then previous value is loaded from [store_addr]; +// in such case store_addr and new_val registers are preserved; +// otherwise pre_val register is preserved. +void InterpreterMacroAssembler::g1_write_barrier_pre(Register store_addr, + Register new_val, + Register pre_val, + Register tmp1, + Register tmp2) { + Label done; + Label runtime; + + if (store_addr != noreg) { + assert_different_registers(store_addr, new_val, pre_val, tmp1, tmp2, noreg); + } else { + assert (new_val == noreg, "should be"); + assert_different_registers(pre_val, tmp1, tmp2, noreg); + } + + Address in_progress(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_active())); + Address index(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_index())); + Address buffer(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_buf())); + + // Is marking active? + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "adjust this code"); + ldrb(tmp1, in_progress); + cbz(tmp1, done); + + // Do we need to load the previous value? + if (store_addr != noreg) { + load_heap_oop(pre_val, Address(store_addr, 0)); + } + + // Is the previous value null? + cbz(pre_val, done); + + // Can we store original value in the thread's buffer? + // Is index == 0? + // (The index field is typed as size_t.) + + ldr(tmp1, index); // tmp1 := *index_adr + ldr(tmp2, buffer); + + subs(tmp1, tmp1, wordSize); // tmp1 := tmp1 - wordSize + b(runtime, lt); // If negative, goto runtime + + str(tmp1, index); // *index_adr := tmp1 + + // Record the previous value + str(pre_val, Address(tmp2, tmp1)); + b(done); + + bind(runtime); + + // save the live input values +#ifdef AARCH64 + if (store_addr != noreg) { + raw_push(store_addr, new_val); + } else { + raw_push(pre_val, ZR); + } +#else + if (store_addr != noreg) { + // avoid raw_push to support any ordering of store_addr and new_val + push(RegisterSet(store_addr) | RegisterSet(new_val)); + } else { + push(pre_val); + } +#endif // AARCH64 + + if (pre_val != R0) { + mov(R0, pre_val); + } + mov(R1, Rthread); + + call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), R0, R1); + +#ifdef AARCH64 + if (store_addr != noreg) { + raw_pop(store_addr, new_val); + } else { + raw_pop(pre_val, ZR); + } +#else + if (store_addr != noreg) { + pop(RegisterSet(store_addr) | RegisterSet(new_val)); + } else { + pop(pre_val); + } +#endif // AARCH64 + + bind(done); +} + +// G1 post-barrier. +// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR). +void InterpreterMacroAssembler::g1_write_barrier_post(Register store_addr, + Register new_val, + Register tmp1, + Register tmp2, + Register tmp3) { + + Address queue_index(Rthread, in_bytes(JavaThread::dirty_card_queue_offset() + + DirtyCardQueue::byte_offset_of_index())); + Address buffer(Rthread, in_bytes(JavaThread::dirty_card_queue_offset() + + DirtyCardQueue::byte_offset_of_buf())); + + BarrierSet* bs = Universe::heap()->barrier_set(); + CardTableModRefBS* ct = (CardTableModRefBS*)bs; + Label done; + Label runtime; + + // Does store cross heap regions? + + eor(tmp1, store_addr, new_val); +#ifdef AARCH64 + logical_shift_right(tmp1, tmp1, HeapRegion::LogOfHRGrainBytes); + cbz(tmp1, done); +#else + movs(tmp1, AsmOperand(tmp1, lsr, HeapRegion::LogOfHRGrainBytes)); + b(done, eq); +#endif + + // crosses regions, storing NULL? + + cbz(new_val, done); + + // storing region crossing non-NULL, is card already dirty? + const Register card_addr = tmp1; + assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code"); + + mov_address(tmp2, (address)ct->byte_map_base, symbolic_Relocation::card_table_reference); + add(card_addr, tmp2, AsmOperand(store_addr, lsr, CardTableModRefBS::card_shift)); + + ldrb(tmp2, Address(card_addr)); + cmp(tmp2, (int)G1SATBCardTableModRefBS::g1_young_card_val()); + b(done, eq); + + membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp2); + + assert(CardTableModRefBS::dirty_card_val() == 0, "adjust this code"); + ldrb(tmp2, Address(card_addr)); + cbz(tmp2, done); + + // storing a region crossing, non-NULL oop, card is clean. + // dirty card and log. + + strb(zero_register(tmp2), Address(card_addr)); + + ldr(tmp2, queue_index); + ldr(tmp3, buffer); + + subs(tmp2, tmp2, wordSize); + b(runtime, lt); // go to runtime if now negative + + str(tmp2, queue_index); + + str(card_addr, Address(tmp3, tmp2)); + b(done); + + bind(runtime); + + if (card_addr != R0) { + mov(R0, card_addr); + } + mov(R1, Rthread); + call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), R0, R1); + + bind(done); +} + +#endif // INCLUDE_ALL_GCS +////////////////////////////////////////////////////////////////////////////////// // Java Expression Stack diff --git a/hotspot/src/cpu/arm/vm/interp_masm_arm.hpp b/hotspot/src/cpu/arm/vm/interp_masm_arm.hpp index 39e60226bf6..5c753753f95 100644 --- a/hotspot/src/cpu/arm/vm/interp_masm_arm.hpp +++ b/hotspot/src/cpu/arm/vm/interp_masm_arm.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, 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 @@ -146,6 +146,27 @@ class InterpreterMacroAssembler: public MacroAssembler { void set_card(Register card_table_base, Address card_table_addr, Register tmp); +#if INCLUDE_ALL_GCS + // G1 pre-barrier. + // Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR). + // If store_addr != noreg, then previous value is loaded from [store_addr]; + // in such case store_addr and new_val registers are preserved; + // otherwise pre_val register is preserved. + void g1_write_barrier_pre(Register store_addr, + Register new_val, + Register pre_val, + Register tmp1, + Register tmp2); + + // G1 post-barrier. + // Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR). + void g1_write_barrier_post(Register store_addr, + Register new_val, + Register tmp1, + Register tmp2, + Register tmp3); +#endif // INCLUDE_ALL_GCS + void pop_ptr(Register r); void pop_i(Register r = R0_tos); #ifdef AARCH64 diff --git a/hotspot/src/cpu/arm/vm/jniFastGetField_arm.cpp b/hotspot/src/cpu/arm/vm/jniFastGetField_arm.cpp index 65f929b1025..f9bd9f37970 100644 --- a/hotspot/src/cpu/arm/vm/jniFastGetField_arm.cpp +++ b/hotspot/src/cpu/arm/vm/jniFastGetField_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, 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 @@ -119,14 +119,6 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { __ ldr_s32(Rsafept_cnt, Address(Rsafepoint_counter_addr)); __ tbnz(Rsafept_cnt, 0, slow_case); -#ifdef AARCH64 - // If mask changes we need to ensure that the inverse is still encodable as an immediate - STATIC_ASSERT(JNIHandles::weak_tag_mask == 1); - __ andr(R1, R1, ~JNIHandles::weak_tag_mask); -#else - __ bic(R1, R1, JNIHandles::weak_tag_mask); -#endif - if (os::is_MP()) { // Address dependency restricts memory access ordering. It's cheaper than explicit LoadLoad barrier __ andr(Rtmp1, Rsafept_cnt, (unsigned)1); diff --git a/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp b/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp index 2eb2a551002..ada7d3fc485 100644 --- a/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp +++ b/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, 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 @@ -2211,219 +2211,6 @@ void MacroAssembler::biased_locking_exit(Register obj_reg, Register tmp_reg, Lab b(done, eq); } - -void MacroAssembler::resolve_jobject(Register value, - Register tmp1, - Register tmp2) { - assert_different_registers(value, tmp1, tmp2); - Label done, not_weak; - cbz(value, done); // Use NULL as-is. - STATIC_ASSERT(JNIHandles::weak_tag_mask == 1u); - tbz(value, 0, not_weak); // Test for jweak tag. - // Resolve jweak. - ldr(value, Address(value, -JNIHandles::weak_tag_value)); - verify_oop(value); -#if INCLUDE_ALL_GCS - if (UseG1GC) { - g1_write_barrier_pre(noreg, // store_addr - noreg, // new_val - value, // pre_val - tmp1, // tmp1 - tmp2); // tmp2 - } -#endif // INCLUDE_ALL_GCS - b(done); - bind(not_weak); - // Resolve (untagged) jobject. - ldr(value, Address(value)); - verify_oop(value); - bind(done); -} - - -////////////////////////////////////////////////////////////////////////////////// - -#if INCLUDE_ALL_GCS - -// G1 pre-barrier. -// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR). -// If store_addr != noreg, then previous value is loaded from [store_addr]; -// in such case store_addr and new_val registers are preserved; -// otherwise pre_val register is preserved. -void MacroAssembler::g1_write_barrier_pre(Register store_addr, - Register new_val, - Register pre_val, - Register tmp1, - Register tmp2) { - Label done; - Label runtime; - - if (store_addr != noreg) { - assert_different_registers(store_addr, new_val, pre_val, tmp1, tmp2, noreg); - } else { - assert (new_val == noreg, "should be"); - assert_different_registers(pre_val, tmp1, tmp2, noreg); - } - - Address in_progress(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + - SATBMarkQueue::byte_offset_of_active())); - Address index(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + - SATBMarkQueue::byte_offset_of_index())); - Address buffer(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + - SATBMarkQueue::byte_offset_of_buf())); - - // Is marking active? - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "adjust this code"); - ldrb(tmp1, in_progress); - cbz(tmp1, done); - - // Do we need to load the previous value? - if (store_addr != noreg) { - load_heap_oop(pre_val, Address(store_addr, 0)); - } - - // Is the previous value null? - cbz(pre_val, done); - - // Can we store original value in the thread's buffer? - // Is index == 0? - // (The index field is typed as size_t.) - - ldr(tmp1, index); // tmp1 := *index_adr - ldr(tmp2, buffer); - - subs(tmp1, tmp1, wordSize); // tmp1 := tmp1 - wordSize - b(runtime, lt); // If negative, goto runtime - - str(tmp1, index); // *index_adr := tmp1 - - // Record the previous value - str(pre_val, Address(tmp2, tmp1)); - b(done); - - bind(runtime); - - // save the live input values -#ifdef AARCH64 - if (store_addr != noreg) { - raw_push(store_addr, new_val); - } else { - raw_push(pre_val, ZR); - } -#else - if (store_addr != noreg) { - // avoid raw_push to support any ordering of store_addr and new_val - push(RegisterSet(store_addr) | RegisterSet(new_val)); - } else { - push(pre_val); - } -#endif // AARCH64 - - if (pre_val != R0) { - mov(R0, pre_val); - } - mov(R1, Rthread); - - call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), R0, R1); - -#ifdef AARCH64 - if (store_addr != noreg) { - raw_pop(store_addr, new_val); - } else { - raw_pop(pre_val, ZR); - } -#else - if (store_addr != noreg) { - pop(RegisterSet(store_addr) | RegisterSet(new_val)); - } else { - pop(pre_val); - } -#endif // AARCH64 - - bind(done); -} - -// G1 post-barrier. -// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR). -void MacroAssembler::g1_write_barrier_post(Register store_addr, - Register new_val, - Register tmp1, - Register tmp2, - Register tmp3) { - - Address queue_index(Rthread, in_bytes(JavaThread::dirty_card_queue_offset() + - DirtyCardQueue::byte_offset_of_index())); - Address buffer(Rthread, in_bytes(JavaThread::dirty_card_queue_offset() + - DirtyCardQueue::byte_offset_of_buf())); - - BarrierSet* bs = Universe::heap()->barrier_set(); - CardTableModRefBS* ct = (CardTableModRefBS*)bs; - Label done; - Label runtime; - - // Does store cross heap regions? - - eor(tmp1, store_addr, new_val); -#ifdef AARCH64 - logical_shift_right(tmp1, tmp1, HeapRegion::LogOfHRGrainBytes); - cbz(tmp1, done); -#else - movs(tmp1, AsmOperand(tmp1, lsr, HeapRegion::LogOfHRGrainBytes)); - b(done, eq); -#endif - - // crosses regions, storing NULL? - - cbz(new_val, done); - - // storing region crossing non-NULL, is card already dirty? - const Register card_addr = tmp1; - assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code"); - - mov_address(tmp2, (address)ct->byte_map_base, symbolic_Relocation::card_table_reference); - add(card_addr, tmp2, AsmOperand(store_addr, lsr, CardTableModRefBS::card_shift)); - - ldrb(tmp2, Address(card_addr)); - cmp(tmp2, (int)G1SATBCardTableModRefBS::g1_young_card_val()); - b(done, eq); - - membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp2); - - assert(CardTableModRefBS::dirty_card_val() == 0, "adjust this code"); - ldrb(tmp2, Address(card_addr)); - cbz(tmp2, done); - - // storing a region crossing, non-NULL oop, card is clean. - // dirty card and log. - - strb(zero_register(tmp2), Address(card_addr)); - - ldr(tmp2, queue_index); - ldr(tmp3, buffer); - - subs(tmp2, tmp2, wordSize); - b(runtime, lt); // go to runtime if now negative - - str(tmp2, queue_index); - - str(card_addr, Address(tmp3, tmp2)); - b(done); - - bind(runtime); - - if (card_addr != R0) { - mov(R0, card_addr); - } - mov(R1, Rthread); - call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), R0, R1); - - bind(done); -} - -#endif // INCLUDE_ALL_GCS - -////////////////////////////////////////////////////////////////////////////////// - #ifdef AARCH64 void MacroAssembler::load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed) { diff --git a/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp b/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp index e6f73353cb9..770bba6c8a1 100644 --- a/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp +++ b/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, 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 @@ -402,29 +402,6 @@ public: void biased_locking_enter_with_cas(Register obj_reg, Register old_mark_reg, Register new_mark_reg, Register tmp, Label& slow_case, int* counter_addr); - void resolve_jobject(Register value, Register tmp1, Register tmp2); - -#if INCLUDE_ALL_GCS - // G1 pre-barrier. - // Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR). - // If store_addr != noreg, then previous value is loaded from [store_addr]; - // in such case store_addr and new_val registers are preserved; - // otherwise pre_val register is preserved. - void g1_write_barrier_pre(Register store_addr, - Register new_val, - Register pre_val, - Register tmp1, - Register tmp2); - - // G1 post-barrier. - // Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR). - void g1_write_barrier_post(Register store_addr, - Register new_val, - Register tmp1, - Register tmp2, - Register tmp3); -#endif // INCLUDE_ALL_GCS - #ifndef AARCH64 void nop() { mov(R0, R0); diff --git a/hotspot/src/cpu/arm/vm/sharedRuntime_arm.cpp b/hotspot/src/cpu/arm/vm/sharedRuntime_arm.cpp index 48f096473c3..9b37b4fe6dc 100644 --- a/hotspot/src/cpu/arm/vm/sharedRuntime_arm.cpp +++ b/hotspot/src/cpu/arm/vm/sharedRuntime_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, 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 @@ -1732,7 +1732,14 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, case T_FLOAT : // fall through case T_DOUBLE : /* nothing to do */ break; case T_OBJECT : // fall through - case T_ARRAY : break; // See JNIHandles::resolve below + case T_ARRAY : { + Label L; + __ cbz(R0, L); + __ ldr(R0, Address(R0)); + __ verify_oop(R0); + __ bind(L); + break; + } default: ShouldNotReachHere(); } @@ -1741,14 +1748,13 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, if (CheckJNICalls) { __ str(__ zero_register(Rtemp), Address(Rthread, JavaThread::pending_jni_exception_check_fn_offset())); } -#endif // AARCH64 - // Unbox oop result, e.g. JNIHandles::resolve value in R0. + // Unhandle the result if (ret_type == T_OBJECT || ret_type == T_ARRAY) { - __ resolve_jobject(R0, // value - Rtemp, // tmp1 - R1_tmp); // tmp2 + __ cmp(R0, 0); + __ ldr(R0, Address(R0), ne); } +#endif // AARCH64 // Any exception pending? __ ldr(Rtemp, Address(Rthread, Thread::pending_exception_offset())); diff --git a/hotspot/src/cpu/arm/vm/templateInterpreterGenerator_arm.cpp b/hotspot/src/cpu/arm/vm/templateInterpreterGenerator_arm.cpp index 7fda747ad48..743510e09a7 100644 --- a/hotspot/src/cpu/arm/vm/templateInterpreterGenerator_arm.cpp +++ b/hotspot/src/cpu/arm/vm/templateInterpreterGenerator_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, 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 @@ -1240,25 +1240,28 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ str(__ zero_register(Rtemp), Address(Rthread, JavaThread::pending_jni_exception_check_fn_offset())); } - // Unbox oop result, e.g. JNIHandles::resolve result if it's an oop. - { - Label Lnot_oop; + // Unbox if the result is non-zero object #ifdef AARCH64 + { + Label L, Lnull; __ mov_slow(Rtemp, AbstractInterpreter::result_handler(T_OBJECT)); __ cmp(Rresult_handler, Rtemp); - __ b(Lnot_oop, ne); -#else // !AARCH64 - // For ARM32, Rresult_handler is -1 for oop result, 0 otherwise. - __ cbz(Rresult_handler, Lnot_oop); -#endif // !AARCH64 - Register value = AARCH64_ONLY(Rsaved_result) NOT_AARCH64(Rsaved_result_lo); - __ resolve_jobject(value, // value - Rtemp, // tmp1 - R1_tmp); // tmp2 - // Store resolved result in frame for GC visibility. - __ str(value, Address(FP, frame::interpreter_frame_oop_temp_offset * wordSize)); - __ bind(Lnot_oop); + __ b(L, ne); + __ cbz(Rsaved_result, Lnull); + __ ldr(Rsaved_result, Address(Rsaved_result)); + __ bind(Lnull); + // Store oop on the stack for GC + __ str(Rsaved_result, Address(FP, frame::interpreter_frame_oop_temp_offset * wordSize)); + __ bind(L); } +#else + __ tst(Rsaved_result_lo, Rresult_handler); + __ ldr(Rsaved_result_lo, Address(Rsaved_result_lo), ne); + + // Store oop on the stack for GC + __ cmp(Rresult_handler, 0); + __ str(Rsaved_result_lo, Address(FP, frame::interpreter_frame_oop_temp_offset * wordSize), ne); +#endif // AARCH64 #ifdef AARCH64 // Restore SP (drop native parameters area), to keep SP in sync with extended_sp in frame diff --git a/hotspot/src/cpu/ppc/vm/frame_ppc.cpp b/hotspot/src/cpu/ppc/vm/frame_ppc.cpp index b6a538681f6..131a931c2c1 100644 --- a/hotspot/src/cpu/ppc/vm/frame_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/frame_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2017 SAP SE. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015 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 @@ -171,7 +171,10 @@ BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) switch (method->result_type()) { case T_OBJECT: case T_ARRAY: { - *oop_result = JNIHandles::resolve(*(jobject*)lresult); + 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; break; } // We use std/stfd to store the values. diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp index 6eb27c78f17..a5d5613a414 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2017 SAP SE. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016 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 @@ -3033,34 +3033,6 @@ 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. @@ -3122,7 +3094,7 @@ void MacroAssembler::g1_write_barrier_pre(Register Robj, RegisterOrConstant offs bind(runtime); - // May need to preserve LR. Also needed if current frame is not compatible with C calling convention. + // VM call need frame to access(write) O register. if (needs_frame) { save_LR_CR(Rtmp1); push_frame_reg_args(0, Rtmp2); diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp index 0b1b2a0befa..11b966a82c9 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2017 SAP SE. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016 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 @@ -649,8 +649,6 @@ 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/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp index dc36aa77da2..784595f11be 100644 --- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2017 SAP SE. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016 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 @@ -2477,11 +2477,16 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ reset_last_Java_frame(); - // Unbox oop result, e.g. JNIHandles::resolve value. + // Unpack oop result. // -------------------------------------------------------------------------- if (ret_type == T_OBJECT || ret_type == T_ARRAY) { - __ resolve_jobject(R3_RET, r_temp_1, r_temp_2, /* needs_frame */ false); // kills R31 + 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); } if (CheckJNICalls) { diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp index ab87c204018..56810938a53 100644 --- a/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2015, 2017 SAP SE. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016 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 @@ -401,8 +401,11 @@ address TemplateInterpreterGenerator::generate_result_handler_for(BasicType type case T_LONG: break; case T_OBJECT: - // JNIHandles::resolve result. - __ resolve_jobject(R3_RET, R11_scratch1, R12_scratch2, /* needs_frame */ true); // kills R31 + // unbox result if not null + __ cmpdi(CCR0, R3_RET, 0); + __ beq(CCR0, done); + __ ld(R3_RET, 0, R3_RET); + __ verify_oop(R3_RET); break; case T_FLOAT: break; diff --git a/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp b/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp index d5776117436..0f78e5a6250 100644 --- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp +++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp @@ -3439,34 +3439,6 @@ void MacroAssembler::card_write_barrier_post(Register store_addr, Register tmp) z_mvi(0, store_addr, 0); // Store byte 0. } -void MacroAssembler::resolve_jobject(Register value, Register tmp1, Register tmp2) { - NearLabel Ldone; - z_ltgr(tmp1, value); - z_bre(Ldone); // Use NULL result as-is. - - z_nill(value, ~JNIHandles::weak_tag_mask); - z_lg(value, 0, value); // Resolve (untagged) jobject. - -#if INCLUDE_ALL_GCS - if (UseG1GC) { - NearLabel Lnot_weak; - z_tmll(tmp1, JNIHandles::weak_tag_mask); // Test for jweak tag. - z_braz(Lnot_weak); - verify_oop(value); - g1_write_barrier_pre(noreg /* obj */, - noreg /* offset */, - value /* pre_val */, - noreg /* val */, - tmp1 /* tmp1 */, - tmp2 /* tmp2 */, - true /* pre_val_needed */); - bind(Lnot_weak); - } -#endif // INCLUDE_ALL_GCS - verify_oop(value); - bind(Ldone); -} - #if INCLUDE_ALL_GCS //------------------------------------------------------ diff --git a/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp b/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp index 2b4002a3bf4..588bde6207e 100644 --- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp +++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp @@ -726,8 +726,6 @@ class MacroAssembler: public Assembler { // Write to card table for modification at store_addr - register is destroyed afterwards. void card_write_barrier_post(Register store_addr, Register tmp); - void resolve_jobject(Register value, Register tmp1, Register tmp2); - #if INCLUDE_ALL_GCS // General G1 pre-barrier generator. // Purpose: record the previous value if it is not null. diff --git a/hotspot/src/cpu/s390/vm/sharedRuntime_s390.cpp b/hotspot/src/cpu/s390/vm/sharedRuntime_s390.cpp index 89c3ae4032a..ea498e3399c 100644 --- a/hotspot/src/cpu/s390/vm/sharedRuntime_s390.cpp +++ b/hotspot/src/cpu/s390/vm/sharedRuntime_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2017 SAP SE. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016 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 @@ -2272,9 +2272,13 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ reset_last_Java_frame(); - // Unpack oop result, e.g. JNIHandles::resolve result. + // Unpack oop result if (ret_type == T_OBJECT || ret_type == T_ARRAY) { - __ resolve_jobject(Z_RET, /* tmp1 */ Z_R13, /* tmp2 */ Z_R7); + NearLabel L; + __ compare64_and_branch(Z_RET, (RegisterOrConstant)0L, Assembler::bcondEqual, L); + __ z_lg(Z_RET, 0, Z_RET); + __ bind(L); + __ verify_oop(Z_RET); } if (CheckJNICalls) { diff --git a/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp b/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp index 20a9a3e9571..2084f36006f 100644 --- a/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp +++ b/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2017 SAP SE. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016 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 @@ -1695,11 +1695,14 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // from the jni handle to z_ijava_state.oop_temp. This is // necessary, because we reset the jni handle block below. // NOTE: frame::interpreter_frame_result() depends on this, too. - { NearLabel no_oop_result; + { NearLabel no_oop_result, store_oop_result; __ load_absolute_address(Z_R1, AbstractInterpreter::result_handler(T_OBJECT)); __ compareU64_and_branch(Z_R1, Rresult_handler, Assembler::bcondNotEqual, no_oop_result); - __ resolve_jobject(Rlresult, /* tmp1 */ Rmethod, /* tmp2 */ Z_R1); + __ compareU64_and_branch(Rlresult, (intptr_t)0L, Assembler::bcondEqual, store_oop_result); + __ z_lg(Rlresult, 0, Rlresult); // unbox + __ bind(store_oop_result); __ z_stg(Rlresult, oop_tmp_offset, Z_fp); + __ verify_oop(Rlresult); __ bind(no_oop_result); } diff --git a/hotspot/src/cpu/sparc/vm/jniFastGetField_sparc.cpp b/hotspot/src/cpu/sparc/vm/jniFastGetField_sparc.cpp index ff9fcd69472..6d3f05a2aab 100644 --- a/hotspot/src/cpu/sparc/vm/jniFastGetField_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/jniFastGetField_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2010, 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,7 +68,6 @@ 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"); @@ -148,7 +147,6 @@ 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); @@ -221,7 +219,6 @@ 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/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp index 613e662d65c..7b4dcf193d3 100644 --- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, 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 @@ -2754,30 +2754,15 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ verify_thread(); // G2_thread must be correct __ reset_last_Java_frame(); - // Unbox oop result, e.g. JNIHandles::resolve value in I0. + // Unpack oop result if (ret_type == T_OBJECT || ret_type == T_ARRAY) { - 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); + 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); } if (CheckJNICalls) { diff --git a/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp index fd4e3ffd149..b677a1dd662 100644 --- a/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -1516,23 +1516,11 @@ address TemplateInterpreterGenerator::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); - // 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 + __ 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); + __ 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/hotspot/src/cpu/x86/vm/jniFastGetField_x86_32.cpp b/hotspot/src/cpu/x86/vm/jniFastGetField_x86_32.cpp index 719bf8ce560..a45e0eb9aa3 100644 --- a/hotspot/src/cpu/x86/vm/jniFastGetField_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/jniFastGetField_x86_32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2010, 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 @@ -85,9 +85,6 @@ address JNI_FastGetField::generate_fast_get_int_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 @@ -205,9 +202,6 @@ address JNI_FastGetField::generate_fast_get_long_field() { __ 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 @@ -297,9 +291,6 @@ 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/hotspot/src/cpu/x86/vm/jniFastGetField_x86_64.cpp b/hotspot/src/cpu/x86/vm/jniFastGetField_x86_64.cpp index f18aa684266..7286fd124b8 100644 --- a/hotspot/src/cpu/x86/vm/jniFastGetField_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/jniFastGetField_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2010, 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 @@ -80,9 +80,6 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { // robj ^ rcounter ^ rcounter == robj // robj is data dependent on rcounter. } - - __ clear_jweak_tag(robj); - __ movptr(robj, Address(robj, 0)); // *obj __ mov (roffset, c_rarg2); __ shrptr(roffset, 2); // offset @@ -181,9 +178,6 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) { // robj ^ rcounter ^ rcounter == robj // robj is data dependent on rcounter. } - - __ clear_jweak_tag(robj); - __ movptr(robj, Address(robj, 0)); // *obj __ mov (roffset, c_rarg2); __ shrptr(roffset, 2); // offset diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index f2c8393fb12..b6d32631582 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -5129,43 +5129,6 @@ 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(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/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp index 39b2e1a5305..a3e81e58dc5 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -297,9 +297,6 @@ 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/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp index 47b9fe5c627..ed317550e08 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, 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 @@ -2226,11 +2226,14 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ reset_last_Java_frame(thread, false); - // Unbox oop result, e.g. JNIHandles::resolve value. + // Unpack oop result if (ret_type == T_OBJECT || ret_type == T_ARRAY) { - __ resolve_jobject(rax /* value */, - thread /* thread */, - rcx /* tmp */); + Label L; + __ cmpptr(rax, (int32_t)NULL_WORD); + __ jcc(Assembler::equal, L); + __ movptr(rax, Address(rax, 0)); + __ bind(L); + __ verify_oop(rax); } if (CheckJNICalls) { diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp index d81e965d05d..4587b8caba6 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, 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 @@ -2579,11 +2579,14 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ reset_last_Java_frame(false); - // Unbox oop result, e.g. JNIHandles::resolve value. + // Unpack oop result if (ret_type == T_OBJECT || ret_type == T_ARRAY) { - __ resolve_jobject(rax /* value */, - r15_thread /* thread */, - rcx /* tmp */); + Label L; + __ testptr(rax, rax); + __ jcc(Assembler::zero, L); + __ movptr(rax, Address(rax, 0)); + __ bind(L); + __ verify_oop(rax); } if (CheckJNICalls) { diff --git a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp index 9c02d44cdb8..eb5661bee00 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, 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 @@ -1193,16 +1193,16 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // and result handler will pick it up { - Label no_oop, not_weak, store_result; + Label no_oop, store_result; __ 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); - // Unbox oop result, e.g. JNIHandles::resolve value. - __ resolve_jobject(rax /* value */, - thread /* thread */, - t /* tmp */); + __ testptr(rax, rax); + __ jcc(Assembler::zero, store_result); + __ movptr(rax, Address(rax, 0)); + __ bind(store_result); __ 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/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp index f7c51092c82..1fcf7d9984b 100644 --- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp +++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, 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. * @@ -406,12 +406,10 @@ 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] == 0) { + if (result[0]) + istate->set_oop_temp(*(oop *) result[0]); + else istate->set_oop_temp(NULL); - } else { - jobject handle = reinterpret_cast(result[0]); - istate->set_oop_temp(JNIHandles::resolve(handle)); - } } // Reset handle block diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index acda443267a..f519e5e2788 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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. * @@ -935,7 +935,8 @@ 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() { _arguments->push_jobject(va_arg(_ap, jobject)); } + inline void get_object() { jobject l = va_arg(_ap, jobject); + _arguments->push_oop(Handle((oop *)l, false)); } inline void set_ap(va_list rap) { va_copy(_ap, rap); @@ -1024,7 +1025,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_jobject((_ap++)->l); } + inline void get_object() { _arguments->push_oop(Handle((oop *)(_ap++)->l, false)); } inline void set_ap(const jvalue *rap) { _ap = rap; } diff --git a/hotspot/src/share/vm/prims/jvmtiEnv.cpp b/hotspot/src/share/vm/prims/jvmtiEnv.cpp index 57292a2c8bc..f9dc315a552 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp +++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, 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 @@ -1796,13 +1796,6 @@ 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/hotspot/src/share/vm/runtime/javaCalls.cpp b/hotspot/src/share/vm/runtime/javaCalls.cpp index d91a32a9f08..5874699a1fc 100644 --- a/hotspot/src/share/vm/runtime/javaCalls.cpp +++ b/hotspot/src/share/vm/runtime/javaCalls.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -328,9 +328,9 @@ void JavaCalls::call_helper(JavaValue* result, const methodHandle& method, JavaC // Verify the arguments if (CheckJNICalls) { - args->verify(method, result->get_type()); + args->verify(method, result->get_type(), thread); } - else debug_only(args->verify(method, result->get_type())); + else debug_only(args->verify(method, result->get_type(), thread)); #if INCLUDE_JVMCI } #else @@ -442,43 +442,12 @@ void JavaCalls::call_helper(JavaValue* result, const methodHandle& method, JavaC //-------------------------------------------------------------------------------------- // 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 %u", state); - return state != JavaCallArguments::value_state_primitive; -} - -inline oop resolve_indirect_oop(intptr_t value, uint state) { - switch (state) { - case JavaCallArguments::value_state_handle: - { - oop* ptr = reinterpret_cast(value); - return Handle::raw_resolve(ptr); - } - - case JavaCallArguments::value_state_jobject: - { - jobject obj = reinterpret_cast(value); - return JNIHandles::resolve(obj); - } - - default: - ShouldNotReachHere(); - return NULL; - } -} - intptr_t* JavaCallArguments::parameters() { // First convert all handles to oops for(int i = 0; i < _size; i++) { - uint state = _value_state[i]; - assert(state != value_state_oop, "Multiple handle conversions"); - if (is_value_state_indirect_oop(state)) { - oop obj = resolve_indirect_oop(_value[i], state); - _value[i] = cast_from_oop(obj); - _value_state[i] = value_state_oop; + if (_is_oop[i]) { + // Handle conversion + _value[i] = cast_from_oop(Handle::raw_resolve((oop *)_value[i])); } } // Return argument vector @@ -488,42 +457,30 @@ intptr_t* JavaCallArguments::parameters() { class SignatureChekker : public SignatureIterator { private: - int _pos; + bool *_is_oop; + int _pos; BasicType _return_type; - u_char* _value_state; - intptr_t* _value; + intptr_t* _value; + Thread* _thread; public: bool _is_return; - 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) - { + 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; + if (!is_static) { check_value(true); // Receiver must be an oop } } void check_value(bool type) { - uint state = _value_state[_pos++]; - if (type) { - guarantee(is_value_state_indirect_oop(state), - "signature does not match pushed arguments: %u at %d", - state, _pos - 1); - } else { - guarantee(state == JavaCallArguments::value_state_primitive, - "signature does not match pushed arguments: %u at %d", - state, _pos - 1); - } + guarantee(_is_oop[_pos++] == type, "signature does not match pushed arguments"); } void check_doing_return(bool state) { _is_return = state; } @@ -558,20 +515,24 @@ class SignatureChekker : public SignatureIterator { return; } - 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 %d: " PTR_FORMAT, _pos, v); - // Verify the pointee. - oop vv = resolve_indirect_oop(v, _value_state[_pos]); - guarantee(vv->is_oop_or_null(true), - "Bad JNI oop argument %d: " PTR_FORMAT " -> " PTR_FORMAT, - _pos, v, p2i(vv)); + // 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"); } - check_value(true); // Verify value state. + check_value(true); } void do_bool() { check_int(T_BOOLEAN); } @@ -588,7 +549,8 @@ class SignatureChekker : public SignatureIterator { }; -void JavaCallArguments::verify(const methodHandle& method, BasicType return_type) { +void JavaCallArguments::verify(const methodHandle& method, BasicType return_type, + Thread *thread) { guarantee(method->size_of_parameters() == size_of_parameters(), "wrong no. of arguments pushed"); // Treat T_OBJECT and T_ARRAY as the same @@ -597,11 +559,7 @@ void JavaCallArguments::verify(const methodHandle& method, BasicType return_type // Check that oop information is correct Symbol* signature = method->signature(); - SignatureChekker sc(signature, - return_type, - method->is_static(), - _value_state, - _value); + SignatureChekker sc(signature, return_type, method->is_static(),_is_oop, _value, thread); sc.iterate_parameters(); sc.check_doing_return(true); sc.iterate_returntype(); diff --git a/hotspot/src/share/vm/runtime/javaCalls.hpp b/hotspot/src/share/vm/runtime/javaCalls.hpp index e77abf7d36b..efe1f8b9813 100644 --- a/hotspot/src/share/vm/runtime/javaCalls.hpp +++ b/hotspot/src/share/vm/runtime/javaCalls.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -80,11 +80,11 @@ class JavaCallArguments : public StackObj { _default_size = 8 // Must be at least # of arguments in JavaCalls methods }; - intptr_t _value_buffer [_default_size + 1]; - u_char _value_state_buffer[_default_size + 1]; + intptr_t _value_buffer [_default_size + 1]; + bool _is_oop_buffer[_default_size + 1]; intptr_t* _value; - u_char* _value_state; + bool* _is_oop; int _size; int _max_size; bool _start_at_zero; // Support late setting of receiver @@ -92,8 +92,8 @@ class JavaCallArguments : public StackObj { void initialize() { // Starts at first element to support set_receiver. - _value = &_value_buffer[1]; - _value_state = &_value_state_buffer[1]; + _value = &_value_buffer[1]; + _is_oop = &_is_oop_buffer[1]; _max_size = _default_size; _size = 0; @@ -101,23 +101,6 @@ class JavaCallArguments : public StackObj { JVMCI_ONLY(_alternative_target = NULL;) } - // Helper for push_oop and the like. The value argument is a - // "handle" that refers to an oop. We record the address of the - // handle rather than the designated oop. The handle is later - // resolved to the oop by parameters(). This delays the exposure of - // naked oops until it is GC-safe. - template - inline int push_oop_impl(T handle, int size) { - // JNITypes::put_obj expects an oop value, so we play fast and - // loose with the type system. The cast from handle type to oop - // *must* use a C-style cast. In a product build it performs a - // reinterpret_cast. In a debug build (more accurately, in a - // CHECK_UNHANDLED_OOPS build) it performs a static_cast, invoking - // the debug-only oop class's conversion from void* constructor. - JNITypes::put_obj((oop)handle, _value, size); // Updates size. - return size; // Return the updated size. - } - public: JavaCallArguments() { initialize(); } @@ -128,12 +111,11 @@ class JavaCallArguments : public StackObj { JavaCallArguments(int max_size) { if (max_size > _default_size) { - _value = NEW_RESOURCE_ARRAY(intptr_t, max_size + 1); - _value_state = NEW_RESOURCE_ARRAY(u_char, max_size + 1); + _value = NEW_RESOURCE_ARRAY(intptr_t, max_size + 1); + _is_oop = NEW_RESOURCE_ARRAY(bool, max_size + 1); - // Reserve room for potential receiver in value and state - _value++; - _value_state++; + // Reserve room for potential receiver in value and is_oop + _value++; _is_oop++; _max_size = max_size; _size = 0; @@ -154,52 +136,25 @@ class JavaCallArguments : public StackObj { } #endif - // 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_oop(Handle h) { _is_oop[_size] = true; + JNITypes::put_obj((oop)h.raw_value(), _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_int(int i) { _is_oop[_size] = false; + JNITypes::put_int(i, _value, _size); } - inline void push_jobject(jobject h) { - _value_state[_size] = value_state_jobject; - _size = push_oop_impl(h, _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_int(int i) { - _value_state[_size] = value_state_primitive; - JNITypes::put_int(i, _value, _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_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); - } + inline void push_float(float f) { _is_oop[_size] = false; + JNITypes::put_float(f, _value, _size); } // receiver Handle receiver() { assert(_size > 0, "must at least be one argument"); - assert(_value_state[0] == value_state_handle, - "first argument must be an oop"); + assert(_is_oop[0], "first argument must be an oop"); assert(_value[0] != 0, "receiver must be not-null"); return Handle((oop*)_value[0], false); } @@ -207,11 +162,11 @@ class JavaCallArguments : public StackObj { void set_receiver(Handle h) { assert(_start_at_zero == false, "can only be called once"); _start_at_zero = true; - _value_state--; + _is_oop--; _value--; _size++; - _value_state[0] = value_state_handle; - push_oop_impl(h.raw_value(), 0); + _is_oop[0] = true; + _value[0] = (intptr_t)h.raw_value(); } // Converts all Handles to oops, and returns a reference to parameter vector @@ -219,7 +174,7 @@ class JavaCallArguments : public StackObj { int size_of_parameters() const { return _size; } // Verify that pushed arguments fits a given method - void verify(const methodHandle& method, BasicType return_type); + void verify(const methodHandle& method, BasicType return_type, Thread *thread); }; // All calls to Java have to go via JavaCalls. Sets up the stack frame diff --git a/hotspot/src/share/vm/runtime/jniHandles.cpp b/hotspot/src/share/vm/runtime/jniHandles.cpp index f4aae3c20bf..679ade0eaca 100644 --- a/hotspot/src/share/vm/runtime/jniHandles.cpp +++ b/hotspot/src/share/vm/runtime/jniHandles.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, 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 @@ -31,9 +31,6 @@ #include "runtime/jniHandles.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/thread.inline.hpp" -#if INCLUDE_ALL_GCS -#include "gc/g1/g1SATBCardTableModRefBS.hpp" -#endif JNIHandleBlock* JNIHandles::_global_handles = NULL; JNIHandleBlock* JNIHandles::_weak_global_handles = NULL; @@ -95,48 +92,28 @@ jobject JNIHandles::make_weak_global(Handle obj) { 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()); - } - // Add weak tag. - assert(is_ptr_aligned(res, weak_tag_alignment), "invariant"); - char* tptr = reinterpret_cast(res) + weak_tag_value; - res = reinterpret_cast(tptr); + MutexLocker ml(JNIGlobalHandle_lock); + assert(Universe::heap()->is_in_reserved(obj()), "sanity check"); + res = _weak_global_handles->allocate_handle(obj()); } else { CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops()); } return res; } -template -oop JNIHandles::resolve_jweak(jweak handle) { - assert(is_jweak(handle), "precondition"); - oop result = jweak_ref(handle); - result = guard_value(result); -#if INCLUDE_ALL_GCS - if (result != NULL && UseG1GC) { - G1SATBCardTableModRefBS::enqueue(result); - } -#endif // INCLUDE_ALL_GCS - return result; -} - -template oop JNIHandles::resolve_jweak(jweak); -template oop JNIHandles::resolve_jweak(jweak); void JNIHandles::destroy_global(jobject handle) { if (handle != NULL) { assert(is_global_handle(handle), "Invalid delete of global JNI handle"); - jobject_ref(handle) = deleted_handle(); + *((oop*)handle) = deleted_handle(); // Mark the handle as deleted, allocate will reuse it } } void JNIHandles::destroy_weak_global(jobject handle) { if (handle != NULL) { - jweak_ref(handle) = deleted_handle(); + 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 } } diff --git a/hotspot/src/share/vm/runtime/jniHandles.hpp b/hotspot/src/share/vm/runtime/jniHandles.hpp index 13e0e155740..ce37d940d7c 100644 --- a/hotspot/src/share/vm/runtime/jniHandles.hpp +++ b/hotspot/src/share/vm/runtime/jniHandles.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2014, 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,28 +40,7 @@ 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 inline static oop guard_value(oop value); - template inline static oop resolve_impl(jobject handle); - template static oop resolve_jweak(jweak handle); - public: - // Low tag bit in jobject used to distinguish a jweak. jweak is - // type equivalent to jobject, but there are places where we need to - // be able to distinguish jweak values from other jobjects, and - // is_weak_global_handle is unsuitable for performance reasons. To - // provide such a test we add weak_tag_value to the (aligned) byte - // address designated by the jobject to produce the corresponding - // jweak. Accessing the value of a jobject must account for it - // being a possibly offset jweak. - static const uintptr_t weak_tag_size = 1; - static const uintptr_t weak_tag_alignment = (1u << weak_tag_size); - static const uintptr_t weak_tag_mask = weak_tag_alignment - 1; - static const int weak_tag_value = 1; - // Resolve handle into oop inline static oop resolve(jobject handle); // Resolve externally provided handle into oop with some guards @@ -197,85 +176,36 @@ class JNIHandleBlock : public CHeapObj { #endif }; -inline bool JNIHandles::is_jweak(jobject handle) { - STATIC_ASSERT(weak_tag_size == 1); - STATIC_ASSERT(weak_tag_value == 1); - return (reinterpret_cast(handle) & weak_tag_mask) != 0; -} - -inline oop& JNIHandles::jobject_ref(jobject handle) { - assert(!is_jweak(handle), "precondition"); - return *reinterpret_cast(handle); -} - -inline oop& JNIHandles::jweak_ref(jobject handle) { - assert(is_jweak(handle), "precondition"); - char* ptr = reinterpret_cast(handle) - weak_tag_value; - return *reinterpret_cast(ptr); -} - -// external_guard is true if called from resolve_external_guard. -// Treat deleted (and possibly zapped) as NULL for external_guard, -// else as (asserted) error. -template -inline oop JNIHandles::guard_value(oop value) { - if (!external_guard) { - assert(value != badJNIHandle, "Pointing to zapped jni handle area"); - assert(value != deleted_handle(), "Used a deleted global handle"); - } else if ((value == badJNIHandle) || (value == deleted_handle())) { - value = NULL; - } - return value; -} - -// external_guard is true if called from resolve_external_guard. -template -inline oop JNIHandles::resolve_impl(jobject handle) { - assert(handle != NULL, "precondition"); - oop result; - if (is_jweak(handle)) { // Unlikely - result = resolve_jweak(handle); - } else { - result = jobject_ref(handle); - // Construction of jobjects canonicalize a null value into a null - // jobject, so for non-jweak the pointee should never be null. - assert(external_guard || result != NULL, - "Invalid value read from jni handle"); - result = guard_value(result); - } - return result; -} inline oop JNIHandles::resolve(jobject handle) { - oop result = NULL; - if (handle != NULL) { - result = resolve_impl(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"); 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) { - oop result = NULL; - if (handle != NULL) { - result = resolve_impl(handle); - } + if (handle == NULL) return NULL; + oop result = *(oop*)handle; + if (result == NULL || result == badJNIHandle) return NULL; return result; -} +}; + inline oop JNIHandles::resolve_non_null(jobject handle) { assert(handle != NULL, "JNI handle should not be null"); - oop result = resolve_impl(handle); - assert(result != NULL, "NULL read from jni handle"); + 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."); return result; -} +}; inline void JNIHandles::destroy_local(jobject handle) { if (handle != NULL) { - jobject_ref(handle) = deleted_handle(); + *((oop*)handle) = deleted_handle(); // Mark the handle as deleted, allocate will reuse it } } diff --git a/hotspot/src/share/vm/shark/sharkNativeWrapper.cpp b/hotspot/src/share/vm/shark/sharkNativeWrapper.cpp index b9ac6a3ebf5..53fea3154b8 100644 --- a/hotspot/src/share/vm/shark/sharkNativeWrapper.cpp +++ b/hotspot/src/share/vm/shark/sharkNativeWrapper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, 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. * @@ -300,7 +300,6 @@ void SharkNativeWrapper::initialize(const char *name) { not_null, merge); builder()->SetInsertPoint(not_null); -#error Needs to be updated for tagged jweak; see JNIHandles. Value *unboxed_result = builder()->CreateLoad(result); builder()->CreateBr(merge); diff --git a/hotspot/test/runtime/jni/CallWithJNIWeak/CallWithJNIWeak.java b/hotspot/test/runtime/jni/CallWithJNIWeak/CallWithJNIWeak.java deleted file mode 100644 index 3aaec5e4fd5..00000000000 --- a/hotspot/test/runtime/jni/CallWithJNIWeak/CallWithJNIWeak.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8166188 - * @summary Test call of native function with JNI weak global ref. - * @modules java.base - * @run main/othervm/native CallWithJNIWeak - */ - -public class CallWithJNIWeak { - static { - System.loadLibrary("CallWithJNIWeak"); - } - - private static native void testJNIFieldAccessors(CallWithJNIWeak o); - - // The field initializations must be kept in sync with the JNI code - // which reads verifies the values of these fields. - private int i = 1; - private long j = 2; - private boolean z = true; - private char c = 'a'; - private short s = 3; - private float f = 1.0f; - private double d = 2.0; - private Object l; - - private CallWithJNIWeak() { - this.l = this; - } - - private native void weakReceiverTest0(); - private void weakReceiverTest() { - weakReceiverTest0(); - } - - private synchronized void synchonizedWeakReceiverTest() { - this.notifyAll(); - } - - - private static native void runTests(CallWithJNIWeak o); - - public static void main(String[] args) { - CallWithJNIWeak w = new CallWithJNIWeak(); - for (int i = 0; i < 20000; i++) { - runTests(w); - } - } -} diff --git a/hotspot/test/runtime/jni/CallWithJNIWeak/libCallWithJNIWeak.c b/hotspot/test/runtime/jni/CallWithJNIWeak/libCallWithJNIWeak.c deleted file mode 100644 index 83a5784c1e8..00000000000 --- a/hotspot/test/runtime/jni/CallWithJNIWeak/libCallWithJNIWeak.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include - -/* - * Class: CallWithJNIWeak - * Method: testJNIFieldAccessors - * Signature: (LCallWithJNIWeak;)V - */ -JNIEXPORT void JNICALL -Java_CallWithJNIWeak_testJNIFieldAccessors(JNIEnv *env, jclass clazz, jobject this) { - // Make sure that we have a weak reference to the receiver - - jweak self = (*env)->NewWeakGlobalRef(env, this); - - jclass this_class = (*env)->GetObjectClass(env, self); - - jclass exception = (*env)->FindClass(env, "java/lang/RuntimeException"); - - jfieldID id_i = (*env)->GetFieldID(env, this_class, "i", "I"); - jfieldID id_j = (*env)->GetFieldID(env, this_class, "j", "J"); - jfieldID id_z = (*env)->GetFieldID(env, this_class, "z", "Z"); - jfieldID id_c = (*env)->GetFieldID(env, this_class, "c", "C"); - jfieldID id_s = (*env)->GetFieldID(env, this_class, "s", "S"); - jfieldID id_f = (*env)->GetFieldID(env, this_class, "f", "F"); - jfieldID id_d = (*env)->GetFieldID(env, this_class, "d", "D"); - jfieldID id_l = (*env)->GetFieldID(env, this_class, "l", "Ljava/lang/Object;"); - jvalue v; - -#define CHECK(variable, expected) \ - do { \ - if ((variable) != (expected)) { \ - (*env)->ThrowNew(env, exception, #variable" != " #expected); \ - return; \ - } \ - } while(0) - - // The values checked below must be kept in sync with the Java source file. - - v.i = (*env)->GetIntField(env, self, id_i); - CHECK(v.i, 1); - - v.j = (*env)->GetLongField(env, self, id_j); - CHECK(v.j, 2); - - v.z = (*env)->GetBooleanField(env, self, id_z); - CHECK(v.z, JNI_TRUE); - - v.c = (*env)->GetCharField(env, self, id_c); - CHECK(v.c, 'a'); - - v.s = (*env)->GetShortField(env, self, id_s); - CHECK(v.s, 3); - - v.f = (*env)->GetFloatField(env, self, id_f); - CHECK(v.f, 1.0f); - - v.d = (*env)->GetDoubleField(env, self, id_d); - CHECK(v.d, 2.0); - -#undef CHECK - - v.l = (*env)->GetObjectField(env, self, id_l); - if (v.l == NULL) { - (*env)->ThrowNew(env, exception, "Object field was null"); - return; - } - { - jclass clz = (*env)->GetObjectClass(env, v.l); - if (!(*env)->IsSameObject(env, clazz, clz)) { - (*env)->ThrowNew(env, exception, "Bad object class"); - } - } - - (*env)->DeleteWeakGlobalRef(env, self); -} - -/* - * Class: CallWithJNIWeak - * Method: runTests - * Signature: (LCallWithJNIWeak;)V - */ -JNIEXPORT void JNICALL -Java_CallWithJNIWeak_runTests(JNIEnv *env, jclass clazz, jobject this) { - jweak that = (*env)->NewWeakGlobalRef(env, this); - { - jmethodID method = (*env)->GetStaticMethodID(env, - clazz, "testJNIFieldAccessors", "(LCallWithJNIWeak;)V"); - (*env)->CallStaticVoidMethod(env, clazz, method, that); - if ((*env)->ExceptionCheck(env)) { - return; - } - } - - { - jmethodID method = (*env)->GetMethodID(env, clazz, "weakReceiverTest", "()V"); - (*env)->CallVoidMethod(env, that, method); - if ((*env)->ExceptionCheck(env)) { - return; - } - } - - { - jmethodID method = (*env)->GetMethodID(env, clazz, "synchonizedWeakReceiverTest", "()V"); - (*env)->CallVoidMethod(env, that, method); - if ((*env)->ExceptionCheck(env)) { - return; - } - } - (*env)->DeleteWeakGlobalRef(env, that); -} - -/* - * Class: CallWithJNIWeak - * Method: weakReceiverTest0 - * Signature: ()V - */ -JNIEXPORT void JNICALL -Java_CallWithJNIWeak_weakReceiverTest0(JNIEnv *env, jobject obj) { - (*env)->GetObjectClass(env, obj); -} diff --git a/hotspot/test/runtime/jni/ReturnJNIWeak/ReturnJNIWeak.java b/hotspot/test/runtime/jni/ReturnJNIWeak/ReturnJNIWeak.java deleted file mode 100644 index 6d581000fb8..00000000000 --- a/hotspot/test/runtime/jni/ReturnJNIWeak/ReturnJNIWeak.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* @test - * @bug 8166188 - * @requires vm.opt.ExplicitGCInvokesConcurrent != true - * @summary Test return of JNI weak global refs from native calls. - * @modules java.base - * @run main/othervm/native -Xint ReturnJNIWeak - * @run main/othervm/native -Xcomp ReturnJNIWeak - */ - -public final class ReturnJNIWeak { - - static { - System.loadLibrary("ReturnJNIWeak"); - } - - private static final class TestObject { - public final int value; - - public TestObject(int value) { - this.value = value; - } - } - - private static volatile TestObject testObject = null; - - private static native void registerObject(Object o); - private static native void unregisterObject(); - private static native Object getObject(); - - // Create the test object and record it both strongly and weakly. - private static void remember(int value) { - TestObject o = new TestObject(value); - registerObject(o); - testObject = o; - } - - // Remove both strong and weak references to the current test object. - private static void forget() { - unregisterObject(); - testObject = null; - } - - // Verify the weakly recorded object - private static void checkValue(int value) throws Exception { - Object o = getObject(); - if (o == null) { - throw new RuntimeException("Weak reference unexpectedly null"); - } - TestObject t = (TestObject)o; - if (t.value != value) { - throw new RuntimeException("Incorrect value"); - } - } - - // Verify we can create a weak reference and get it back. - private static void testSanity() throws Exception { - System.out.println("running testSanity"); - int value = 5; - try { - remember(value); - checkValue(value); - } finally { - forget(); - } - } - - // Verify weak ref value survives across collection if strong ref exists. - private static void testSurvival() throws Exception { - System.out.println("running testSurvival"); - int value = 10; - try { - remember(value); - checkValue(value); - System.gc(); - // Verify weak ref still has expected value. - checkValue(value); - } finally { - forget(); - } - } - - // Verify weak ref cleared if no strong ref exists. - private static void testClear() throws Exception { - System.out.println("running testClear"); - int value = 15; - try { - remember(value); - checkValue(value); - // Verify still good. - checkValue(value); - // Drop reference. - testObject = null; - System.gc(); - // Verify weak ref cleared as expected. - Object recorded = getObject(); - if (recorded != null) { - throw new RuntimeException("expected clear"); - } - } finally { - forget(); - } - } - - public static void main(String[] args) throws Exception { - testSanity(); - testSurvival(); - testClear(); - } -} diff --git a/hotspot/test/runtime/jni/ReturnJNIWeak/libReturnJNIWeak.c b/hotspot/test/runtime/jni/ReturnJNIWeak/libReturnJNIWeak.c deleted file mode 100644 index 12d7ae92e6e..00000000000 --- a/hotspot/test/runtime/jni/ReturnJNIWeak/libReturnJNIWeak.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * Native support for ReturnJNIWeak test. - */ - -#include "jni.h" - -static jweak registered = NULL; - -JNIEXPORT void JNICALL -Java_ReturnJNIWeak_registerObject(JNIEnv* env, - jclass jclazz, - jobject value) { - // assert registered == NULL - registered = (*env)->NewWeakGlobalRef(env, value); -} - -JNIEXPORT void JNICALL -Java_ReturnJNIWeak_unregisterObject(JNIEnv* env, jclass jclazz) { - if (registered != NULL) { - (*env)->DeleteWeakGlobalRef(env, registered); - registered = NULL; - } -} - -JNIEXPORT jobject JNICALL -Java_ReturnJNIWeak_getObject(JNIEnv* env, jclass jclazz) { - // assert registered != NULL - return registered; -}