# HG changeset patch # User jwilhelm # Date 1491516793 0 # Node ID 7a0ae73888ff8f54f81518a78edae2e197f275a6 # Parent da05330bbc7b697ed5308d0e7afc1d56cc06ac48# Parent 3bf4544bec14135930cfe192e132a1fad36c54a2 Merge diff -r da05330bbc7b -r 7a0ae73888ff hotspot/.hgtags --- a/hotspot/.hgtags Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/.hgtags Thu Apr 06 22:13:13 2017 +0000 @@ -566,3 +566,4 @@ 94b4e2e5331d38eab6a3639c3511b2e0715df0e9 jdk-9+160 191ffbdb3d7b734288daa7fb76b37a0a85dfe7eb jdk-9+161 b01c519b715ef6f785d0631adee0a6537cf6c12e jdk-9+162 +983fe207555724d98f4876991e1cbafbcf2733e8 jdk-9+163 diff -r da05330bbc7b -r 7a0ae73888ff hotspot/make/lib/CompileJvm.gmk --- a/hotspot/make/lib/CompileJvm.gmk Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/make/lib/CompileJvm.gmk Thu Apr 06 22:13:13 2017 +0000 @@ -118,6 +118,12 @@ OPENJDK_TARGET_CPU_VM_VERSION := amd64 else ifeq ($(OPENJDK_TARGET_CPU), sparcv9) OPENJDK_TARGET_CPU_VM_VERSION := sparc +else ifeq ($(HOTSPOT_TARGET_CPU_ARCH), arm) + ifeq ($(OPENJDK_TARGET_CPU), aarch64) + # This sets the Oracle Aarch64 port to use arm64 + # while the original Aarch64 port uses aarch64 + OPENJDK_TARGET_CPU_VM_VERSION := arm64 + endif else OPENJDK_TARGET_CPU_VM_VERSION := $(OPENJDK_TARGET_CPU) endif diff -r da05330bbc7b -r 7a0ae73888ff hotspot/make/test/JtregNative.gmk --- a/hotspot/make/test/JtregNative.gmk Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/make/test/JtregNative.gmk Thu Apr 06 22:13:13 2017 +0000 @@ -50,6 +50,8 @@ $(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 -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/aarch64/vm/aarch64.ad --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad Thu Apr 06 22:13:13 2017 +0000 @@ -15501,7 +15501,7 @@ %} instruct string_indexofUU(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, iRegI_R2 cnt2, - iRegI_R0 result, iRegI tmp1, iRegI tmp2, iRegI tmp3, iRegI tmp4, rFlagsReg cr) + iRegI_R0 result, iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, iRegINoSp tmp4, rFlagsReg cr) %{ predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU); match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); @@ -15520,7 +15520,7 @@ %} instruct string_indexofLL(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, iRegI_R2 cnt2, - iRegI_R0 result, iRegI tmp1, iRegI tmp2, iRegI tmp3, iRegI tmp4, rFlagsReg cr) + iRegI_R0 result, iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, iRegINoSp tmp4, rFlagsReg cr) %{ predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL); match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); @@ -15539,7 +15539,7 @@ %} instruct string_indexofUL(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, iRegI_R2 cnt2, - iRegI_R0 result, iRegI tmp1, iRegI tmp2, iRegI tmp3, iRegI tmp4, rFlagsReg cr) + iRegI_R0 result, iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, iRegINoSp tmp4, rFlagsReg cr) %{ predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL); match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); @@ -15558,7 +15558,7 @@ %} instruct string_indexofLU(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, iRegI_R2 cnt2, - iRegI_R0 result, iRegI tmp1, iRegI tmp2, iRegI tmp3, iRegI tmp4, rFlagsReg cr) + iRegI_R0 result, iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, iRegINoSp tmp4, rFlagsReg cr) %{ predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LU); match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); @@ -15577,8 +15577,8 @@ %} instruct string_indexof_conUU(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, - immI_le_4 int_cnt2, iRegI_R0 result, iRegI tmp1, iRegI tmp2, - iRegI tmp3, iRegI tmp4, rFlagsReg cr) + immI_le_4 int_cnt2, iRegI_R0 result, iRegINoSp tmp1, iRegINoSp tmp2, + iRegINoSp tmp3, iRegINoSp tmp4, rFlagsReg cr) %{ predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU); match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); @@ -15598,8 +15598,8 @@ %} instruct string_indexof_conLL(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, - immI_le_4 int_cnt2, iRegI_R0 result, iRegI tmp1, iRegI tmp2, - iRegI tmp3, iRegI tmp4, rFlagsReg cr) + immI_le_4 int_cnt2, iRegI_R0 result, iRegINoSp tmp1, iRegINoSp tmp2, + iRegINoSp tmp3, iRegINoSp tmp4, rFlagsReg cr) %{ predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL); match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); @@ -15619,8 +15619,8 @@ %} instruct string_indexof_conUL(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, - immI_1 int_cnt2, iRegI_R0 result, iRegI tmp1, iRegI tmp2, - iRegI tmp3, iRegI tmp4, rFlagsReg cr) + immI_1 int_cnt2, iRegI_R0 result, iRegINoSp tmp1, iRegINoSp tmp2, + iRegINoSp tmp3, iRegINoSp tmp4, rFlagsReg cr) %{ predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL); match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); @@ -15640,8 +15640,8 @@ %} instruct string_indexof_conLU(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, - immI_1 int_cnt2, iRegI_R0 result, iRegI tmp1, iRegI tmp2, - iRegI tmp3, iRegI tmp4, rFlagsReg cr) + immI_1 int_cnt2, iRegI_R0 result, iRegINoSp tmp1, iRegINoSp tmp2, + iRegINoSp tmp3, iRegINoSp tmp4, rFlagsReg cr) %{ predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LU); match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); @@ -15661,8 +15661,8 @@ %} instruct string_indexofU_char(iRegP_R1 str1, iRegI_R2 cnt1, iRegI_R3 ch, - iRegI_R0 result, iRegI tmp1, iRegI tmp2, - iRegI tmp3, rFlagsReg cr) + iRegI_R0 result, iRegINoSp tmp1, iRegINoSp tmp2, + iRegINoSp tmp3, rFlagsReg cr) %{ match(Set result (StrIndexOfChar (Binary str1 cnt1) ch)); effect(USE_KILL str1, USE_KILL cnt1, USE_KILL ch, @@ -16101,7 +16101,7 @@ // ====================REDUCTION ARITHMETIC==================================== -instruct reduce_add2I(iRegINoSp dst, iRegIorL2I src1, vecD src2, iRegI tmp, iRegI tmp2) +instruct reduce_add2I(iRegINoSp dst, iRegIorL2I src1, vecD src2, iRegINoSp tmp, iRegINoSp tmp2) %{ match(Set dst (AddReductionVI src1 src2)); ins_cost(INSN_COST); @@ -16120,7 +16120,7 @@ ins_pipe(pipe_class_default); %} -instruct reduce_add4I(iRegINoSp dst, iRegIorL2I src1, vecX src2, vecX tmp, iRegI tmp2) +instruct reduce_add4I(iRegINoSp dst, iRegIorL2I src1, vecX src2, vecX tmp, iRegINoSp tmp2) %{ match(Set dst (AddReductionVI src1 src2)); ins_cost(INSN_COST); @@ -16138,7 +16138,7 @@ ins_pipe(pipe_class_default); %} -instruct reduce_mul2I(iRegINoSp dst, iRegIorL2I src1, vecD src2, iRegI tmp) +instruct reduce_mul2I(iRegINoSp dst, iRegIorL2I src1, vecD src2, iRegINoSp tmp) %{ match(Set dst (MulReductionVI src1 src2)); ins_cost(INSN_COST); @@ -16157,7 +16157,7 @@ ins_pipe(pipe_class_default); %} -instruct reduce_mul4I(iRegINoSp dst, iRegIorL2I src1, vecX src2, vecX tmp, iRegI tmp2) +instruct reduce_mul4I(iRegINoSp dst, iRegIorL2I src1, vecX src2, vecX tmp, iRegINoSp tmp2) %{ match(Set dst (MulReductionVI src1 src2)); ins_cost(INSN_COST); diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -82,6 +82,11 @@ __ 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 -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -2052,13 +2052,31 @@ __ 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 -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/aarch64/vm/templateInterpreterGenerator_aarch64.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -1395,13 +1395,32 @@ // 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 -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/arm/vm/interp_masm_arm.cpp --- a/hotspot/src/cpu/arm/vm/interp_masm_arm.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/arm/vm/interp_masm_arm.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -476,185 +476,6 @@ } ////////////////////////////////////////////////////////////////////////////////// -#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 -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/arm/vm/interp_masm_arm.hpp --- a/hotspot/src/cpu/arm/vm/interp_masm_arm.hpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/arm/vm/interp_masm_arm.hpp Thu Apr 06 22:13:13 2017 +0000 @@ -146,27 +146,6 @@ 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 -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/arm/vm/jniFastGetField_arm.cpp --- a/hotspot/src/cpu/arm/vm/jniFastGetField_arm.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/arm/vm/jniFastGetField_arm.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -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 @@ __ 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 -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp --- a/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/arm/vm/macroAssembler_arm.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -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 @@ 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 -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp --- a/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/arm/vm/macroAssembler_arm.hpp Thu Apr 06 22:13:13 2017 +0000 @@ -401,6 +401,29 @@ 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 -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/arm/vm/sharedRuntime_arm.cpp --- a/hotspot/src/cpu/arm/vm/sharedRuntime_arm.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/arm/vm/sharedRuntime_arm.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -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 @@ 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,13 +1741,14 @@ if (CheckJNICalls) { __ str(__ zero_register(Rtemp), Address(Rthread, JavaThread::pending_jni_exception_check_fn_offset())); } +#endif // AARCH64 - // Unhandle the result + // Unbox oop result, e.g. JNIHandles::resolve value in R0. if (ret_type == T_OBJECT || ret_type == T_ARRAY) { - __ cmp(R0, 0); - __ ldr(R0, Address(R0), ne); + __ resolve_jobject(R0, // value + Rtemp, // tmp1 + R1_tmp); // tmp2 } -#endif // AARCH64 // Any exception pending? __ ldr(Rtemp, Address(Rthread, Thread::pending_exception_offset())); diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/arm/vm/templateInterpreterGenerator_arm.cpp --- a/hotspot/src/cpu/arm/vm/templateInterpreterGenerator_arm.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/arm/vm/templateInterpreterGenerator_arm.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -1237,28 +1237,25 @@ __ str(__ zero_register(Rtemp), Address(Rthread, JavaThread::pending_jni_exception_check_fn_offset())); } - // Unbox if the result is non-zero object + // Unbox oop result, e.g. JNIHandles::resolve result if it's an oop. + { + Label Lnot_oop; #ifdef AARCH64 - { - Label L, Lnull; __ 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 -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/ppc/vm/frame_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/frame_ppc.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/ppc/vm/frame_ppc.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -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 @@ switch (method->result_type()) { case T_OBJECT: case T_ARRAY: { - oop* obj_p = *(oop**)lresult; - oop obj = (obj_p == NULL) ? (oop)NULL : *obj_p; - assert(obj == NULL || Universe::heap()->is_in(obj), "sanity check"); - *oop_result = obj; + *oop_result = JNIHandles::resolve(*(jobject*)lresult); break; } // We use std/stfd to store the values. diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -3033,6 +3033,34 @@ stbx(R0, Rtmp, Robj); } +// Kills R31 if value is a volatile register. +void MacroAssembler::resolve_jobject(Register value, Register tmp1, Register tmp2, bool needs_frame) { + Label done; + cmpdi(CCR0, value, 0); + beq(CCR0, done); // Use NULL as-is. + + clrrdi(tmp1, value, JNIHandles::weak_tag_size); +#if INCLUDE_ALL_GCS + if (UseG1GC) { andi_(tmp2, value, JNIHandles::weak_tag_mask); } +#endif + ld(value, 0, tmp1); // Resolve (untagged) jobject. + +#if INCLUDE_ALL_GCS + if (UseG1GC) { + Label not_weak; + beq(CCR0, not_weak); // Test for jweak tag. + verify_oop(value); + g1_write_barrier_pre(noreg, // obj + noreg, // offset + value, // pre_val + tmp1, tmp2, needs_frame); + bind(not_weak); + } +#endif // INCLUDE_ALL_GCS + verify_oop(value); + bind(done); +} + #if INCLUDE_ALL_GCS // General G1 pre-barrier generator. // Goal: record the previous value if it is not null. @@ -3094,7 +3122,7 @@ bind(runtime); - // VM call need frame to access(write) O register. + // May need to preserve LR. Also needed if current frame is not compatible with C calling convention. if (needs_frame) { save_LR_CR(Rtmp1); push_frame_reg_args(0, Rtmp2); diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp Thu Apr 06 22:13:13 2017 +0000 @@ -649,6 +649,8 @@ void card_write_barrier_post(Register Rstore_addr, Register Rnew_val, Register Rtmp); void card_table_write(jbyte* byte_map_base, Register Rtmp, Register Robj); + void resolve_jobject(Register value, Register tmp1, Register tmp2, bool needs_frame); + #if INCLUDE_ALL_GCS // General G1 pre-barrier generator. void g1_write_barrier_pre(Register Robj, RegisterOrConstant offset, Register Rpre_val, diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -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 @@ __ 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 -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -401,11 +401,8 @@ case T_LONG: break; case T_OBJECT: - // unbox result if not null - __ cmpdi(CCR0, R3_RET, 0); - __ beq(CCR0, done); - __ ld(R3_RET, 0, R3_RET); - __ verify_oop(R3_RET); + // JNIHandles::resolve result. + __ resolve_jobject(R3_RET, R11_scratch1, R12_scratch2, /* needs_frame */ true); // kills R31 break; case T_FLOAT: break; diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp --- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -3450,6 +3450,34 @@ 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 -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp --- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp Thu Apr 06 22:13:13 2017 +0000 @@ -726,6 +726,8 @@ // 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 -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/s390/vm/sharedRuntime_s390.cpp --- a/hotspot/src/cpu/s390/vm/sharedRuntime_s390.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/s390/vm/sharedRuntime_s390.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -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 @@ __ 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 -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp --- a/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -1692,14 +1692,11 @@ // 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 -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/sparc/vm/jniFastGetField_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/jniFastGetField_sparc.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/sparc/vm/jniFastGetField_sparc.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,6 +68,7 @@ __ andcc (G4, 1, G0); __ br (Assembler::notZero, false, Assembler::pn, label1); __ delayed()->srl (O2, 2, O4); + __ andn (O1, JNIHandles::weak_tag_mask, O1); __ ld_ptr (O1, 0, O5); assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); @@ -147,6 +148,7 @@ __ andcc (G4, 1, G0); __ br (Assembler::notZero, false, Assembler::pn, label1); __ delayed()->srl (O2, 2, O4); + __ andn (O1, JNIHandles::weak_tag_mask, O1); __ ld_ptr (O1, 0, O5); __ add (O5, O4, O5); @@ -219,6 +221,7 @@ __ andcc (G4, 1, G0); __ br (Assembler::notZero, false, Assembler::pn, label1); __ delayed()->srl (O2, 2, O4); + __ andn (O1, JNIHandles::weak_tag_mask, O1); __ ld_ptr (O1, 0, O5); assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2754,15 +2754,30 @@ __ verify_thread(); // G2_thread must be correct __ reset_last_Java_frame(); - // Unpack oop result + // Unbox oop result, e.g. JNIHandles::resolve value in I0. if (ret_type == T_OBJECT || ret_type == T_ARRAY) { - Label L; - __ addcc(G0, I0, G0); - __ brx(Assembler::notZero, true, Assembler::pt, L); - __ delayed()->ld_ptr(I0, 0, I0); - __ mov(G0, I0); - __ bind(L); - __ verify_oop(I0); + Label done, not_weak; + __ br_null(I0, false, Assembler::pn, done); // Use NULL as-is. + __ delayed()->andcc(I0, JNIHandles::weak_tag_mask, G0); // Test for jweak + __ brx(Assembler::zero, true, Assembler::pt, not_weak); + __ delayed()->ld_ptr(I0, 0, I0); // Maybe resolve (untagged) jobject. + // Resolve jweak. + __ ld_ptr(I0, -JNIHandles::weak_tag_value, I0); +#if INCLUDE_ALL_GCS + if (UseG1GC) { + // Copy to O0 because macro doesn't allow pre_val in input reg. + __ mov(I0, O0); + __ g1_write_barrier_pre(noreg /* obj */, + noreg /* index */, + 0 /* offset */, + O0 /* pre_val */, + G3_scratch /* tmp */, + true /* preserve_o_regs */); + } +#endif // INCLUDE_ALL_GCS + __ bind(not_weak); + __ verify_oop(I0); + __ bind(done); } if (CheckJNICalls) { diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/sparc/vm/templateInterpreterGenerator_sparc.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -1514,11 +1514,23 @@ __ set((intptr_t)AbstractInterpreter::result_handler(T_OBJECT), G3_scratch); __ cmp_and_brx_short(G3_scratch, Lscratch, Assembler::notEqual, Assembler::pt, no_oop); - __ addcc(G0, O0, O0); - __ brx(Assembler::notZero, true, Assembler::pt, store_result); // if result is not NULL: - __ delayed()->ld_ptr(O0, 0, O0); // unbox it - __ mov(G0, O0); - + // Unbox oop result, e.g. JNIHandles::resolve value in O0. + __ br_null(O0, false, Assembler::pn, store_result); // Use NULL as-is. + __ delayed()->andcc(O0, JNIHandles::weak_tag_mask, G0); // Test for jweak + __ brx(Assembler::zero, true, Assembler::pt, store_result); + __ delayed()->ld_ptr(O0, 0, O0); // Maybe resolve (untagged) jobject. + // Resolve jweak. + __ ld_ptr(O0, -JNIHandles::weak_tag_value, O0); +#if INCLUDE_ALL_GCS + if (UseG1GC) { + __ g1_write_barrier_pre(noreg /* obj */, + noreg /* index */, + 0 /* offset */, + O0 /* pre_val */, + G3_scratch /* tmp */, + true /* preserve_o_regs */); + } +#endif // INCLUDE_ALL_GCS __ bind(store_result); // Store it where gc will look for it and result handler expects it. __ st_ptr(O0, FP, (frame::interpreter_frame_oop_temp_offset*wordSize) + STACK_BIAS); diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/x86/vm/jniFastGetField_x86_32.cpp --- a/hotspot/src/cpu/x86/vm/jniFastGetField_x86_32.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/x86/vm/jniFastGetField_x86_32.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,6 +85,9 @@ __ movptr (rdx, Address(rsp, 2*wordSize)); // obj } __ movptr(rax, Address(rsp, 3*wordSize)); // jfieldID + + __ clear_jweak_tag(rdx); + __ movptr(rdx, Address(rdx, 0)); // *obj __ shrptr (rax, 2); // offset @@ -202,6 +205,9 @@ __ 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 @@ __ movptr(rdx, Address(rsp, 2*wordSize)); // obj } __ movptr(rax, Address(rsp, 3*wordSize)); // jfieldID + + __ clear_jweak_tag(rdx); + __ movptr(rdx, Address(rdx, 0)); // *obj __ shrptr(rax, 2); // offset diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/x86/vm/jniFastGetField_x86_64.cpp --- a/hotspot/src/cpu/x86/vm/jniFastGetField_x86_64.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/x86/vm/jniFastGetField_x86_64.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,6 +80,9 @@ // 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 @@ // 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 -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -5129,6 +5129,43 @@ } +void MacroAssembler::resolve_jobject(Register value, + Register thread, + Register tmp) { + assert_different_registers(value, thread, tmp); + Label done, not_weak; + testptr(value, value); + jcc(Assembler::zero, done); // Use NULL as-is. + testptr(value, JNIHandles::weak_tag_mask); // Test for jweak tag. + jcc(Assembler::zero, not_weak); + // Resolve jweak. + movptr(value, Address(value, -JNIHandles::weak_tag_value)); + verify_oop(value); +#if INCLUDE_ALL_GCS + if (UseG1GC) { + g1_write_barrier_pre(noreg /* obj */, + value /* pre_val */, + thread /* thread */, + tmp /* tmp */, + true /* tosca_live */, + true /* expand_call */); + } +#endif // INCLUDE_ALL_GCS + jmp(done); + bind(not_weak); + // Resolve (untagged) jobject. + movptr(value, Address(value, 0)); + verify_oop(value); + bind(done); +} + +void MacroAssembler::clear_jweak_tag(Register possibly_jweak) { + const int32_t inverted_jweak_mask = ~static_cast(JNIHandles::weak_tag_mask); + STATIC_ASSERT(inverted_jweak_mask == -2); // otherwise check this code + // The inverted mask is sign-extended + andptr(possibly_jweak, inverted_jweak_mask); +} + ////////////////////////////////////////////////////////////////////////////////// #if INCLUDE_ALL_GCS diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp Thu Apr 06 22:13:13 2017 +0000 @@ -297,6 +297,9 @@ void store_check(Register obj); // store check for obj - register is destroyed afterwards void store_check(Register obj, Address dst); // same as above, dst is exact store location (reg. is destroyed) + void resolve_jobject(Register value, Register thread, Register tmp); + void clear_jweak_tag(Register possibly_jweak); + #if INCLUDE_ALL_GCS void g1_write_barrier_pre(Register obj, diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2226,14 +2226,11 @@ __ reset_last_Java_frame(thread, false); - // Unpack oop result + // Unbox oop result, e.g. JNIHandles::resolve value. if (ret_type == T_OBJECT || ret_type == T_ARRAY) { - Label L; - __ cmpptr(rax, (int32_t)NULL_WORD); - __ jcc(Assembler::equal, L); - __ movptr(rax, Address(rax, 0)); - __ bind(L); - __ verify_oop(rax); + __ resolve_jobject(rax /* value */, + thread /* thread */, + rcx /* tmp */); } if (CheckJNICalls) { diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2579,14 +2579,11 @@ __ reset_last_Java_frame(false); - // Unpack oop result + // Unbox oop result, e.g. JNIHandles::resolve value. if (ret_type == T_OBJECT || ret_type == T_ARRAY) { - Label L; - __ testptr(rax, rax); - __ jcc(Assembler::zero, L); - __ movptr(rax, Address(rax, 0)); - __ bind(L); - __ verify_oop(rax); + __ resolve_jobject(rax /* value */, + r15_thread /* thread */, + rcx /* tmp */); } if (CheckJNICalls) { diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp --- a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -1194,16 +1194,16 @@ // 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 -r da05330bbc7b -r 7a0ae73888ff hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp --- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -406,10 +406,12 @@ // oop_temp where the garbage collector can see it before // we release the handle it might be protected by. if (handler->result_type() == &ffi_type_pointer) { - if (result[0]) - istate->set_oop_temp(*(oop *) result[0]); - else + if (result[0] == 0) { istate->set_oop_temp(NULL); + } else { + jobject handle = reinterpret_cast(result[0]); + istate->set_oop_temp(JNIHandles::resolve(handle)); + } } // Reset handle block diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/Xusage.txt --- a/hotspot/src/share/vm/Xusage.txt Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/Xusage.txt Thu Apr 06 22:13:13 2017 +0000 @@ -12,7 +12,7 @@ -Xms set initial Java heap size -Xmx set maximum Java heap size -Xss set java thread stack size - -Xprof output cpu profiling data + -Xprof output cpu profiling data (deprecated) -Xfuture enable strictest checks, anticipating future default -Xrs reduce use of OS signals by Java/VM (see documentation) -Xcheck:jni perform additional checks for JNI functions diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/c1/c1_GraphBuilder.cpp --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -1540,7 +1540,7 @@ ciMethod* caller = state()->scope()->method(); ciMethodData* md = caller->method_data_or_null(); ciProfileData* data = md->bci_to_data(invoke_bci); - if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) { + if (data != NULL && (data->is_CallTypeData() || data->is_VirtualCallTypeData())) { bool has_return = data->is_CallTypeData() ? ((ciCallTypeData*)data)->has_return() : ((ciVirtualCallTypeData*)data)->has_return(); // May not be true in case of an inlined call through a method handle intrinsic. if (has_return) { @@ -1758,7 +1758,7 @@ start = has_receiver ? 1 : 0; if (profile_arguments()) { ciProfileData* data = method()->method_data()->bci_to_data(bci()); - if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) { + if (data != NULL && (data->is_CallTypeData() || data->is_VirtualCallTypeData())) { n = data->is_CallTypeData() ? data->as_CallTypeData()->number_of_arguments() : data->as_VirtualCallTypeData()->number_of_arguments(); } } @@ -4351,7 +4351,7 @@ } ciMethodData* md = m->method_data_or_null(); ciProfileData* data = md->bci_to_data(invoke_bci); - if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) { + if (data != NULL && (data->is_CallTypeData() || data->is_VirtualCallTypeData())) { append(new ProfileReturnType(m , invoke_bci, callee, ret)); } } diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/c1/c1_LIRGenerator.cpp --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -3262,50 +3262,52 @@ int bci = x->bci_of_invoke(); ciMethodData* md = x->method()->method_data_or_null(); ciProfileData* data = md->bci_to_data(bci); - if ((data->is_CallTypeData() && data->as_CallTypeData()->has_arguments()) || - (data->is_VirtualCallTypeData() && data->as_VirtualCallTypeData()->has_arguments())) { - ByteSize extra = data->is_CallTypeData() ? CallTypeData::args_data_offset() : VirtualCallTypeData::args_data_offset(); - int base_offset = md->byte_offset_of_slot(data, extra); - LIR_Opr mdp = LIR_OprFact::illegalOpr; - ciTypeStackSlotEntries* args = data->is_CallTypeData() ? ((ciCallTypeData*)data)->args() : ((ciVirtualCallTypeData*)data)->args(); - - Bytecodes::Code bc = x->method()->java_code_at_bci(bci); - int start = 0; - int stop = data->is_CallTypeData() ? ((ciCallTypeData*)data)->number_of_arguments() : ((ciVirtualCallTypeData*)data)->number_of_arguments(); - if (x->callee()->is_loaded() && x->callee()->is_static() && Bytecodes::has_receiver(bc)) { - // first argument is not profiled at call (method handle invoke) - assert(x->method()->raw_code_at_bci(bci) == Bytecodes::_invokehandle, "invokehandle expected"); - start = 1; + if (data != NULL) { + if ((data->is_CallTypeData() && data->as_CallTypeData()->has_arguments()) || + (data->is_VirtualCallTypeData() && data->as_VirtualCallTypeData()->has_arguments())) { + ByteSize extra = data->is_CallTypeData() ? CallTypeData::args_data_offset() : VirtualCallTypeData::args_data_offset(); + int base_offset = md->byte_offset_of_slot(data, extra); + LIR_Opr mdp = LIR_OprFact::illegalOpr; + ciTypeStackSlotEntries* args = data->is_CallTypeData() ? ((ciCallTypeData*)data)->args() : ((ciVirtualCallTypeData*)data)->args(); + + Bytecodes::Code bc = x->method()->java_code_at_bci(bci); + int start = 0; + int stop = data->is_CallTypeData() ? ((ciCallTypeData*)data)->number_of_arguments() : ((ciVirtualCallTypeData*)data)->number_of_arguments(); + if (x->callee()->is_loaded() && x->callee()->is_static() && Bytecodes::has_receiver(bc)) { + // first argument is not profiled at call (method handle invoke) + assert(x->method()->raw_code_at_bci(bci) == Bytecodes::_invokehandle, "invokehandle expected"); + start = 1; + } + ciSignature* callee_signature = x->callee()->signature(); + // method handle call to virtual method + bool has_receiver = x->callee()->is_loaded() && !x->callee()->is_static() && !Bytecodes::has_receiver(bc); + ciSignatureStream callee_signature_stream(callee_signature, has_receiver ? x->callee()->holder() : NULL); + + bool ignored_will_link; + ciSignature* signature_at_call = NULL; + x->method()->get_method_at_bci(bci, ignored_will_link, &signature_at_call); + ciSignatureStream signature_at_call_stream(signature_at_call); + + // if called through method handle invoke, some arguments may have been popped + for (int i = 0; i < stop && i+start < x->nb_profiled_args(); i++) { + int off = in_bytes(TypeEntriesAtCall::argument_type_offset(i)) - in_bytes(TypeEntriesAtCall::args_data_offset()); + ciKlass* exact = profile_type(md, base_offset, off, + args->type(i), x->profiled_arg_at(i+start), mdp, + !x->arg_needs_null_check(i+start), + signature_at_call_stream.next_klass(), callee_signature_stream.next_klass()); + if (exact != NULL) { + md->set_argument_type(bci, i, exact); + } + } + } else { +#ifdef ASSERT + Bytecodes::Code code = x->method()->raw_code_at_bci(x->bci_of_invoke()); + int n = x->nb_profiled_args(); + assert(MethodData::profile_parameters() && (MethodData::profile_arguments_jsr292_only() || + (x->inlined() && ((code == Bytecodes::_invokedynamic && n <= 1) || (code == Bytecodes::_invokehandle && n <= 2)))), + "only at JSR292 bytecodes"); +#endif } - ciSignature* callee_signature = x->callee()->signature(); - // method handle call to virtual method - bool has_receiver = x->callee()->is_loaded() && !x->callee()->is_static() && !Bytecodes::has_receiver(bc); - ciSignatureStream callee_signature_stream(callee_signature, has_receiver ? x->callee()->holder() : NULL); - - bool ignored_will_link; - ciSignature* signature_at_call = NULL; - x->method()->get_method_at_bci(bci, ignored_will_link, &signature_at_call); - ciSignatureStream signature_at_call_stream(signature_at_call); - - // if called through method handle invoke, some arguments may have been popped - for (int i = 0; i < stop && i+start < x->nb_profiled_args(); i++) { - int off = in_bytes(TypeEntriesAtCall::argument_type_offset(i)) - in_bytes(TypeEntriesAtCall::args_data_offset()); - ciKlass* exact = profile_type(md, base_offset, off, - args->type(i), x->profiled_arg_at(i+start), mdp, - !x->arg_needs_null_check(i+start), - signature_at_call_stream.next_klass(), callee_signature_stream.next_klass()); - if (exact != NULL) { - md->set_argument_type(bci, i, exact); - } - } - } else { -#ifdef ASSERT - Bytecodes::Code code = x->method()->raw_code_at_bci(x->bci_of_invoke()); - int n = x->nb_profiled_args(); - assert(MethodData::profile_parameters() && (MethodData::profile_arguments_jsr292_only() || - (x->inlined() && ((code == Bytecodes::_invokedynamic && n <= 1) || (code == Bytecodes::_invokehandle && n <= 2)))), - "only at JSR292 bytecodes"); -#endif } } } @@ -3396,24 +3398,26 @@ int bci = x->bci_of_invoke(); ciMethodData* md = x->method()->method_data_or_null(); ciProfileData* data = md->bci_to_data(bci); - assert(data->is_CallTypeData() || data->is_VirtualCallTypeData(), "wrong profile data type"); - ciReturnTypeEntry* ret = data->is_CallTypeData() ? ((ciCallTypeData*)data)->ret() : ((ciVirtualCallTypeData*)data)->ret(); - LIR_Opr mdp = LIR_OprFact::illegalOpr; - - bool ignored_will_link; - ciSignature* signature_at_call = NULL; - x->method()->get_method_at_bci(bci, ignored_will_link, &signature_at_call); - - // The offset within the MDO of the entry to update may be too large - // to be used in load/store instructions on some platforms. So have - // profile_type() compute the address of the profile in a register. - ciKlass* exact = profile_type(md, md->byte_offset_of_slot(data, ret->type_offset()), 0, - ret->type(), x->ret(), mdp, - !x->needs_null_check(), - signature_at_call->return_type()->as_klass(), - x->callee()->signature()->return_type()->as_klass()); - if (exact != NULL) { - md->set_return_type(bci, exact); + if (data != NULL) { + assert(data->is_CallTypeData() || data->is_VirtualCallTypeData(), "wrong profile data type"); + ciReturnTypeEntry* ret = data->is_CallTypeData() ? ((ciCallTypeData*)data)->ret() : ((ciVirtualCallTypeData*)data)->ret(); + LIR_Opr mdp = LIR_OprFact::illegalOpr; + + bool ignored_will_link; + ciSignature* signature_at_call = NULL; + x->method()->get_method_at_bci(bci, ignored_will_link, &signature_at_call); + + // The offset within the MDO of the entry to update may be too large + // to be used in load/store instructions on some platforms. So have + // profile_type() compute the address of the profile in a register. + ciKlass* exact = profile_type(md, md->byte_offset_of_slot(data, ret->type_offset()), 0, + ret->type(), x->ret(), mdp, + !x->needs_null_check(), + signature_at_call->return_type()->as_klass(), + x->callee()->signature()->return_type()->as_klass()); + if (exact != NULL) { + md->set_return_type(bci, exact); + } } } diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/ci/ciMethodData.cpp --- a/hotspot/src/share/vm/ci/ciMethodData.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/ci/ciMethodData.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -408,11 +408,13 @@ MethodData* mdo = get_MethodData(); if (mdo != NULL) { ProfileData* data = mdo->bci_to_data(bci); - if (data->is_CallTypeData()) { - data->as_CallTypeData()->set_argument_type(i, k->get_Klass()); - } else { - assert(data->is_VirtualCallTypeData(), "no arguments!"); - data->as_VirtualCallTypeData()->set_argument_type(i, k->get_Klass()); + if (data != NULL) { + if (data->is_CallTypeData()) { + data->as_CallTypeData()->set_argument_type(i, k->get_Klass()); + } else { + assert(data->is_VirtualCallTypeData(), "no arguments!"); + data->as_VirtualCallTypeData()->set_argument_type(i, k->get_Klass()); + } } } } @@ -430,11 +432,13 @@ MethodData* mdo = get_MethodData(); if (mdo != NULL) { ProfileData* data = mdo->bci_to_data(bci); - if (data->is_CallTypeData()) { - data->as_CallTypeData()->set_return_type(k->get_Klass()); - } else { - assert(data->is_VirtualCallTypeData(), "no arguments!"); - data->as_VirtualCallTypeData()->set_return_type(k->get_Klass()); + if (data != NULL) { + if (data->is_CallTypeData()) { + data->as_CallTypeData()->set_return_type(k->get_Klass()); + } else { + assert(data->is_VirtualCallTypeData(), "no arguments!"); + data->as_VirtualCallTypeData()->set_return_type(k->get_Klass()); + } } } } diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/classfile/moduleEntry.hpp --- a/hotspot/src/share/vm/classfile/moduleEntry.hpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/classfile/moduleEntry.hpp Thu Apr 06 22:13:13 2017 +0000 @@ -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 @@ -36,8 +36,8 @@ #include "utilities/ostream.hpp" #define UNNAMED_MODULE "Unnamed Module" -#define JAVAPKG "java/" -#define JAVAPKG_LEN 5 +#define JAVAPKG "java" +#define JAVAPKG_LEN 4 #define JAVA_BASE_NAME "java.base" class ModuleClosure; diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/classfile/modules.cpp --- a/hotspot/src/share/vm/classfile/modules.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/classfile/modules.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -319,7 +319,8 @@ // Only modules defined to either the boot or platform class loader, can define a "java/" package. if (!h_loader.is_null() && !SystemDictionary::is_platform_class_loader(h_loader()) && - strncmp(package_name, JAVAPKG, JAVAPKG_LEN) == 0) { + (strncmp(package_name, JAVAPKG, JAVAPKG_LEN) == 0 && + (package_name[JAVAPKG_LEN] == '/' || package_name[JAVAPKG_LEN] == '\0'))) { const char* class_loader_name = SystemDictionary::loader_name(h_loader()); size_t pkg_len = strlen(package_name); char* pkg_name = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, pkg_len); @@ -704,7 +705,8 @@ // Only modules defined to either the boot or platform class loader, can define a "java/" package. if (!loader_data->is_the_null_class_loader_data() && !loader_data->is_platform_class_loader_data() && - strncmp(package_name, JAVAPKG, JAVAPKG_LEN) == 0) { + (strncmp(package_name, JAVAPKG, JAVAPKG_LEN) == 0 && + (package_name[JAVAPKG_LEN] == '/' || package_name[JAVAPKG_LEN] == '\0'))) { const char* class_loader_name = SystemDictionary::loader_name(loader_data); size_t pkg_len = strlen(package_name); char* pkg_name = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, pkg_len); diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/classfile/stringTable.cpp --- a/hotspot/src/share/vm/classfile/stringTable.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/classfile/stringTable.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -96,10 +96,14 @@ // Pick hashing algorithm unsigned int StringTable::hash_string(const jchar* s, int len) { - return use_alternate_hashcode() ? AltHashing::murmur3_32(seed(), s, len) : + return use_alternate_hashcode() ? alt_hash_string(s, len) : java_lang_String::hash_code(s, len); } +unsigned int StringTable::alt_hash_string(const jchar* s, int len) { + return AltHashing::murmur3_32(seed(), s, len); +} + unsigned int StringTable::hash_string(oop string) { EXCEPTION_MARK; if (string == NULL) { @@ -117,11 +121,10 @@ } } -oop StringTable::lookup_shared(jchar* name, int len) { - // java_lang_String::hash_code() was used to compute hash values in the shared table. Don't - // use the hash value from StringTable::hash_string() as it might use alternate hashcode. - return _shared_table.lookup((const char*)name, - java_lang_String::hash_code(name, len), len); +oop StringTable::lookup_shared(jchar* name, int len, unsigned int hash) { + assert(hash == java_lang_String::hash_code(name, len), + "hash must be computed using java_lang_String::hash_code"); + return _shared_table.lookup((const char*)name, hash, len); } oop StringTable::lookup_in_main_table(int index, jchar* name, @@ -156,7 +159,7 @@ unsigned int hashValue; int index; if (use_alternate_hashcode()) { - hashValue = hash_string(name, len); + hashValue = alt_hash_string(name, len); index = hash_to_index(hashValue); } else { hashValue = hashValue_arg; @@ -199,12 +202,15 @@ } oop StringTable::lookup(jchar* name, int len) { - oop string = lookup_shared(name, len); + // shared table always uses java_lang_String::hash_code + unsigned int hash = java_lang_String::hash_code(name, len); + oop string = lookup_shared(name, len, hash); if (string != NULL) { return string; } - - unsigned int hash = hash_string(name, len); + if (use_alternate_hashcode()) { + hash = alt_hash_string(name, len); + } int index = the_table()->hash_to_index(hash); string = the_table()->lookup_in_main_table(index, name, len, hash); @@ -215,12 +221,15 @@ oop StringTable::intern(Handle string_or_null, jchar* name, int len, TRAPS) { - oop found_string = lookup_shared(name, len); + // shared table always uses java_lang_String::hash_code + unsigned int hashValue = java_lang_String::hash_code(name, len); + oop found_string = lookup_shared(name, len, hashValue); if (found_string != NULL) { return found_string; } - - unsigned int hashValue = hash_string(name, len); + if (use_alternate_hashcode()) { + hashValue = alt_hash_string(name, len); + } int index = the_table()->hash_to_index(hashValue); found_string = the_table()->lookup_in_main_table(index, name, len, hashValue); diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/classfile/stringTable.hpp --- a/hotspot/src/share/vm/classfile/stringTable.hpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/classfile/stringTable.hpp Thu Apr 06 22:13:13 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,7 +56,7 @@ unsigned int hashValue, TRAPS); oop lookup_in_main_table(int index, jchar* chars, int length, unsigned int hashValue); - static oop lookup_shared(jchar* name, int len); + static oop lookup_shared(jchar* name, int len, unsigned int hash); // Apply the give oop closure to the entries to the buckets // in the range [start_idx, end_idx). @@ -65,6 +65,13 @@ // in the range [start_idx, end_idx). static void buckets_unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, int start_idx, int end_idx, int* processed, int* removed); + // Hashing algorithm, used as the hash value used by the + // StringTable for bucket selection and comparison (stored in the + // HashtableEntry structures). This is used in the String.intern() method. + static unsigned int hash_string(const jchar* s, int len); + static unsigned int hash_string(oop string); + static unsigned int alt_hash_string(const jchar* s, int len); + StringTable() : RehashableHashtable((int)StringTableSize, sizeof (HashtableEntry)) {} @@ -109,12 +116,6 @@ } static void possibly_parallel_oops_do(OopClosure* f); - // Hashing algorithm, used as the hash value used by the - // StringTable for bucket selection and comparison (stored in the - // HashtableEntry structures). This is used in the String.intern() method. - static unsigned int hash_string(const jchar* s, int len); - static unsigned int hash_string(oop string); - // Internal test. static void test_alt_hash() PRODUCT_RETURN; diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/classfile/vmSymbols.hpp --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Thu Apr 06 22:13:13 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -561,6 +561,7 @@ template(int_StringBuffer_signature, "(I)Ljava/lang/StringBuffer;") \ template(char_StringBuffer_signature, "(C)Ljava/lang/StringBuffer;") \ template(int_String_signature, "(I)Ljava/lang/String;") \ + template(boolean_boolean_int_signature, "(ZZ)I") \ template(codesource_permissioncollection_signature, "(Ljava/security/CodeSource;Ljava/security/PermissionCollection;)V") \ /* signature symbols needed by intrinsics */ \ VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, template, VM_ALIAS_IGNORE) \ diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/compiler/compilerDefinitions.cpp --- a/hotspot/src/share/vm/compiler/compilerDefinitions.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/compiler/compilerDefinitions.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -100,7 +100,9 @@ FLAG_SET_ERGO(size_t, MetaspaceSize, 12*M); } if (FLAG_IS_DEFAULT(MaxRAM)) { - FLAG_SET_ERGO(uint64_t, MaxRAM, 1ULL*G); + // Do not use FLAG_SET_ERGO to update MaxRAM, as this will impact + // heap setting done based on available phys_mem (see Arguments::set_heap_size). + FLAG_SET_DEFAULT(MaxRAM, 1ULL*G); } if (FLAG_IS_DEFAULT(CompileThreshold)) { FLAG_SET_ERGO(intx, CompileThreshold, 1500); diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/oops/instanceKlass.cpp --- a/hotspot/src/share/vm/oops/instanceKlass.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -2417,22 +2417,24 @@ void InstanceKlass::check_prohibited_package(Symbol* class_name, Handle class_loader, TRAPS) { - ResourceMark rm(THREAD); if (!class_loader.is_null() && !SystemDictionary::is_platform_class_loader(class_loader()) && - class_name != NULL && - strncmp(class_name->as_C_string(), JAVAPKG, JAVAPKG_LEN) == 0) { - TempNewSymbol pkg_name = InstanceKlass::package_from_name(class_name, CHECK); - assert(pkg_name != NULL, "Error in parsing package name starting with 'java/'"); - char* name = pkg_name->as_C_string(); - const char* class_loader_name = SystemDictionary::loader_name(class_loader()); - StringUtils::replace_no_expand(name, "/", "."); - const char* msg_text1 = "Class loader (instance of): "; - const char* msg_text2 = " tried to load prohibited package name: "; - size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + strlen(name) + 1; - char* message = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, len); - jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, name); - THROW_MSG(vmSymbols::java_lang_SecurityException(), message); + class_name != NULL) { + ResourceMark rm(THREAD); + char* name = class_name->as_C_string(); + if (strncmp(name, JAVAPKG, JAVAPKG_LEN) == 0 && name[JAVAPKG_LEN] == '/') { + TempNewSymbol pkg_name = InstanceKlass::package_from_name(class_name, CHECK); + assert(pkg_name != NULL, "Error in parsing package name starting with 'java/'"); + name = pkg_name->as_C_string(); + const char* class_loader_name = SystemDictionary::loader_name(class_loader()); + StringUtils::replace_no_expand(name, "/", "."); + const char* msg_text1 = "Class loader (instance of): "; + const char* msg_text2 = " tried to load prohibited package name: "; + size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + strlen(name) + 1; + char* message = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, len); + jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, name); + THROW_MSG(vmSymbols::java_lang_SecurityException(), message); + } } return; } diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/opto/arraycopynode.cpp --- a/hotspot/src/share/vm/opto/arraycopynode.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/opto/arraycopynode.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -225,7 +225,6 @@ Node* dest = in(ArrayCopyNode::Dest); const Type* src_type = phase->type(src); const TypeAryPtr* ary_src = src_type->isa_aryptr(); - assert(ary_src != NULL, "should be an array copy/clone"); if (is_arraycopy() || is_copyofrange() || is_copyof()) { const Type* dest_type = phase->type(dest); @@ -286,7 +285,8 @@ copy_type = dest_elem; } else { - assert (is_clonebasic(), "should be"); + assert(ary_src != NULL, "should be a clone"); + assert(is_clonebasic(), "should be"); disjoint_bases = true; assert(src->is_AddP(), "should be base + off"); diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/opto/callnode.cpp --- a/hotspot/src/share/vm/opto/callnode.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/opto/callnode.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -784,8 +784,8 @@ } // May modify (by reflection) if an boxing object is passed // as argument or returned. - if (returns_pointer() && (proj_out(TypeFunc::Parms) != NULL)) { - Node* proj = proj_out(TypeFunc::Parms); + Node* proj = returns_pointer() ? proj_out(TypeFunc::Parms) : NULL; + if (proj != NULL) { const TypeInstPtr* inst_t = phase->type(proj)->isa_instptr(); if ((inst_t != NULL) && (!inst_t->klass_is_exact() || (inst_t->klass() == boxing_klass))) { diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/opto/castnode.cpp --- a/hotspot/src/share/vm/opto/castnode.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/opto/castnode.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -225,7 +225,10 @@ } // Similar to ConvI2LNode::Ideal() for the same reasons - if (can_reshape && !phase->C->major_progress()) { + // Do not narrow the type of range check dependent CastIINodes to + // avoid corruption of the graph if a CastII is replaced by TOP but + // the corresponding range check is not removed. + if (can_reshape && !_range_check_dependency && !phase->C->major_progress()) { const TypeInt* this_type = this->type()->is_int(); const TypeInt* in_type = phase->type(in(1))->isa_int(); if (in_type != NULL && this_type != NULL && diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/opto/convertnode.cpp --- a/hotspot/src/share/vm/opto/convertnode.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/opto/convertnode.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -294,8 +294,7 @@ } #ifdef _LP64 - // Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y)) or - // ConvI2L(CastII(AddI(x, y))) to AddL(ConvI2L(CastII(x)), ConvI2L(CastII(y))), + // Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y)) // but only if x and y have subranges that cannot cause 32-bit overflow, // under the assumption that x+y is in my own subrange this->type(). @@ -319,13 +318,6 @@ Node* z = in(1); int op = z->Opcode(); - Node* ctrl = NULL; - if (op == Op_CastII && z->as_CastII()->has_range_check()) { - // Skip CastII node but save control dependency - ctrl = z->in(0); - z = z->in(1); - op = z->Opcode(); - } if (op == Op_AddI || op == Op_SubI) { Node* x = z->in(1); Node* y = z->in(2); @@ -385,8 +377,8 @@ } assert(rxlo == (int)rxlo && rxhi == (int)rxhi, "x should not overflow"); assert(rylo == (int)rylo && ryhi == (int)ryhi, "y should not overflow"); - Node* cx = phase->C->constrained_convI2L(phase, x, TypeInt::make(rxlo, rxhi, widen), ctrl); - Node* cy = phase->C->constrained_convI2L(phase, y, TypeInt::make(rylo, ryhi, widen), ctrl); + Node* cx = phase->C->constrained_convI2L(phase, x, TypeInt::make(rxlo, rxhi, widen), NULL); + Node* cy = phase->C->constrained_convI2L(phase, y, TypeInt::make(rylo, ryhi, widen), NULL); switch (op) { case Op_AddI: return new AddLNode(cx, cy); case Op_SubI: return new SubLNode(cx, cy); diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/opto/ifnode.cpp --- a/hotspot/src/share/vm/opto/ifnode.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/opto/ifnode.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -1465,8 +1465,9 @@ // be skipped. For example, range check predicate has two checks // for lower and upper bounds. ProjNode* unc_proj = proj_out(1 - prev_dom->as_Proj()->_con)->as_Proj(); - if (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) != NULL) - prev_dom = idom; + if ((unc_proj != NULL) && (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) != NULL)) { + prev_dom = idom; + } // Now walk the current IfNode's projections. // Loop ends when 'this' has no more uses. diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/opto/lcm.cpp --- a/hotspot/src/share/vm/opto/lcm.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/opto/lcm.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -254,10 +254,12 @@ const TypePtr *adr_type = NULL; // Do not need this return value here const Node* base = mach->get_base_and_disp(offset, adr_type); if (base == NULL || base == NodeSentinel) { - // Narrow oop address doesn't have base, only index - if( val->bottom_type()->isa_narrowoop() && - MacroAssembler::needs_explicit_null_check(offset) ) - continue; // Give up if offset is beyond page size + // Narrow oop address doesn't have base, only index. + // Give up if offset is beyond page size or if heap base is not protected. + if (val->bottom_type()->isa_narrowoop() && + (MacroAssembler::needs_explicit_null_check(offset) || + !Universe::narrow_oop_use_implicit_null_checks())) + continue; // cannot reason about it; is probably not implicit null exception } else { const TypePtr* tptr; @@ -269,12 +271,17 @@ // only regular oops are expected here tptr = base->bottom_type()->is_ptr(); } - // Give up if offset is not a compile-time constant - if( offset == Type::OffsetBot || tptr->_offset == Type::OffsetBot ) + // Give up if offset is not a compile-time constant. + if (offset == Type::OffsetBot || tptr->_offset == Type::OffsetBot) continue; offset += tptr->_offset; // correct if base is offseted - if( MacroAssembler::needs_explicit_null_check(offset) ) - continue; // Give up is reference is beyond 4K page size + // Give up if reference is beyond page size. + if (MacroAssembler::needs_explicit_null_check(offset)) + continue; + // Give up if base is a decode node and the heap base is not protected. + if (base->is_Mach() && base->as_Mach()->ideal_Opcode() == Op_DecodeN && + !Universe::narrow_oop_use_implicit_null_checks()) + continue; } } diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/opto/library_call.cpp --- a/hotspot/src/share/vm/opto/library_call.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/opto/library_call.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -2394,10 +2394,10 @@ // the barriers get omitted and the unsafe reference begins to "pollute" // the alias analysis of the rest of the graph, either Compile::can_alias // or Compile::must_alias will throw a diagnostic assert.) - bool need_mem_bar; + bool need_mem_bar = false; switch (kind) { case Relaxed: - need_mem_bar = mismatched || can_access_non_heap; + need_mem_bar = mismatched && !adr_type->isa_aryptr(); break; case Opaque: // Opaque uses CPUOrder membars for protection against code movement. diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/opto/loopTransform.cpp --- a/hotspot/src/share/vm/opto/loopTransform.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/opto/loopTransform.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -3174,6 +3174,11 @@ return false; } + Node* exit = head->loopexit()->proj_out(0); + if (exit == NULL) { + return false; + } + #ifndef PRODUCT if (TraceLoopOpts) { tty->print("ArrayFill "); @@ -3281,7 +3286,6 @@ */ // Redirect the old control and memory edges that are outside the loop. - Node* exit = head->loopexit()->proj_out(0); // Sometimes the memory phi of the head is used as the outgoing // state of the loop. It's safe in this case to replace it with the // result_mem. diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/opto/parse2.cpp --- a/hotspot/src/share/vm/opto/parse2.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/opto/parse2.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -826,6 +826,9 @@ ciMethodData* methodData = method()->method_data(); if (!methodData->is_mature()) return PROB_UNKNOWN; ciProfileData* data = methodData->bci_to_data(bci()); + if (data == NULL) { + return PROB_UNKNOWN; + } if (!data->is_JumpData()) return PROB_UNKNOWN; // get taken and not taken values @@ -917,8 +920,8 @@ // of the OSR-ed method, and we want to deopt to gather more stats. // If you have ANY counts, then this loop is simply 'cold' relative // to the OSR loop. - if (data->as_BranchData()->taken() + - data->as_BranchData()->not_taken() == 0 ) { + if (data == NULL || + (data->as_BranchData()->taken() + data->as_BranchData()->not_taken() == 0)) { // This is the only way to return PROB_UNKNOWN: return PROB_UNKNOWN; } diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/opto/stringopts.cpp --- a/hotspot/src/share/vm/opto/stringopts.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/opto/stringopts.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -891,8 +891,9 @@ ctrl_path.push(cn); ctrl_path.push(cn->proj_out(0)); ctrl_path.push(cn->proj_out(0)->unique_out()); - if (cn->proj_out(0)->unique_out()->as_Catch()->proj_out(0) != NULL) { - ctrl_path.push(cn->proj_out(0)->unique_out()->as_Catch()->proj_out(0)); + Node* catchproj = cn->proj_out(0)->unique_out()->as_Catch()->proj_out(0); + if (catchproj != NULL) { + ctrl_path.push(catchproj); } } else { ShouldNotReachHere(); diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/prims/jni.cpp --- a/hotspot/src/share/vm/prims/jni.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/prims/jni.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -932,8 +932,7 @@ inline void get_long() { _arguments->push_long(va_arg(_ap, jlong)); } inline void get_float() { _arguments->push_float((jfloat)va_arg(_ap, jdouble)); } // float is coerced to double w/ va_arg inline void get_double() { _arguments->push_double(va_arg(_ap, jdouble)); } - inline void get_object() { jobject l = va_arg(_ap, jobject); - _arguments->push_oop(Handle((oop *)l, false)); } + inline void get_object() { _arguments->push_jobject(va_arg(_ap, jobject)); } inline void set_ap(va_list rap) { va_copy(_ap, rap); @@ -1022,7 +1021,7 @@ inline void get_long() { _arguments->push_long((_ap++)->j); } inline void get_float() { _arguments->push_float((_ap++)->f); } inline void get_double() { _arguments->push_double((_ap++)->d);} - inline void get_object() { _arguments->push_oop(Handle((oop *)(_ap++)->l, false)); } + inline void get_object() { _arguments->push_jobject((_ap++)->l); } inline void set_ap(const jvalue *rap) { _ap = rap; } diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/prims/jvmtiEnv.cpp --- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -1793,6 +1793,13 @@ } } + if (initial_object != NULL) { + oop init_obj = JNIHandles::resolve_external_guard(initial_object); + if (init_obj == NULL) { + return JVMTI_ERROR_INVALID_OBJECT; + } + } + Thread *thread = Thread::current(); HandleMark hm(thread); diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/runtime/arguments.cpp --- a/hotspot/src/share/vm/runtime/arguments.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/runtime/arguments.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -2863,6 +2863,10 @@ if (res != JNI_OK) { return res; } + } else if (match_option(option, "--permit-illegal-access")) { + if (!create_property("jdk.module.permitIllegalAccess", "true", ExternalProperty)) { + return JNI_ENOMEM; + } // -agentlib and -agentpath } else if (match_option(option, "-agentlib:", &tail) || (is_absolute_path = match_option(option, "-agentpath:", &tail))) { @@ -3105,6 +3109,7 @@ // -Xprof } else if (match_option(option, "-Xprof")) { #if INCLUDE_FPROF + log_warning(arguments)("Option -Xprof was deprecated in version 9 and will likely be removed in a future release."); _has_profile = true; #else // INCLUDE_FPROF jio_fprintf(defaultStream::error_stream(), diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/runtime/java.cpp --- a/hotspot/src/share/vm/runtime/java.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/runtime/java.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -618,6 +618,13 @@ } } +void vm_exit_during_initialization() { + vm_notify_during_shutdown(NULL, NULL); + + // Failure during initialization, we don't want to dump core + vm_abort(false); +} + void vm_exit_during_initialization(Handle exception) { tty->print_cr("Error occurred during initialization of VM"); // If there are exceptions on this thread it must be cleared diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/runtime/java.hpp --- a/hotspot/src/share/vm/runtime/java.hpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/runtime/java.hpp Thu Apr 06 22:13:13 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, 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 @@ -45,6 +45,7 @@ extern void notify_vm_shutdown(); // VM exit if error occurs during initialization of VM +extern void vm_exit_during_initialization(); extern void vm_exit_during_initialization(Handle exception); extern void vm_exit_during_initialization(Symbol* exception_name, const char* message); extern void vm_exit_during_initialization(const char* error, const char* message = NULL); diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/runtime/javaCalls.cpp --- a/hotspot/src/share/vm/runtime/javaCalls.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/runtime/javaCalls.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -328,9 +328,9 @@ // Verify the arguments if (CheckJNICalls) { - args->verify(method, result->get_type(), thread); + args->verify(method, result->get_type()); } - else debug_only(args->verify(method, result->get_type(), thread)); + else debug_only(args->verify(method, result->get_type())); #if INCLUDE_JVMCI } #else @@ -442,12 +442,43 @@ //-------------------------------------------------------------------------------------- // 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 @@ 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 @@ 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 @@ }; -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 @@ // Check that oop information is correct Symbol* signature = method->signature(); - SignatureChekker sc(signature, return_type, method->is_static(),_is_oop, _value, thread); + SignatureChekker sc(signature, + return_type, + method->is_static(), + _value_state, + _value); sc.iterate_parameters(); sc.check_doing_return(true); sc.iterate_returntype(); diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/runtime/javaCalls.hpp --- a/hotspot/src/share/vm/runtime/javaCalls.hpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/runtime/javaCalls.hpp Thu Apr 06 22:13:13 2017 +0000 @@ -80,11 +80,11 @@ _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 @@ 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 @@ 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 @@ 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 @@ } #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_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_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) { _is_oop[_size] = false; _is_oop[_size + 1] = false; - JNITypes::put_long(l, _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) { _is_oop[_size] = false; - JNITypes::put_float(f, _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 @@ 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 @@ 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 -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/runtime/jniHandles.cpp --- a/hotspot/src/share/vm/runtime/jniHandles.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/runtime/jniHandles.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -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 res = NULL; if (!obj.is_null()) { // ignore null handles - MutexLocker ml(JNIGlobalHandle_lock); - assert(Universe::heap()->is_in_reserved(obj()), "sanity check"); - res = _weak_global_handles->allocate_handle(obj()); + { + MutexLocker ml(JNIGlobalHandle_lock); + assert(Universe::heap()->is_in_reserved(obj()), "sanity check"); + res = _weak_global_handles->allocate_handle(obj()); + } + // Add weak tag. + assert(is_ptr_aligned(res, weak_tag_alignment), "invariant"); + char* tptr = reinterpret_cast(res) + weak_tag_value; + res = reinterpret_cast(tptr); } else { CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops()); } return res; } +template +oop JNIHandles::resolve_jweak(jweak handle) { + assert(is_jweak(handle), "precondition"); + oop result = jweak_ref(handle); + result = guard_value(result); +#if INCLUDE_ALL_GCS + if (result != NULL && UseG1GC) { + G1SATBCardTableModRefBS::enqueue(result); + } +#endif // INCLUDE_ALL_GCS + return result; +} + +template oop JNIHandles::resolve_jweak(jweak); +template oop JNIHandles::resolve_jweak(jweak); void JNIHandles::destroy_global(jobject handle) { if (handle != NULL) { assert(is_global_handle(handle), "Invalid delete of global JNI handle"); - *((oop*)handle) = deleted_handle(); // Mark the handle as deleted, allocate will reuse it + jobject_ref(handle) = deleted_handle(); } } void JNIHandles::destroy_weak_global(jobject handle) { if (handle != NULL) { - assert(!CheckJNICalls || is_weak_global_handle(handle), "Invalid delete of weak global JNI handle"); - *((oop*)handle) = deleted_handle(); // Mark the handle as deleted, allocate will reuse it + jweak_ref(handle) = deleted_handle(); } } diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/runtime/jniHandles.hpp --- a/hotspot/src/share/vm/runtime/jniHandles.hpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/runtime/jniHandles.hpp Thu Apr 06 22:13:13 2017 +0000 @@ -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 @@ 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 @@ #endif }; +inline bool JNIHandles::is_jweak(jobject handle) { + STATIC_ASSERT(weak_tag_size == 1); + STATIC_ASSERT(weak_tag_value == 1); + return (reinterpret_cast(handle) & weak_tag_mask) != 0; +} + +inline oop& JNIHandles::jobject_ref(jobject handle) { + assert(!is_jweak(handle), "precondition"); + return *reinterpret_cast(handle); +} + +inline oop& JNIHandles::jweak_ref(jobject handle) { + assert(is_jweak(handle), "precondition"); + char* ptr = reinterpret_cast(handle) - weak_tag_value; + return *reinterpret_cast(ptr); +} + +// external_guard is true if called from resolve_external_guard. +// Treat deleted (and possibly zapped) as NULL for external_guard, +// else as (asserted) error. +template +inline oop JNIHandles::guard_value(oop value) { + if (!external_guard) { + assert(value != badJNIHandle, "Pointing to zapped jni handle area"); + assert(value != deleted_handle(), "Used a deleted global handle"); + } else if ((value == badJNIHandle) || (value == deleted_handle())) { + value = NULL; + } + return value; +} + +// external_guard is true if called from resolve_external_guard. +template +inline oop JNIHandles::resolve_impl(jobject handle) { + assert(handle != NULL, "precondition"); + oop result; + if (is_jweak(handle)) { // Unlikely + result = resolve_jweak(handle); + } else { + result = jobject_ref(handle); + // Construction of jobjects canonicalize a null value into a null + // jobject, so for non-jweak the pointee should never be null. + assert(external_guard || result != NULL, + "Invalid value read from jni handle"); + result = guard_value(result); + } + return result; +} inline oop JNIHandles::resolve(jobject handle) { - oop result = (handle == NULL ? (oop)NULL : *(oop*)handle); - assert(result != NULL || (handle == NULL || !CheckJNICalls || is_weak_global_handle(handle)), "Invalid value read from jni handle"); - assert(result != badJNIHandle, "Pointing to zapped jni handle area"); + oop result = NULL; + if (handle != NULL) { + result = resolve_impl(handle); + } return result; -}; - +} +// Resolve some erroneous cases to NULL, rather than treating them as +// possibly unchecked errors. In particular, deleted handles are +// treated as NULL (though a deleted and later reallocated handle +// isn't detected). inline oop JNIHandles::resolve_external_guard(jobject handle) { - if (handle == NULL) return NULL; - oop result = *(oop*)handle; - if (result == NULL || result == badJNIHandle) return NULL; + oop result = NULL; + if (handle != NULL) { + result = resolve_impl(handle); + } return result; -}; - +} inline oop JNIHandles::resolve_non_null(jobject handle) { assert(handle != NULL, "JNI handle should not be null"); - oop result = *(oop*)handle; - assert(result != NULL, "Invalid value read from jni handle"); - assert(result != badJNIHandle, "Pointing to zapped jni handle area"); - // Don't let that private _deleted_handle object escape into the wild. - assert(result != deleted_handle(), "Used a deleted global handle."); + oop result = resolve_impl(handle); + assert(result != NULL, "NULL read from jni handle"); return result; -}; +} inline void JNIHandles::destroy_local(jobject handle) { if (handle != NULL) { - *((oop*)handle) = deleted_handle(); // Mark the handle as deleted, allocate will reuse it + jobject_ref(handle) = deleted_handle(); } } diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/runtime/mutexLocker.cpp --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -181,13 +181,13 @@ } if (UseG1GC) { - def(SATB_Q_FL_lock , PaddedMutex , special, true, Monitor::_safepoint_check_never); - def(SATB_Q_CBL_mon , PaddedMonitor, nonleaf, true, Monitor::_safepoint_check_never); - def(Shared_SATB_Q_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_never); + def(SATB_Q_FL_lock , PaddedMutex , special , true, Monitor::_safepoint_check_never); + def(SATB_Q_CBL_mon , PaddedMonitor, leaf - 1 , true, Monitor::_safepoint_check_never); + def(Shared_SATB_Q_lock , PaddedMutex , leaf - 1 , true, Monitor::_safepoint_check_never); - def(DirtyCardQ_FL_lock , PaddedMutex , special, true, Monitor::_safepoint_check_never); - def(DirtyCardQ_CBL_mon , PaddedMonitor, nonleaf, true, Monitor::_safepoint_check_never); - def(Shared_DirtyCardQ_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_never); + def(DirtyCardQ_FL_lock , PaddedMutex , special , true, Monitor::_safepoint_check_never); + def(DirtyCardQ_CBL_mon , PaddedMonitor, leaf - 1 , true, Monitor::_safepoint_check_never); + def(Shared_DirtyCardQ_lock , PaddedMutex , leaf - 1 , true, Monitor::_safepoint_check_never); def(FreeList_lock , PaddedMutex , leaf , true, Monitor::_safepoint_check_never); def(SecondaryFreeList_lock , PaddedMonitor, leaf , true, Monitor::_safepoint_check_never); diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/runtime/thread.cpp --- a/hotspot/src/share/vm/runtime/thread.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/runtime/thread.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -3408,9 +3408,16 @@ Klass* klass = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(), true, CHECK); - JavaValue result(T_VOID); + JavaValue result(T_INT); + JavaCallArguments args; + args.push_int(DisplayVMOutputToStderr); + args.push_int(log_is_enabled(Debug, init)); // print stack trace if exception thrown JavaCalls::call_static(&result, klass, vmSymbols::initPhase2_name(), - vmSymbols::void_method_signature(), CHECK); + vmSymbols::boolean_boolean_int_signature(), &args, CHECK); + if (result.get_jint() != JNI_OK) { + vm_exit_during_initialization(); // no message or exception + } + universe_post_module_init(); } diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/shark/sharkNativeWrapper.cpp --- a/hotspot/src/share/vm/shark/sharkNativeWrapper.cpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/shark/sharkNativeWrapper.cpp Thu Apr 06 22:13:13 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright 2009, 2010 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -300,6 +300,7 @@ 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 -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/utilities/debug.hpp --- a/hotspot/src/share/vm/utilities/debug.hpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/utilities/debug.hpp Thu Apr 06 22:13:13 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -140,6 +140,9 @@ // For backward compatibility. #define assert(p, ...) vmassert(p, __VA_ARGS__) +#ifndef ASSERT +#define vmassert_status(p, status, msg) +#else // This version of vmassert is for use with checking return status from // library calls that return actual error values eg. EINVAL, // ENOMEM etc, rather than returning -1 and setting errno. @@ -155,6 +158,7 @@ BREAKPOINT; \ } \ } while (0) +#endif // For backward compatibility. #define assert_status(p, status, msg) vmassert_status(p, status, msg) diff -r da05330bbc7b -r 7a0ae73888ff hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp --- a/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp Thu Apr 06 22:13:13 2017 +0000 @@ -1,6 +1,6 @@ /* * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2016 SAP SE. 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 @@ -153,6 +153,9 @@ // offset_of as it is defined for gcc. #define offset_of(klass,field) (size_t)((intx)&(((klass*)16)->field) - 16) +// AIX 5.3 has buggy __thread support. (see JDK-8176442). +#define USE_LIBRARY_BASED_TLS_ONLY 1 + #ifndef USE_LIBRARY_BASED_TLS_ONLY #define THREAD_LOCAL_DECL __thread #endif diff -r da05330bbc7b -r 7a0ae73888ff hotspot/test/compiler/arraycopy/TestObjectArrayCopy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/arraycopy/TestObjectArrayCopy.java Thu Apr 06 22:13:13 2017 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017, SAP SE 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 8176505 + * @summary Wrong assertion 'should be an array copy/clone' in arraycopynode.cpp + * + * @run main/othervm -Xbatch -XX:-UseOnStackReplacement compiler.arraycopy.TestObjectArrayCopy + * + * @author Volker Simonis + */ + +package compiler.arraycopy; + +public class TestObjectArrayCopy { + + public static boolean crash(Object src) { + String[] dst = new String[1]; + System.arraycopy(src, 0, dst, 0, 1); + return dst[0] == null; + } + + public static void main(String[] args) { + String[] sa = new String[1]; + for (int i = 0; i < 20_000; i++) { + crash(sa); + } + } +} diff -r da05330bbc7b -r 7a0ae73888ff hotspot/test/compiler/c2/TestNPEHeapBased.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/c2/TestNPEHeapBased.java Thu Apr 06 22:13:13 2017 +0000 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 + * 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 8176518 + * @summary Invalid ImplicitNullChecks when heap base not protected + * + * @run main/othervm -XX:ObjectAlignmentInBytes=16 -XX:HeapBaseMinAddress=64g + * -XX:-TieredCompilation -Xbatch + * compiler.c2.TestNPEHeapBased + * @requires vm.bits == "64" + */ + +package compiler.c2; +public class TestNPEHeapBased { + + TestNPEHeapBased instance = null; + int i = 0; + + public void set_i(int value) { + instance.i = value; + } + + + static final int loop_cnt = 200000; + + public static void main(String args[]){ + TestNPEHeapBased xyz = new TestNPEHeapBased(); + xyz.instance = xyz; + for (int x = 0; x < loop_cnt; x++) xyz.set_i(x); + xyz.instance = null; + try { + xyz.set_i(0); + } catch (NullPointerException npe) { + System.out.println("Got expected NullPointerException:"); + npe.printStackTrace(); + return; + } + throw new InternalError("NullPointerException is missing!"); + } + +} diff -r da05330bbc7b -r 7a0ae73888ff hotspot/test/compiler/loopopts/TestLoopPeeling.java --- a/hotspot/test/compiler/loopopts/TestLoopPeeling.java Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/test/compiler/loopopts/TestLoopPeeling.java Thu Apr 06 22:13:13 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8078262 + * @bug 8078262 8177095 * @summary Tests correct dominator information after loop peeling. * * @run main/othervm -Xcomp @@ -40,14 +40,16 @@ public static void main(String args[]) { TestLoopPeeling test = new TestLoopPeeling(); try { - test.testArrayAccess(0, 1); + test.testArrayAccess1(0, 1); + test.testArrayAccess2(0); + test.testArrayAccess3(0, false); test.testArrayAllocation(0, 1); } catch (Exception e) { // Ignore exceptions } } - public void testArrayAccess(int index, int inc) { + public void testArrayAccess1(int index, int inc) { int storeIndex = -1; for (; index < 10; index += inc) { @@ -63,7 +65,7 @@ if (index == 42) { // This store and the corresponding range check are moved out of the - // loop and both used after old loop and the peeled iteration exit. + // loop and both used after main loop and the peeled iteration exit. // For the peeled iteration, storeIndex is always -1 and the ConvI2L // is replaced by TOP. However, the range check is not folded because // we don't do the split if optimization in PhaseIdealLoop2. @@ -77,6 +79,44 @@ } } + public int testArrayAccess2(int index) { + // Load1 and the corresponding range check are moved out of the loop + // and both are used after the main loop and the peeled iteration exit. + // For the peeled iteration, storeIndex is always Integer.MIN_VALUE and + // for the main loop it is 0. Hence, the merging phi has type int:<=0. + // Load1 reads the array at index ConvI2L(CastII(AddI(storeIndex, -1))) + // where the CastII is range check dependent and has type int:>=0. + // The CastII gets pushed through the AddI and its type is changed to int:>=1 + // which does not overlap with the input type of storeIndex (int:<=0). + // The CastII is replaced by TOP causing a cascade of other eliminations. + // Since the control path through the range check CmpU(AddI(storeIndex, -1)) + // is not eliminated, the graph is in a corrupted state. We fail once we merge + // with the result of Load2 because we get data from a non-dominating region. + int storeIndex = Integer.MIN_VALUE; + for (; index < 10; ++index) { + if (index == 42) { + return array[storeIndex-1]; // Load1 + } + storeIndex = 0; + } + return array[42]; // Load2 + } + + public int testArrayAccess3(int index, boolean b) { + // Same as testArrayAccess2 but manifests as crash in register allocator. + int storeIndex = Integer.MIN_VALUE; + for (; index < 10; ++index) { + if (b) { + return 0; + } + if (index == 42) { + return array[storeIndex-1]; // Load1 + } + storeIndex = 0; + } + return array[42]; // Load2 + } + public byte[] testArrayAllocation(int index, int inc) { int allocationCount = -1; byte[] result; @@ -88,7 +128,7 @@ if (index == 42) { // This allocation and the corresponding size check are moved out of the - // loop and both used after old loop and the peeled iteration exit. + // loop and both used after main loop and the peeled iteration exit. // For the peeled iteration, allocationCount is always -1 and the ConvI2L // is replaced by TOP. However, the size check is not folded because // we don't do the split if optimization in PhaseIdealLoop2. diff -r da05330bbc7b -r 7a0ae73888ff hotspot/test/runtime/MinimalVM/JMX.java --- a/hotspot/test/runtime/MinimalVM/JMX.java Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/test/runtime/MinimalVM/JMX.java Thu Apr 06 22:13:13 2017 +0000 @@ -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 @@ -47,9 +47,8 @@ .shouldContain("-Dcom.sun.management is not supported in this VM.") .shouldHaveExitValue(1); - pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), Long.toString(ProcessTools.getProcessId()), "VM.print_threads"}); + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), "-l"}); new OutputAnalyzer(pb.start()) - .shouldContain("Could not find any processes matching ") - .shouldHaveExitValue(1); + .shouldNotMatch("^" + Long.toString(ProcessTools.getProcessId()) + "\\s+.*$"); } } diff -r da05330bbc7b -r 7a0ae73888ff hotspot/test/runtime/jni/CallWithJNIWeak/CallWithJNIWeak.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/jni/CallWithJNIWeak/CallWithJNIWeak.java Thu Apr 06 22:13:13 2017 +0000 @@ -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 -r da05330bbc7b -r 7a0ae73888ff hotspot/test/runtime/jni/CallWithJNIWeak/libCallWithJNIWeak.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/jni/CallWithJNIWeak/libCallWithJNIWeak.c Thu Apr 06 22:13:13 2017 +0000 @@ -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 -r da05330bbc7b -r 7a0ae73888ff hotspot/test/runtime/jni/ReturnJNIWeak/ReturnJNIWeak.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/jni/ReturnJNIWeak/ReturnJNIWeak.java Thu Apr 06 22:13:13 2017 +0000 @@ -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 -r da05330bbc7b -r 7a0ae73888ff hotspot/test/runtime/jni/ReturnJNIWeak/libReturnJNIWeak.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/jni/ReturnJNIWeak/libReturnJNIWeak.c Thu Apr 06 22:13:13 2017 +0000 @@ -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; +} diff -r da05330bbc7b -r 7a0ae73888ff hotspot/test/runtime/modules/IgnoreModulePropertiesTest.java --- a/hotspot/test/runtime/modules/IgnoreModulePropertiesTest.java Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/test/runtime/modules/IgnoreModulePropertiesTest.java Thu Apr 06 22:13:13 2017 +0000 @@ -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 @@ -44,7 +44,7 @@ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-D" + prop + "=" + value, "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("java version "); + output.shouldContain(" version "); output.shouldHaveExitValue(0); // Ensure that the property and its value aren't available. diff -r da05330bbc7b -r 7a0ae73888ff hotspot/test/serviceability/jvmti/GetNamedModule/libGetNamedModuleTest.c --- a/hotspot/test/serviceability/jvmti/GetNamedModule/libGetNamedModuleTest.c Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/test/serviceability/jvmti/GetNamedModule/libGetNamedModuleTest.c Thu Apr 06 22:13:13 2017 +0000 @@ -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 @@ -183,7 +183,7 @@ err = (*jvmti)->GetNamedModule(jvmti, loader, pkg_name, module_ptr); if (err != JVMTI_ERROR_NONE) { printf(" Error in GetNamedModule for package \"%s\": %s (%d)\n", - pkg_name, TranslateError(err), err); + name, TranslateError(err), err); return err; } printf(" returned module: %p\n", *module_ptr); diff -r da05330bbc7b -r 7a0ae73888ff hotspot/test/test_env.sh --- a/hotspot/test/test_env.sh Thu Apr 06 21:14:07 2017 +0000 +++ b/hotspot/test/test_env.sh Thu Apr 06 22:13:13 2017 +0000 @@ -214,6 +214,11 @@ then VM_CPU="aarch64" fi +grep "arm64" vm_version.out > ${NULL} +if [ $? = 0 ] +then + VM_CPU="aarch64" +fi export VM_TYPE VM_BITS VM_OS VM_CPU echo "VM_TYPE=${VM_TYPE}" echo "VM_BITS=${VM_BITS}"