8166188: G1 Needs pre barrier on dereference of weak JNI handles
Add low tag to jweaks and G1 barrier for jweak loads. Co-authored-by: Martin Doerr <martin.doerr@sap.com> Co-authored-by: Volker Simonis <volker.simonis@sap.com> Reviewed-by: mgerdin, mdoerr, pliden, dlong, dcubed, coleenp, aph, tschatzl
This commit is contained in:
parent
6a5e6f2ae1
commit
28477cf493
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
# Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
@ -48,6 +48,8 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC := \
|
|||||||
$(HOTSPOT_TOPDIR)/test/runtime/jni/PrivateInterfaceMethods \
|
$(HOTSPOT_TOPDIR)/test/runtime/jni/PrivateInterfaceMethods \
|
||||||
$(HOTSPOT_TOPDIR)/test/runtime/jni/ToStringInInterfaceTest \
|
$(HOTSPOT_TOPDIR)/test/runtime/jni/ToStringInInterfaceTest \
|
||||||
$(HOTSPOT_TOPDIR)/test/runtime/jni/CalleeSavedRegisters \
|
$(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/modules/getModuleJNI \
|
||||||
$(HOTSPOT_TOPDIR)/test/runtime/SameObject \
|
$(HOTSPOT_TOPDIR)/test/runtime/SameObject \
|
||||||
$(HOTSPOT_TOPDIR)/test/runtime/BoolReturn \
|
$(HOTSPOT_TOPDIR)/test/runtime/BoolReturn \
|
||||||
|
@ -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.
|
* Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
@ -2052,13 +2052,31 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
|||||||
|
|
||||||
__ reset_last_Java_frame(false);
|
__ 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) {
|
if (ret_type == T_OBJECT || ret_type == T_ARRAY) {
|
||||||
Label L;
|
Label done, not_weak;
|
||||||
__ cbz(r0, L);
|
__ cbz(r0, done); // Use NULL as-is.
|
||||||
__ ldr(r0, Address(r0, 0));
|
STATIC_ASSERT(JNIHandles::weak_tag_mask == 1u);
|
||||||
__ bind(L);
|
__ tbz(r0, 0, not_weak); // Test for jweak tag.
|
||||||
__ verify_oop(r0);
|
// 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) {
|
if (CheckJNICalls) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
@ -1399,13 +1399,32 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
|
|||||||
// and result handler will pick it up
|
// 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)));
|
__ adr(t, ExternalAddress(AbstractInterpreter::result_handler(T_OBJECT)));
|
||||||
__ cmp(t, result_handler);
|
__ cmp(t, result_handler);
|
||||||
__ br(Assembler::NE, no_oop);
|
__ br(Assembler::NE, no_oop);
|
||||||
// retrieve result
|
// Unbox oop result, e.g. JNIHandles::resolve result.
|
||||||
__ pop(ltos);
|
__ 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));
|
__ ldr(r0, Address(r0, 0));
|
||||||
__ bind(store_result);
|
__ bind(store_result);
|
||||||
__ str(r0, Address(rfp, frame::interpreter_frame_oop_temp_offset*wordSize));
|
__ str(r0, Address(rfp, frame::interpreter_frame_oop_temp_offset*wordSize));
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -476,185 +476,6 @@ void InterpreterMacroAssembler::set_card(Register card_table_base, Address card_
|
|||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
#if INCLUDE_ALL_GCS
|
|
||||||
|
|
||||||
// G1 pre-barrier.
|
|
||||||
// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
|
|
||||||
// If store_addr != noreg, then previous value is loaded from [store_addr];
|
|
||||||
// in such case store_addr and new_val registers are preserved;
|
|
||||||
// otherwise pre_val register is preserved.
|
|
||||||
void InterpreterMacroAssembler::g1_write_barrier_pre(Register store_addr,
|
|
||||||
Register new_val,
|
|
||||||
Register pre_val,
|
|
||||||
Register tmp1,
|
|
||||||
Register tmp2) {
|
|
||||||
Label done;
|
|
||||||
Label runtime;
|
|
||||||
|
|
||||||
if (store_addr != noreg) {
|
|
||||||
assert_different_registers(store_addr, new_val, pre_val, tmp1, tmp2, noreg);
|
|
||||||
} else {
|
|
||||||
assert (new_val == noreg, "should be");
|
|
||||||
assert_different_registers(pre_val, tmp1, tmp2, noreg);
|
|
||||||
}
|
|
||||||
|
|
||||||
Address in_progress(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
|
|
||||||
SATBMarkQueue::byte_offset_of_active()));
|
|
||||||
Address index(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
|
|
||||||
SATBMarkQueue::byte_offset_of_index()));
|
|
||||||
Address buffer(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
|
|
||||||
SATBMarkQueue::byte_offset_of_buf()));
|
|
||||||
|
|
||||||
// Is marking active?
|
|
||||||
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "adjust this code");
|
|
||||||
ldrb(tmp1, in_progress);
|
|
||||||
cbz(tmp1, done);
|
|
||||||
|
|
||||||
// Do we need to load the previous value?
|
|
||||||
if (store_addr != noreg) {
|
|
||||||
load_heap_oop(pre_val, Address(store_addr, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is the previous value null?
|
|
||||||
cbz(pre_val, done);
|
|
||||||
|
|
||||||
// Can we store original value in the thread's buffer?
|
|
||||||
// Is index == 0?
|
|
||||||
// (The index field is typed as size_t.)
|
|
||||||
|
|
||||||
ldr(tmp1, index); // tmp1 := *index_adr
|
|
||||||
ldr(tmp2, buffer);
|
|
||||||
|
|
||||||
subs(tmp1, tmp1, wordSize); // tmp1 := tmp1 - wordSize
|
|
||||||
b(runtime, lt); // If negative, goto runtime
|
|
||||||
|
|
||||||
str(tmp1, index); // *index_adr := tmp1
|
|
||||||
|
|
||||||
// Record the previous value
|
|
||||||
str(pre_val, Address(tmp2, tmp1));
|
|
||||||
b(done);
|
|
||||||
|
|
||||||
bind(runtime);
|
|
||||||
|
|
||||||
// save the live input values
|
|
||||||
#ifdef AARCH64
|
|
||||||
if (store_addr != noreg) {
|
|
||||||
raw_push(store_addr, new_val);
|
|
||||||
} else {
|
|
||||||
raw_push(pre_val, ZR);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (store_addr != noreg) {
|
|
||||||
// avoid raw_push to support any ordering of store_addr and new_val
|
|
||||||
push(RegisterSet(store_addr) | RegisterSet(new_val));
|
|
||||||
} else {
|
|
||||||
push(pre_val);
|
|
||||||
}
|
|
||||||
#endif // AARCH64
|
|
||||||
|
|
||||||
if (pre_val != R0) {
|
|
||||||
mov(R0, pre_val);
|
|
||||||
}
|
|
||||||
mov(R1, Rthread);
|
|
||||||
|
|
||||||
call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), R0, R1);
|
|
||||||
|
|
||||||
#ifdef AARCH64
|
|
||||||
if (store_addr != noreg) {
|
|
||||||
raw_pop(store_addr, new_val);
|
|
||||||
} else {
|
|
||||||
raw_pop(pre_val, ZR);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (store_addr != noreg) {
|
|
||||||
pop(RegisterSet(store_addr) | RegisterSet(new_val));
|
|
||||||
} else {
|
|
||||||
pop(pre_val);
|
|
||||||
}
|
|
||||||
#endif // AARCH64
|
|
||||||
|
|
||||||
bind(done);
|
|
||||||
}
|
|
||||||
|
|
||||||
// G1 post-barrier.
|
|
||||||
// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
|
|
||||||
void InterpreterMacroAssembler::g1_write_barrier_post(Register store_addr,
|
|
||||||
Register new_val,
|
|
||||||
Register tmp1,
|
|
||||||
Register tmp2,
|
|
||||||
Register tmp3) {
|
|
||||||
|
|
||||||
Address queue_index(Rthread, in_bytes(JavaThread::dirty_card_queue_offset() +
|
|
||||||
DirtyCardQueue::byte_offset_of_index()));
|
|
||||||
Address buffer(Rthread, in_bytes(JavaThread::dirty_card_queue_offset() +
|
|
||||||
DirtyCardQueue::byte_offset_of_buf()));
|
|
||||||
|
|
||||||
BarrierSet* bs = Universe::heap()->barrier_set();
|
|
||||||
CardTableModRefBS* ct = (CardTableModRefBS*)bs;
|
|
||||||
Label done;
|
|
||||||
Label runtime;
|
|
||||||
|
|
||||||
// Does store cross heap regions?
|
|
||||||
|
|
||||||
eor(tmp1, store_addr, new_val);
|
|
||||||
#ifdef AARCH64
|
|
||||||
logical_shift_right(tmp1, tmp1, HeapRegion::LogOfHRGrainBytes);
|
|
||||||
cbz(tmp1, done);
|
|
||||||
#else
|
|
||||||
movs(tmp1, AsmOperand(tmp1, lsr, HeapRegion::LogOfHRGrainBytes));
|
|
||||||
b(done, eq);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// crosses regions, storing NULL?
|
|
||||||
|
|
||||||
cbz(new_val, done);
|
|
||||||
|
|
||||||
// storing region crossing non-NULL, is card already dirty?
|
|
||||||
const Register card_addr = tmp1;
|
|
||||||
assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
|
|
||||||
|
|
||||||
mov_address(tmp2, (address)ct->byte_map_base, symbolic_Relocation::card_table_reference);
|
|
||||||
add(card_addr, tmp2, AsmOperand(store_addr, lsr, CardTableModRefBS::card_shift));
|
|
||||||
|
|
||||||
ldrb(tmp2, Address(card_addr));
|
|
||||||
cmp(tmp2, (int)G1SATBCardTableModRefBS::g1_young_card_val());
|
|
||||||
b(done, eq);
|
|
||||||
|
|
||||||
membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp2);
|
|
||||||
|
|
||||||
assert(CardTableModRefBS::dirty_card_val() == 0, "adjust this code");
|
|
||||||
ldrb(tmp2, Address(card_addr));
|
|
||||||
cbz(tmp2, done);
|
|
||||||
|
|
||||||
// storing a region crossing, non-NULL oop, card is clean.
|
|
||||||
// dirty card and log.
|
|
||||||
|
|
||||||
strb(zero_register(tmp2), Address(card_addr));
|
|
||||||
|
|
||||||
ldr(tmp2, queue_index);
|
|
||||||
ldr(tmp3, buffer);
|
|
||||||
|
|
||||||
subs(tmp2, tmp2, wordSize);
|
|
||||||
b(runtime, lt); // go to runtime if now negative
|
|
||||||
|
|
||||||
str(tmp2, queue_index);
|
|
||||||
|
|
||||||
str(card_addr, Address(tmp3, tmp2));
|
|
||||||
b(done);
|
|
||||||
|
|
||||||
bind(runtime);
|
|
||||||
|
|
||||||
if (card_addr != R0) {
|
|
||||||
mov(R0, card_addr);
|
|
||||||
}
|
|
||||||
mov(R1, Rthread);
|
|
||||||
call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), R0, R1);
|
|
||||||
|
|
||||||
bind(done);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // INCLUDE_ALL_GCS
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
// Java Expression Stack
|
// Java Expression Stack
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -146,27 +146,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
|||||||
|
|
||||||
void set_card(Register card_table_base, Address card_table_addr, Register tmp);
|
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_ptr(Register r);
|
||||||
void pop_i(Register r = R0_tos);
|
void pop_i(Register r = R0_tos);
|
||||||
#ifdef AARCH64
|
#ifdef AARCH64
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -2211,6 +2211,219 @@ void MacroAssembler::biased_locking_exit(Register obj_reg, Register tmp_reg, Lab
|
|||||||
b(done, eq);
|
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
|
#ifdef AARCH64
|
||||||
|
|
||||||
void MacroAssembler::load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed) {
|
void MacroAssembler::load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed) {
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -402,6 +402,29 @@ public:
|
|||||||
void biased_locking_enter_with_cas(Register obj_reg, Register old_mark_reg, Register new_mark_reg,
|
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);
|
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
|
#ifndef AARCH64
|
||||||
void nop() {
|
void nop() {
|
||||||
mov(R0, R0);
|
mov(R0, R0);
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -1732,14 +1732,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
|||||||
case T_FLOAT : // fall through
|
case T_FLOAT : // fall through
|
||||||
case T_DOUBLE : /* nothing to do */ break;
|
case T_DOUBLE : /* nothing to do */ break;
|
||||||
case T_OBJECT : // fall through
|
case T_OBJECT : // fall through
|
||||||
case T_ARRAY : {
|
case T_ARRAY : break; // See JNIHandles::resolve below
|
||||||
Label L;
|
|
||||||
__ cbz(R0, L);
|
|
||||||
__ ldr(R0, Address(R0));
|
|
||||||
__ verify_oop(R0);
|
|
||||||
__ bind(L);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
@ -1748,14 +1741,15 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
|||||||
if (CheckJNICalls) {
|
if (CheckJNICalls) {
|
||||||
__ str(__ zero_register(Rtemp), Address(Rthread, JavaThread::pending_jni_exception_check_fn_offset()));
|
__ str(__ zero_register(Rtemp), Address(Rthread, JavaThread::pending_jni_exception_check_fn_offset()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unhandle the result
|
|
||||||
if (ret_type == T_OBJECT || ret_type == T_ARRAY) {
|
|
||||||
__ cmp(R0, 0);
|
|
||||||
__ ldr(R0, Address(R0), ne);
|
|
||||||
}
|
|
||||||
#endif // AARCH64
|
#endif // AARCH64
|
||||||
|
|
||||||
|
// Unbox oop result, e.g. JNIHandles::resolve value in R0.
|
||||||
|
if (ret_type == T_OBJECT || ret_type == T_ARRAY) {
|
||||||
|
__ resolve_jobject(R0, // value
|
||||||
|
Rtemp, // tmp1
|
||||||
|
R1_tmp); // tmp2
|
||||||
|
}
|
||||||
|
|
||||||
// Any exception pending?
|
// Any exception pending?
|
||||||
__ ldr(Rtemp, Address(Rthread, Thread::pending_exception_offset()));
|
__ ldr(Rtemp, Address(Rthread, Thread::pending_exception_offset()));
|
||||||
__ mov(SP, FP);
|
__ mov(SP, FP);
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -1240,28 +1240,25 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
|
|||||||
__ str(__ zero_register(Rtemp), Address(Rthread, JavaThread::pending_jni_exception_check_fn_offset()));
|
__ 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.
|
||||||
#ifdef AARCH64
|
|
||||||
{
|
{
|
||||||
Label L, Lnull;
|
Label Lnot_oop;
|
||||||
|
#ifdef AARCH64
|
||||||
__ mov_slow(Rtemp, AbstractInterpreter::result_handler(T_OBJECT));
|
__ mov_slow(Rtemp, AbstractInterpreter::result_handler(T_OBJECT));
|
||||||
__ cmp(Rresult_handler, Rtemp);
|
__ cmp(Rresult_handler, Rtemp);
|
||||||
__ b(L, ne);
|
__ b(Lnot_oop, ne);
|
||||||
__ cbz(Rsaved_result, Lnull);
|
#else // !AARCH64
|
||||||
__ ldr(Rsaved_result, Address(Rsaved_result));
|
// For ARM32, Rresult_handler is -1 for oop result, 0 otherwise.
|
||||||
__ bind(Lnull);
|
__ cbz(Rresult_handler, Lnot_oop);
|
||||||
// Store oop on the stack for GC
|
#endif // !AARCH64
|
||||||
__ str(Rsaved_result, Address(FP, frame::interpreter_frame_oop_temp_offset * wordSize));
|
Register value = AARCH64_ONLY(Rsaved_result) NOT_AARCH64(Rsaved_result_lo);
|
||||||
__ bind(L);
|
__ 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
|
#ifdef AARCH64
|
||||||
// Restore SP (drop native parameters area), to keep SP in sync with extended_sp in frame
|
// Restore SP (drop native parameters area), to keep SP in sync with extended_sp in frame
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2012, 2015 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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -171,10 +171,7 @@ BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result)
|
|||||||
switch (method->result_type()) {
|
switch (method->result_type()) {
|
||||||
case T_OBJECT:
|
case T_OBJECT:
|
||||||
case T_ARRAY: {
|
case T_ARRAY: {
|
||||||
oop* obj_p = *(oop**)lresult;
|
*oop_result = JNIHandles::resolve(*(jobject*)lresult);
|
||||||
oop obj = (obj_p == NULL) ? (oop)NULL : *obj_p;
|
|
||||||
assert(obj == NULL || Universe::heap()->is_in(obj), "sanity check");
|
|
||||||
*oop_result = obj;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// We use std/stfd to store the values.
|
// We use std/stfd to store the values.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2012, 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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -3033,6 +3033,34 @@ void MacroAssembler::card_table_write(jbyte* byte_map_base, Register Rtmp, Regis
|
|||||||
stbx(R0, Rtmp, Robj);
|
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
|
#if INCLUDE_ALL_GCS
|
||||||
// General G1 pre-barrier generator.
|
// General G1 pre-barrier generator.
|
||||||
// Goal: record the previous value if it is not null.
|
// Goal: record the previous value if it is not null.
|
||||||
@ -3094,7 +3122,7 @@ void MacroAssembler::g1_write_barrier_pre(Register Robj, RegisterOrConstant offs
|
|||||||
|
|
||||||
bind(runtime);
|
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) {
|
if (needs_frame) {
|
||||||
save_LR_CR(Rtmp1);
|
save_LR_CR(Rtmp1);
|
||||||
push_frame_reg_args(0, Rtmp2);
|
push_frame_reg_args(0, Rtmp2);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2002, 2017, 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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -649,6 +649,8 @@ class MacroAssembler: public Assembler {
|
|||||||
void card_write_barrier_post(Register Rstore_addr, Register Rnew_val, Register Rtmp);
|
void card_write_barrier_post(Register Rstore_addr, Register Rnew_val, Register Rtmp);
|
||||||
void card_table_write(jbyte* byte_map_base, Register Rtmp, Register Robj);
|
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
|
#if INCLUDE_ALL_GCS
|
||||||
// General G1 pre-barrier generator.
|
// General G1 pre-barrier generator.
|
||||||
void g1_write_barrier_pre(Register Robj, RegisterOrConstant offset, Register Rpre_val,
|
void g1_write_barrier_pre(Register Robj, RegisterOrConstant offset, Register Rpre_val,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2012, 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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -2477,16 +2477,11 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
|
|||||||
|
|
||||||
__ reset_last_Java_frame();
|
__ reset_last_Java_frame();
|
||||||
|
|
||||||
// Unpack oop result.
|
// Unbox oop result, e.g. JNIHandles::resolve value.
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
if (ret_type == T_OBJECT || ret_type == T_ARRAY) {
|
if (ret_type == T_OBJECT || ret_type == T_ARRAY) {
|
||||||
Label skip_unboxing;
|
__ resolve_jobject(R3_RET, r_temp_1, r_temp_2, /* needs_frame */ false); // kills R31
|
||||||
__ cmpdi(CCR0, R3_RET, 0);
|
|
||||||
__ beq(CCR0, skip_unboxing);
|
|
||||||
__ ld(R3_RET, 0, R3_RET);
|
|
||||||
__ bind(skip_unboxing);
|
|
||||||
__ verify_oop(R3_RET);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CheckJNICalls) {
|
if (CheckJNICalls) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2015, 2016 SAP SE. All rights reserved.
|
* Copyright (c) 2015, 2017 SAP SE. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -401,11 +401,8 @@ address TemplateInterpreterGenerator::generate_result_handler_for(BasicType type
|
|||||||
case T_LONG:
|
case T_LONG:
|
||||||
break;
|
break;
|
||||||
case T_OBJECT:
|
case T_OBJECT:
|
||||||
// unbox result if not null
|
// JNIHandles::resolve result.
|
||||||
__ cmpdi(CCR0, R3_RET, 0);
|
__ resolve_jobject(R3_RET, R11_scratch1, R12_scratch2, /* needs_frame */ true); // kills R31
|
||||||
__ beq(CCR0, done);
|
|
||||||
__ ld(R3_RET, 0, R3_RET);
|
|
||||||
__ verify_oop(R3_RET);
|
|
||||||
break;
|
break;
|
||||||
case T_FLOAT:
|
case T_FLOAT:
|
||||||
break;
|
break;
|
||||||
|
@ -3439,6 +3439,34 @@ void MacroAssembler::card_write_barrier_post(Register store_addr, Register tmp)
|
|||||||
z_mvi(0, store_addr, 0); // Store byte 0.
|
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
|
#if INCLUDE_ALL_GCS
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
|
@ -726,6 +726,8 @@ class MacroAssembler: public Assembler {
|
|||||||
// Write to card table for modification at store_addr - register is destroyed afterwards.
|
// Write to card table for modification at store_addr - register is destroyed afterwards.
|
||||||
void card_write_barrier_post(Register store_addr, Register tmp);
|
void card_write_barrier_post(Register store_addr, Register tmp);
|
||||||
|
|
||||||
|
void resolve_jobject(Register value, Register tmp1, Register tmp2);
|
||||||
|
|
||||||
#if INCLUDE_ALL_GCS
|
#if INCLUDE_ALL_GCS
|
||||||
// General G1 pre-barrier generator.
|
// General G1 pre-barrier generator.
|
||||||
// Purpose: record the previous value if it is not null.
|
// Purpose: record the previous value if it is not null.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
* Copyright (c) 2016, 2017 SAP SE. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -2272,13 +2272,9 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
|
|||||||
|
|
||||||
__ reset_last_Java_frame();
|
__ reset_last_Java_frame();
|
||||||
|
|
||||||
// Unpack oop result
|
// Unpack oop result, e.g. JNIHandles::resolve result.
|
||||||
if (ret_type == T_OBJECT || ret_type == T_ARRAY) {
|
if (ret_type == T_OBJECT || ret_type == T_ARRAY) {
|
||||||
NearLabel L;
|
__ resolve_jobject(Z_RET, /* tmp1 */ Z_R13, /* tmp2 */ Z_R7);
|
||||||
__ compare64_and_branch(Z_RET, (RegisterOrConstant)0L, Assembler::bcondEqual, L);
|
|
||||||
__ z_lg(Z_RET, 0, Z_RET);
|
|
||||||
__ bind(L);
|
|
||||||
__ verify_oop(Z_RET);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CheckJNICalls) {
|
if (CheckJNICalls) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
* Copyright (c) 2016, 2017 SAP SE. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -1695,14 +1695,11 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
|
|||||||
// from the jni handle to z_ijava_state.oop_temp. This is
|
// from the jni handle to z_ijava_state.oop_temp. This is
|
||||||
// necessary, because we reset the jni handle block below.
|
// necessary, because we reset the jni handle block below.
|
||||||
// NOTE: frame::interpreter_frame_result() depends on this, too.
|
// 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));
|
__ 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(Z_R1, Rresult_handler, Assembler::bcondNotEqual, no_oop_result);
|
||||||
__ compareU64_and_branch(Rlresult, (intptr_t)0L, Assembler::bcondEqual, store_oop_result);
|
__ resolve_jobject(Rlresult, /* tmp1 */ Rmethod, /* tmp2 */ Z_R1);
|
||||||
__ z_lg(Rlresult, 0, Rlresult); // unbox
|
|
||||||
__ bind(store_oop_result);
|
|
||||||
__ z_stg(Rlresult, oop_tmp_offset, Z_fp);
|
__ z_stg(Rlresult, oop_tmp_offset, Z_fp);
|
||||||
__ verify_oop(Rlresult);
|
|
||||||
__ bind(no_oop_result);
|
__ bind(no_oop_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -2754,15 +2754,30 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
|||||||
__ verify_thread(); // G2_thread must be correct
|
__ verify_thread(); // G2_thread must be correct
|
||||||
__ reset_last_Java_frame();
|
__ 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) {
|
if (ret_type == T_OBJECT || ret_type == T_ARRAY) {
|
||||||
Label L;
|
Label done, not_weak;
|
||||||
__ addcc(G0, I0, G0);
|
__ br_null(I0, false, Assembler::pn, done); // Use NULL as-is.
|
||||||
__ brx(Assembler::notZero, true, Assembler::pt, L);
|
__ delayed()->andcc(I0, JNIHandles::weak_tag_mask, G0); // Test for jweak
|
||||||
__ delayed()->ld_ptr(I0, 0, I0);
|
__ brx(Assembler::zero, true, Assembler::pt, not_weak);
|
||||||
__ mov(G0, I0);
|
__ delayed()->ld_ptr(I0, 0, I0); // Maybe resolve (untagged) jobject.
|
||||||
__ bind(L);
|
// Resolve jweak.
|
||||||
__ verify_oop(I0);
|
__ 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) {
|
if (CheckJNICalls) {
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -1516,11 +1516,23 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
|
|||||||
|
|
||||||
__ set((intptr_t)AbstractInterpreter::result_handler(T_OBJECT), G3_scratch);
|
__ set((intptr_t)AbstractInterpreter::result_handler(T_OBJECT), G3_scratch);
|
||||||
__ cmp_and_brx_short(G3_scratch, Lscratch, Assembler::notEqual, Assembler::pt, no_oop);
|
__ cmp_and_brx_short(G3_scratch, Lscratch, Assembler::notEqual, Assembler::pt, no_oop);
|
||||||
__ addcc(G0, O0, O0);
|
// Unbox oop result, e.g. JNIHandles::resolve value in O0.
|
||||||
__ brx(Assembler::notZero, true, Assembler::pt, store_result); // if result is not NULL:
|
__ br_null(O0, false, Assembler::pn, store_result); // Use NULL as-is.
|
||||||
__ delayed()->ld_ptr(O0, 0, O0); // unbox it
|
__ delayed()->andcc(O0, JNIHandles::weak_tag_mask, G0); // Test for jweak
|
||||||
__ mov(G0, O0);
|
__ 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);
|
__ bind(store_result);
|
||||||
// Store it where gc will look for it and result handler expects it.
|
// 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);
|
__ st_ptr(O0, FP, (frame::interpreter_frame_oop_temp_offset*wordSize) + STACK_BIAS);
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -5129,6 +5129,36 @@ void MacroAssembler::vxorps(XMMRegister dst, XMMRegister nds, AddressLiteral src
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MacroAssembler::resolve_jobject(Register value,
|
||||||
|
Register thread,
|
||||||
|
Register tmp) {
|
||||||
|
assert_different_registers(value, thread, tmp);
|
||||||
|
Label done, not_weak;
|
||||||
|
testptr(value, value);
|
||||||
|
jcc(Assembler::zero, done); // Use NULL as-is.
|
||||||
|
testptr(value, JNIHandles::weak_tag_mask); // Test for jweak tag.
|
||||||
|
jcc(Assembler::zero, not_weak);
|
||||||
|
// Resolve jweak.
|
||||||
|
movptr(value, Address(value, -JNIHandles::weak_tag_value));
|
||||||
|
verify_oop(value);
|
||||||
|
#if INCLUDE_ALL_GCS
|
||||||
|
if (UseG1GC) {
|
||||||
|
g1_write_barrier_pre(noreg /* obj */,
|
||||||
|
value /* pre_val */,
|
||||||
|
thread /* thread */,
|
||||||
|
tmp /* tmp */,
|
||||||
|
true /* tosca_live */,
|
||||||
|
true /* expand_call */);
|
||||||
|
}
|
||||||
|
#endif // INCLUDE_ALL_GCS
|
||||||
|
jmp(done);
|
||||||
|
bind(not_weak);
|
||||||
|
// Resolve (untagged) jobject.
|
||||||
|
movptr(value, Address(value, 0));
|
||||||
|
verify_oop(value);
|
||||||
|
bind(done);
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
#if INCLUDE_ALL_GCS
|
#if INCLUDE_ALL_GCS
|
||||||
|
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -297,6 +297,8 @@ class MacroAssembler: public Assembler {
|
|||||||
void store_check(Register obj); // store check for obj - register is destroyed afterwards
|
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 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);
|
||||||
|
|
||||||
#if INCLUDE_ALL_GCS
|
#if INCLUDE_ALL_GCS
|
||||||
|
|
||||||
void g1_write_barrier_pre(Register obj,
|
void g1_write_barrier_pre(Register obj,
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -2226,14 +2226,11 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
|||||||
|
|
||||||
__ reset_last_Java_frame(thread, false);
|
__ 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) {
|
if (ret_type == T_OBJECT || ret_type == T_ARRAY) {
|
||||||
Label L;
|
__ resolve_jobject(rax /* value */,
|
||||||
__ cmpptr(rax, (int32_t)NULL_WORD);
|
thread /* thread */,
|
||||||
__ jcc(Assembler::equal, L);
|
rcx /* tmp */);
|
||||||
__ movptr(rax, Address(rax, 0));
|
|
||||||
__ bind(L);
|
|
||||||
__ verify_oop(rax);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CheckJNICalls) {
|
if (CheckJNICalls) {
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -2579,14 +2579,11 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
|||||||
|
|
||||||
__ reset_last_Java_frame(false);
|
__ 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) {
|
if (ret_type == T_OBJECT || ret_type == T_ARRAY) {
|
||||||
Label L;
|
__ resolve_jobject(rax /* value */,
|
||||||
__ testptr(rax, rax);
|
r15_thread /* thread */,
|
||||||
__ jcc(Assembler::zero, L);
|
rcx /* tmp */);
|
||||||
__ movptr(rax, Address(rax, 0));
|
|
||||||
__ bind(L);
|
|
||||||
__ verify_oop(rax);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CheckJNICalls) {
|
if (CheckJNICalls) {
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -1193,16 +1193,16 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
|
|||||||
// and result handler will pick it up
|
// 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)));
|
__ lea(t, ExternalAddress(AbstractInterpreter::result_handler(T_OBJECT)));
|
||||||
__ cmpptr(t, Address(rbp, frame::interpreter_frame_result_handler_offset*wordSize));
|
__ cmpptr(t, Address(rbp, frame::interpreter_frame_result_handler_offset*wordSize));
|
||||||
__ jcc(Assembler::notEqual, no_oop);
|
__ jcc(Assembler::notEqual, no_oop);
|
||||||
// retrieve result
|
// retrieve result
|
||||||
__ pop(ltos);
|
__ pop(ltos);
|
||||||
__ testptr(rax, rax);
|
// Unbox oop result, e.g. JNIHandles::resolve value.
|
||||||
__ jcc(Assembler::zero, store_result);
|
__ resolve_jobject(rax /* value */,
|
||||||
__ movptr(rax, Address(rax, 0));
|
thread /* thread */,
|
||||||
__ bind(store_result);
|
t /* tmp */);
|
||||||
__ movptr(Address(rbp, frame::interpreter_frame_oop_temp_offset*wordSize), rax);
|
__ movptr(Address(rbp, frame::interpreter_frame_oop_temp_offset*wordSize), rax);
|
||||||
// keep stack depth as expected by pushing oop which will eventually be discarded
|
// keep stack depth as expected by pushing oop which will eventually be discarded
|
||||||
__ push(ltos);
|
__ push(ltos);
|
||||||
|
@ -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.
|
* Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
@ -406,10 +406,12 @@ int CppInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) {
|
|||||||
// oop_temp where the garbage collector can see it before
|
// oop_temp where the garbage collector can see it before
|
||||||
// we release the handle it might be protected by.
|
// we release the handle it might be protected by.
|
||||||
if (handler->result_type() == &ffi_type_pointer) {
|
if (handler->result_type() == &ffi_type_pointer) {
|
||||||
if (result[0])
|
if (result[0] == 0) {
|
||||||
istate->set_oop_temp(*(oop *) result[0]);
|
|
||||||
else
|
|
||||||
istate->set_oop_temp(NULL);
|
istate->set_oop_temp(NULL);
|
||||||
|
} else {
|
||||||
|
jobject handle = reinterpret_cast<jobject>(result[0]);
|
||||||
|
istate->set_oop_temp(JNIHandles::resolve(handle));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset handle block
|
// Reset handle block
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2012 Red Hat, Inc.
|
* Copyright (c) 2012 Red Hat, Inc.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
@ -935,8 +935,7 @@ class JNI_ArgumentPusherVaArg : public JNI_ArgumentPusher {
|
|||||||
inline void get_long() { _arguments->push_long(va_arg(_ap, jlong)); }
|
inline void get_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_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_double() { _arguments->push_double(va_arg(_ap, jdouble)); }
|
||||||
inline void get_object() { jobject l = va_arg(_ap, jobject);
|
inline void get_object() { _arguments->push_jobject(va_arg(_ap, jobject)); }
|
||||||
_arguments->push_oop(Handle((oop *)l, false)); }
|
|
||||||
|
|
||||||
inline void set_ap(va_list rap) {
|
inline void set_ap(va_list rap) {
|
||||||
va_copy(_ap, rap);
|
va_copy(_ap, rap);
|
||||||
@ -1025,7 +1024,7 @@ class JNI_ArgumentPusherArray : public JNI_ArgumentPusher {
|
|||||||
inline void get_long() { _arguments->push_long((_ap++)->j); }
|
inline void get_long() { _arguments->push_long((_ap++)->j); }
|
||||||
inline void get_float() { _arguments->push_float((_ap++)->f); }
|
inline void get_float() { _arguments->push_float((_ap++)->f); }
|
||||||
inline void get_double() { _arguments->push_double((_ap++)->d);}
|
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; }
|
inline void set_ap(const jvalue *rap) { _ap = rap; }
|
||||||
|
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -1796,6 +1796,13 @@ JvmtiEnv::FollowReferences(jint heap_filter, jclass klass, jobject initial_objec
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (initial_object != NULL) {
|
||||||
|
oop init_obj = JNIHandles::resolve_external_guard(initial_object);
|
||||||
|
if (init_obj == NULL) {
|
||||||
|
return JVMTI_ERROR_INVALID_OBJECT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Thread *thread = Thread::current();
|
Thread *thread = Thread::current();
|
||||||
HandleMark hm(thread);
|
HandleMark hm(thread);
|
||||||
KlassHandle kh (thread, k_oop);
|
KlassHandle kh (thread, k_oop);
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -328,9 +328,9 @@ void JavaCalls::call_helper(JavaValue* result, const methodHandle& method, JavaC
|
|||||||
// Verify the arguments
|
// Verify the arguments
|
||||||
|
|
||||||
if (CheckJNICalls) {
|
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
|
#if INCLUDE_JVMCI
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -442,12 +442,43 @@ void JavaCalls::call_helper(JavaValue* result, const methodHandle& method, JavaC
|
|||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
// Implementation of JavaCallArguments
|
// 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<oop*>(value);
|
||||||
|
return Handle::raw_resolve(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
case JavaCallArguments::value_state_jobject:
|
||||||
|
{
|
||||||
|
jobject obj = reinterpret_cast<jobject>(value);
|
||||||
|
return JNIHandles::resolve(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
ShouldNotReachHere();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
intptr_t* JavaCallArguments::parameters() {
|
intptr_t* JavaCallArguments::parameters() {
|
||||||
// First convert all handles to oops
|
// First convert all handles to oops
|
||||||
for(int i = 0; i < _size; i++) {
|
for(int i = 0; i < _size; i++) {
|
||||||
if (_is_oop[i]) {
|
uint state = _value_state[i];
|
||||||
// Handle conversion
|
assert(state != value_state_oop, "Multiple handle conversions");
|
||||||
_value[i] = cast_from_oop<intptr_t>(Handle::raw_resolve((oop *)_value[i]));
|
if (is_value_state_indirect_oop(state)) {
|
||||||
|
oop obj = resolve_indirect_oop(_value[i], state);
|
||||||
|
_value[i] = cast_from_oop<intptr_t>(obj);
|
||||||
|
_value_state[i] = value_state_oop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Return argument vector
|
// Return argument vector
|
||||||
@ -457,30 +488,42 @@ intptr_t* JavaCallArguments::parameters() {
|
|||||||
|
|
||||||
class SignatureChekker : public SignatureIterator {
|
class SignatureChekker : public SignatureIterator {
|
||||||
private:
|
private:
|
||||||
bool *_is_oop;
|
int _pos;
|
||||||
int _pos;
|
|
||||||
BasicType _return_type;
|
BasicType _return_type;
|
||||||
intptr_t* _value;
|
u_char* _value_state;
|
||||||
Thread* _thread;
|
intptr_t* _value;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool _is_return;
|
bool _is_return;
|
||||||
|
|
||||||
SignatureChekker(Symbol* signature, BasicType return_type, bool is_static, bool* is_oop, intptr_t* value, Thread* thread) : SignatureIterator(signature) {
|
SignatureChekker(Symbol* signature,
|
||||||
_is_oop = is_oop;
|
BasicType return_type,
|
||||||
_is_return = false;
|
bool is_static,
|
||||||
_return_type = return_type;
|
u_char* value_state,
|
||||||
_pos = 0;
|
intptr_t* value) :
|
||||||
_value = value;
|
SignatureIterator(signature),
|
||||||
_thread = thread;
|
_pos(0),
|
||||||
|
_return_type(return_type),
|
||||||
|
_value_state(value_state),
|
||||||
|
_value(value),
|
||||||
|
_is_return(false)
|
||||||
|
{
|
||||||
if (!is_static) {
|
if (!is_static) {
|
||||||
check_value(true); // Receiver must be an oop
|
check_value(true); // Receiver must be an oop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_value(bool type) {
|
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; }
|
void check_doing_return(bool state) { _is_return = state; }
|
||||||
@ -515,24 +558,20 @@ class SignatureChekker : public SignatureIterator {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify handle and the oop pointed to by handle
|
intptr_t v = _value[_pos];
|
||||||
int p = _pos;
|
if (v != 0) {
|
||||||
bool bad = false;
|
// v is a "handle" referring to an oop, cast to integral type.
|
||||||
// If argument is oop
|
// There shouldn't be any handles in very low memory.
|
||||||
if (_is_oop[p]) {
|
guarantee((size_t)v >= (size_t)os::vm_page_size(),
|
||||||
intptr_t v = _value[p];
|
"Bad JNI oop argument %d: " PTR_FORMAT, _pos, v);
|
||||||
if (v != 0 ) {
|
// Verify the pointee.
|
||||||
size_t t = (size_t)v;
|
oop vv = resolve_indirect_oop(v, _value_state[_pos]);
|
||||||
bad = (t < (size_t)os::vm_page_size() ) || !Handle::raw_resolve((oop *)v)->is_oop_or_null(true);
|
guarantee(vv->is_oop_or_null(true),
|
||||||
if (CheckJNICalls && bad) {
|
"Bad JNI oop argument %d: " PTR_FORMAT " -> " PTR_FORMAT,
|
||||||
ReportJNIFatalError((JavaThread*)_thread, "Bad JNI oop argument");
|
_pos, v, p2i(vv));
|
||||||
}
|
|
||||||
}
|
|
||||||
// for the regular debug case.
|
|
||||||
assert(!bad, "Bad JNI oop argument");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
check_value(true);
|
check_value(true); // Verify value state.
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_bool() { check_int(T_BOOLEAN); }
|
void do_bool() { check_int(T_BOOLEAN); }
|
||||||
@ -549,8 +588,7 @@ class SignatureChekker : public SignatureIterator {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void JavaCallArguments::verify(const methodHandle& method, BasicType return_type,
|
void JavaCallArguments::verify(const methodHandle& method, BasicType return_type) {
|
||||||
Thread *thread) {
|
|
||||||
guarantee(method->size_of_parameters() == size_of_parameters(), "wrong no. of arguments pushed");
|
guarantee(method->size_of_parameters() == size_of_parameters(), "wrong no. of arguments pushed");
|
||||||
|
|
||||||
// Treat T_OBJECT and T_ARRAY as the same
|
// Treat T_OBJECT and T_ARRAY as the same
|
||||||
@ -559,7 +597,11 @@ void JavaCallArguments::verify(const methodHandle& method, BasicType return_type
|
|||||||
// Check that oop information is correct
|
// Check that oop information is correct
|
||||||
Symbol* signature = method->signature();
|
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.iterate_parameters();
|
||||||
sc.check_doing_return(true);
|
sc.check_doing_return(true);
|
||||||
sc.iterate_returntype();
|
sc.iterate_returntype();
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -80,11 +80,11 @@ class JavaCallArguments : public StackObj {
|
|||||||
_default_size = 8 // Must be at least # of arguments in JavaCalls methods
|
_default_size = 8 // Must be at least # of arguments in JavaCalls methods
|
||||||
};
|
};
|
||||||
|
|
||||||
intptr_t _value_buffer [_default_size + 1];
|
intptr_t _value_buffer [_default_size + 1];
|
||||||
bool _is_oop_buffer[_default_size + 1];
|
u_char _value_state_buffer[_default_size + 1];
|
||||||
|
|
||||||
intptr_t* _value;
|
intptr_t* _value;
|
||||||
bool* _is_oop;
|
u_char* _value_state;
|
||||||
int _size;
|
int _size;
|
||||||
int _max_size;
|
int _max_size;
|
||||||
bool _start_at_zero; // Support late setting of receiver
|
bool _start_at_zero; // Support late setting of receiver
|
||||||
@ -92,8 +92,8 @@ class JavaCallArguments : public StackObj {
|
|||||||
|
|
||||||
void initialize() {
|
void initialize() {
|
||||||
// Starts at first element to support set_receiver.
|
// Starts at first element to support set_receiver.
|
||||||
_value = &_value_buffer[1];
|
_value = &_value_buffer[1];
|
||||||
_is_oop = &_is_oop_buffer[1];
|
_value_state = &_value_state_buffer[1];
|
||||||
|
|
||||||
_max_size = _default_size;
|
_max_size = _default_size;
|
||||||
_size = 0;
|
_size = 0;
|
||||||
@ -101,6 +101,23 @@ class JavaCallArguments : public StackObj {
|
|||||||
JVMCI_ONLY(_alternative_target = NULL;)
|
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<typename T>
|
||||||
|
inline int push_oop_impl(T handle, int size) {
|
||||||
|
// JNITypes::put_obj expects an oop value, so we play fast and
|
||||||
|
// loose with the type system. The cast from handle type to oop
|
||||||
|
// *must* use a C-style cast. In a product build it performs a
|
||||||
|
// reinterpret_cast. In a debug build (more accurately, in a
|
||||||
|
// CHECK_UNHANDLED_OOPS build) it performs a static_cast, invoking
|
||||||
|
// the debug-only oop class's conversion from void* constructor.
|
||||||
|
JNITypes::put_obj((oop)handle, _value, size); // Updates size.
|
||||||
|
return size; // Return the updated size.
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
JavaCallArguments() { initialize(); }
|
JavaCallArguments() { initialize(); }
|
||||||
|
|
||||||
@ -111,11 +128,12 @@ class JavaCallArguments : public StackObj {
|
|||||||
|
|
||||||
JavaCallArguments(int max_size) {
|
JavaCallArguments(int max_size) {
|
||||||
if (max_size > _default_size) {
|
if (max_size > _default_size) {
|
||||||
_value = NEW_RESOURCE_ARRAY(intptr_t, max_size + 1);
|
_value = NEW_RESOURCE_ARRAY(intptr_t, max_size + 1);
|
||||||
_is_oop = NEW_RESOURCE_ARRAY(bool, max_size + 1);
|
_value_state = NEW_RESOURCE_ARRAY(u_char, max_size + 1);
|
||||||
|
|
||||||
// Reserve room for potential receiver in value and is_oop
|
// Reserve room for potential receiver in value and state
|
||||||
_value++; _is_oop++;
|
_value++;
|
||||||
|
_value_state++;
|
||||||
|
|
||||||
_max_size = max_size;
|
_max_size = max_size;
|
||||||
_size = 0;
|
_size = 0;
|
||||||
@ -136,25 +154,52 @@ class JavaCallArguments : public StackObj {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline void push_oop(Handle h) { _is_oop[_size] = true;
|
// The possible values for _value_state elements.
|
||||||
JNITypes::put_obj((oop)h.raw_value(), _value, _size); }
|
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;
|
inline void push_oop(Handle h) {
|
||||||
JNITypes::put_int(i, _value, _size); }
|
_value_state[_size] = value_state_handle;
|
||||||
|
_size = push_oop_impl(h.raw_value(), _size);
|
||||||
|
}
|
||||||
|
|
||||||
inline void push_double(double d) { _is_oop[_size] = false; _is_oop[_size + 1] = false;
|
inline void push_jobject(jobject h) {
|
||||||
JNITypes::put_double(d, _value, _size); }
|
_value_state[_size] = value_state_jobject;
|
||||||
|
_size = push_oop_impl(h, _size);
|
||||||
|
}
|
||||||
|
|
||||||
inline void push_long(jlong l) { _is_oop[_size] = false; _is_oop[_size + 1] = false;
|
inline void push_int(int i) {
|
||||||
JNITypes::put_long(l, _value, _size); }
|
_value_state[_size] = value_state_primitive;
|
||||||
|
JNITypes::put_int(i, _value, _size);
|
||||||
|
}
|
||||||
|
|
||||||
inline void push_float(float f) { _is_oop[_size] = false;
|
inline void push_double(double d) {
|
||||||
JNITypes::put_float(f, _value, _size); }
|
_value_state[_size] = value_state_primitive;
|
||||||
|
_value_state[_size + 1] = value_state_primitive;
|
||||||
|
JNITypes::put_double(d, _value, _size);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void push_long(jlong l) {
|
||||||
|
_value_state[_size] = value_state_primitive;
|
||||||
|
_value_state[_size + 1] = value_state_primitive;
|
||||||
|
JNITypes::put_long(l, _value, _size);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void push_float(float f) {
|
||||||
|
_value_state[_size] = value_state_primitive;
|
||||||
|
JNITypes::put_float(f, _value, _size);
|
||||||
|
}
|
||||||
|
|
||||||
// receiver
|
// receiver
|
||||||
Handle receiver() {
|
Handle receiver() {
|
||||||
assert(_size > 0, "must at least be one argument");
|
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");
|
assert(_value[0] != 0, "receiver must be not-null");
|
||||||
return Handle((oop*)_value[0], false);
|
return Handle((oop*)_value[0], false);
|
||||||
}
|
}
|
||||||
@ -162,11 +207,11 @@ class JavaCallArguments : public StackObj {
|
|||||||
void set_receiver(Handle h) {
|
void set_receiver(Handle h) {
|
||||||
assert(_start_at_zero == false, "can only be called once");
|
assert(_start_at_zero == false, "can only be called once");
|
||||||
_start_at_zero = true;
|
_start_at_zero = true;
|
||||||
_is_oop--;
|
_value_state--;
|
||||||
_value--;
|
_value--;
|
||||||
_size++;
|
_size++;
|
||||||
_is_oop[0] = true;
|
_value_state[0] = value_state_handle;
|
||||||
_value[0] = (intptr_t)h.raw_value();
|
push_oop_impl(h.raw_value(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts all Handles to oops, and returns a reference to parameter vector
|
// Converts all Handles to oops, and returns a reference to parameter vector
|
||||||
@ -174,7 +219,7 @@ class JavaCallArguments : public StackObj {
|
|||||||
int size_of_parameters() const { return _size; }
|
int size_of_parameters() const { return _size; }
|
||||||
|
|
||||||
// Verify that pushed arguments fits a given method
|
// 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
|
// All calls to Java have to go via JavaCalls. Sets up the stack frame
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -31,6 +31,9 @@
|
|||||||
#include "runtime/jniHandles.hpp"
|
#include "runtime/jniHandles.hpp"
|
||||||
#include "runtime/mutexLocker.hpp"
|
#include "runtime/mutexLocker.hpp"
|
||||||
#include "runtime/thread.inline.hpp"
|
#include "runtime/thread.inline.hpp"
|
||||||
|
#if INCLUDE_ALL_GCS
|
||||||
|
#include "gc/g1/g1SATBCardTableModRefBS.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
JNIHandleBlock* JNIHandles::_global_handles = NULL;
|
JNIHandleBlock* JNIHandles::_global_handles = NULL;
|
||||||
JNIHandleBlock* JNIHandles::_weak_global_handles = NULL;
|
JNIHandleBlock* JNIHandles::_weak_global_handles = NULL;
|
||||||
@ -92,28 +95,48 @@ jobject JNIHandles::make_weak_global(Handle obj) {
|
|||||||
jobject res = NULL;
|
jobject res = NULL;
|
||||||
if (!obj.is_null()) {
|
if (!obj.is_null()) {
|
||||||
// ignore null handles
|
// ignore null handles
|
||||||
MutexLocker ml(JNIGlobalHandle_lock);
|
{
|
||||||
assert(Universe::heap()->is_in_reserved(obj()), "sanity check");
|
MutexLocker ml(JNIGlobalHandle_lock);
|
||||||
res = _weak_global_handles->allocate_handle(obj());
|
assert(Universe::heap()->is_in_reserved(obj()), "sanity check");
|
||||||
|
res = _weak_global_handles->allocate_handle(obj());
|
||||||
|
}
|
||||||
|
// Add weak tag.
|
||||||
|
assert(is_ptr_aligned(res, weak_tag_alignment), "invariant");
|
||||||
|
char* tptr = reinterpret_cast<char*>(res) + weak_tag_value;
|
||||||
|
res = reinterpret_cast<jobject>(tptr);
|
||||||
} else {
|
} else {
|
||||||
CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
|
CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<bool external_guard>
|
||||||
|
oop JNIHandles::resolve_jweak(jweak handle) {
|
||||||
|
assert(is_jweak(handle), "precondition");
|
||||||
|
oop result = jweak_ref(handle);
|
||||||
|
result = guard_value<external_guard>(result);
|
||||||
|
#if INCLUDE_ALL_GCS
|
||||||
|
if (result != NULL && UseG1GC) {
|
||||||
|
G1SATBCardTableModRefBS::enqueue(result);
|
||||||
|
}
|
||||||
|
#endif // INCLUDE_ALL_GCS
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template oop JNIHandles::resolve_jweak<true>(jweak);
|
||||||
|
template oop JNIHandles::resolve_jweak<false>(jweak);
|
||||||
|
|
||||||
void JNIHandles::destroy_global(jobject handle) {
|
void JNIHandles::destroy_global(jobject handle) {
|
||||||
if (handle != NULL) {
|
if (handle != NULL) {
|
||||||
assert(is_global_handle(handle), "Invalid delete of global JNI handle");
|
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) {
|
void JNIHandles::destroy_weak_global(jobject handle) {
|
||||||
if (handle != NULL) {
|
if (handle != NULL) {
|
||||||
assert(!CheckJNICalls || is_weak_global_handle(handle), "Invalid delete of weak global JNI handle");
|
jweak_ref(handle) = deleted_handle();
|
||||||
*((oop*)handle) = deleted_handle(); // Mark the handle as deleted, allocate will reuse it
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -40,7 +40,28 @@ class JNIHandles : AllStatic {
|
|||||||
static JNIHandleBlock* _weak_global_handles; // First weak global handle block
|
static JNIHandleBlock* _weak_global_handles; // First weak global handle block
|
||||||
static oop _deleted_handle; // Sentinel marking deleted handles
|
static oop _deleted_handle; // Sentinel marking deleted handles
|
||||||
|
|
||||||
|
inline static bool is_jweak(jobject handle);
|
||||||
|
inline static oop& jobject_ref(jobject handle); // NOT jweak!
|
||||||
|
inline static oop& jweak_ref(jobject handle);
|
||||||
|
|
||||||
|
template<bool external_guard> inline static oop guard_value(oop value);
|
||||||
|
template<bool external_guard> inline static oop resolve_impl(jobject handle);
|
||||||
|
template<bool external_guard> static oop resolve_jweak(jweak handle);
|
||||||
|
|
||||||
public:
|
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
|
// Resolve handle into oop
|
||||||
inline static oop resolve(jobject handle);
|
inline static oop resolve(jobject handle);
|
||||||
// Resolve externally provided handle into oop with some guards
|
// Resolve externally provided handle into oop with some guards
|
||||||
@ -176,36 +197,85 @@ class JNIHandleBlock : public CHeapObj<mtInternal> {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline bool JNIHandles::is_jweak(jobject handle) {
|
||||||
|
STATIC_ASSERT(weak_tag_size == 1);
|
||||||
|
STATIC_ASSERT(weak_tag_value == 1);
|
||||||
|
return (reinterpret_cast<uintptr_t>(handle) & weak_tag_mask) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline oop& JNIHandles::jobject_ref(jobject handle) {
|
||||||
|
assert(!is_jweak(handle), "precondition");
|
||||||
|
return *reinterpret_cast<oop*>(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline oop& JNIHandles::jweak_ref(jobject handle) {
|
||||||
|
assert(is_jweak(handle), "precondition");
|
||||||
|
char* ptr = reinterpret_cast<char*>(handle) - weak_tag_value;
|
||||||
|
return *reinterpret_cast<oop*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// external_guard is true if called from resolve_external_guard.
|
||||||
|
// Treat deleted (and possibly zapped) as NULL for external_guard,
|
||||||
|
// else as (asserted) error.
|
||||||
|
template<bool external_guard>
|
||||||
|
inline oop JNIHandles::guard_value(oop value) {
|
||||||
|
if (!external_guard) {
|
||||||
|
assert(value != badJNIHandle, "Pointing to zapped jni handle area");
|
||||||
|
assert(value != deleted_handle(), "Used a deleted global handle");
|
||||||
|
} else if ((value == badJNIHandle) || (value == deleted_handle())) {
|
||||||
|
value = NULL;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// external_guard is true if called from resolve_external_guard.
|
||||||
|
template<bool external_guard>
|
||||||
|
inline oop JNIHandles::resolve_impl(jobject handle) {
|
||||||
|
assert(handle != NULL, "precondition");
|
||||||
|
oop result;
|
||||||
|
if (is_jweak(handle)) { // Unlikely
|
||||||
|
result = resolve_jweak<external_guard>(handle);
|
||||||
|
} else {
|
||||||
|
result = jobject_ref(handle);
|
||||||
|
// Construction of jobjects canonicalize a null value into a null
|
||||||
|
// jobject, so for non-jweak the pointee should never be null.
|
||||||
|
assert(external_guard || result != NULL,
|
||||||
|
"Invalid value read from jni handle");
|
||||||
|
result = guard_value<external_guard>(result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
inline oop JNIHandles::resolve(jobject handle) {
|
inline oop JNIHandles::resolve(jobject handle) {
|
||||||
oop result = (handle == NULL ? (oop)NULL : *(oop*)handle);
|
oop result = NULL;
|
||||||
assert(result != NULL || (handle == NULL || !CheckJNICalls || is_weak_global_handle(handle)), "Invalid value read from jni handle");
|
if (handle != NULL) {
|
||||||
assert(result != badJNIHandle, "Pointing to zapped jni handle area");
|
result = resolve_impl<false /* external_guard */ >(handle);
|
||||||
|
}
|
||||||
return result;
|
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) {
|
inline oop JNIHandles::resolve_external_guard(jobject handle) {
|
||||||
if (handle == NULL) return NULL;
|
oop result = NULL;
|
||||||
oop result = *(oop*)handle;
|
if (handle != NULL) {
|
||||||
if (result == NULL || result == badJNIHandle) return NULL;
|
result = resolve_impl<true /* external_guard */ >(handle);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
inline oop JNIHandles::resolve_non_null(jobject handle) {
|
inline oop JNIHandles::resolve_non_null(jobject handle) {
|
||||||
assert(handle != NULL, "JNI handle should not be null");
|
assert(handle != NULL, "JNI handle should not be null");
|
||||||
oop result = *(oop*)handle;
|
oop result = resolve_impl<false /* external_guard */ >(handle);
|
||||||
assert(result != NULL, "Invalid value read from jni handle");
|
assert(result != NULL, "NULL read from jni handle");
|
||||||
assert(result != badJNIHandle, "Pointing to zapped jni handle area");
|
|
||||||
// Don't let that private _deleted_handle object escape into the wild.
|
|
||||||
assert(result != deleted_handle(), "Used a deleted global handle.");
|
|
||||||
return result;
|
return result;
|
||||||
};
|
}
|
||||||
|
|
||||||
inline void JNIHandles::destroy_local(jobject handle) {
|
inline void JNIHandles::destroy_local(jobject handle) {
|
||||||
if (handle != NULL) {
|
if (handle != NULL) {
|
||||||
*((oop*)handle) = deleted_handle(); // Mark the handle as deleted, allocate will reuse it
|
jobject_ref(handle) = deleted_handle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
* Copyright 2009, 2010 Red Hat, Inc.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
@ -300,6 +300,7 @@ void SharkNativeWrapper::initialize(const char *name) {
|
|||||||
not_null, merge);
|
not_null, merge);
|
||||||
|
|
||||||
builder()->SetInsertPoint(not_null);
|
builder()->SetInsertPoint(not_null);
|
||||||
|
#error Needs to be updated for tagged jweak; see JNIHandles.
|
||||||
Value *unboxed_result = builder()->CreateLoad(result);
|
Value *unboxed_result = builder()->CreateLoad(result);
|
||||||
builder()->CreateBr(merge);
|
builder()->CreateBr(merge);
|
||||||
|
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
static native Object doStuff(Object o);
|
||||||
|
static native Object doWithWeak(Object o);
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Object o = doStuff(Thread.currentThread());
|
||||||
|
System.out.println(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* 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 <jni.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: CallWithJNIWeak
|
||||||
|
* Method: doStuff
|
||||||
|
* Signature: (Ljava/lang/Object;)Ljava/lang/Object;
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobject JNICALL
|
||||||
|
Java_CallWithJNIWeak_doStuff(JNIEnv *env, jclass c, jobject o) {
|
||||||
|
jmethodID id = (*env)->GetStaticMethodID(
|
||||||
|
env, c, "doWithWeak", "(Ljava/lang/Object;)Ljava/lang/Object;");
|
||||||
|
jweak w = (*env)->NewWeakGlobalRef(env, o);
|
||||||
|
jobject param = w;
|
||||||
|
(*env)->CallStaticVoidMethod(env, c, id, param);
|
||||||
|
return param;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: CallWithJNIWeak
|
||||||
|
* Method: doWithWeak
|
||||||
|
* Signature: (Ljava/lang/Object;)Ljava/lang/Object;
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobject JNICALL
|
||||||
|
Java_CallWithJNIWeak_doWithWeak(JNIEnv *env, jclass c, jobject o) {
|
||||||
|
jclass thr_class = (*env)->GetObjectClass(env, o); // o is java.lang.Thread
|
||||||
|
jmethodID id = (*env)->GetMethodID(env, thr_class, "isInterrupted", "()Z");
|
||||||
|
jboolean b = (*env)->CallBooleanMethod(env, o, id);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
132
hotspot/test/runtime/jni/ReturnJNIWeak/ReturnJNIWeak.java
Normal file
132
hotspot/test/runtime/jni/ReturnJNIWeak/ReturnJNIWeak.java
Normal file
@ -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();
|
||||||
|
}
|
||||||
|
}
|
52
hotspot/test/runtime/jni/ReturnJNIWeak/libReturnJNIWeak.c
Normal file
52
hotspot/test/runtime/jni/ReturnJNIWeak/libReturnJNIWeak.c
Normal file
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user