8228743: [PPC64, s390] Implement FastJNIAccessors
Reviewed-by: goetz, lucy
This commit is contained in:
parent
1186d8203b
commit
918492bb58
@ -116,3 +116,9 @@ void BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value,
|
||||
__ verify_oop(value);
|
||||
__ bind(done);
|
||||
}
|
||||
|
||||
void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register dst, Register jni_env,
|
||||
Register obj, Register tmp, Label& slowpath) {
|
||||
__ clrrdi(dst, obj, JNIHandles::weak_tag_size);
|
||||
__ ld(dst, 0, dst); // Resolve (untagged) jobject.
|
||||
}
|
||||
|
@ -49,6 +49,9 @@ public:
|
||||
|
||||
virtual void resolve_jobject(MacroAssembler* masm, Register value, Register tmp1, Register tmp2, bool needs_frame);
|
||||
|
||||
virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register dst, Register jni_env,
|
||||
Register obj, Register tmp, Label& slowpath);
|
||||
|
||||
virtual void barrier_stubs_init() {}
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2018 SAP SE. All rights reserved.
|
||||
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2019 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -24,16 +24,138 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/assembler.inline.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "gc/shared/barrierSetAssembler.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "prims/jniFastGetField.hpp"
|
||||
#include "prims/jvm_misc.hpp"
|
||||
#include "runtime/safepoint.hpp"
|
||||
|
||||
#define __ masm->
|
||||
|
||||
#define BUFFER_SIZE 48*BytesPerInstWord
|
||||
|
||||
|
||||
// Common register usage:
|
||||
// R3/F0: result
|
||||
// R3_ARG1: jni env
|
||||
// R4_ARG2: obj
|
||||
// R5_ARG3: jfield id
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
|
||||
// We don't have fast jni accessors.
|
||||
return (address) -1;
|
||||
const char *name;
|
||||
switch (type) {
|
||||
case T_BOOLEAN: name = "jni_fast_GetBooleanField"; break;
|
||||
case T_BYTE: name = "jni_fast_GetByteField"; break;
|
||||
case T_CHAR: name = "jni_fast_GetCharField"; break;
|
||||
case T_SHORT: name = "jni_fast_GetShortField"; break;
|
||||
case T_INT: name = "jni_fast_GetIntField"; break;
|
||||
case T_LONG: name = "jni_fast_GetLongField"; break;
|
||||
case T_FLOAT: name = "jni_fast_GetFloatField"; break;
|
||||
case T_DOUBLE: name = "jni_fast_GetDoubleField"; break;
|
||||
default: ShouldNotReachHere();
|
||||
name = NULL; // unreachable
|
||||
}
|
||||
ResourceMark rm;
|
||||
BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE);
|
||||
CodeBuffer cbuf(blob);
|
||||
MacroAssembler* masm = new MacroAssembler(&cbuf);
|
||||
address fast_entry = __ function_entry();
|
||||
|
||||
Label slow;
|
||||
|
||||
const Register Rcounter_addr = R6_ARG4,
|
||||
Rcounter = R7_ARG5,
|
||||
Robj = R8_ARG6,
|
||||
Rtmp = R9_ARG7;
|
||||
const int counter_offs = __ load_const_optimized(Rcounter_addr,
|
||||
SafepointSynchronize::safepoint_counter_addr(),
|
||||
R0, true);
|
||||
|
||||
__ ld(Rcounter, counter_offs, Rcounter_addr);
|
||||
__ andi_(R0, Rcounter, 1);
|
||||
__ bne(CCR0, slow);
|
||||
|
||||
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
|
||||
// Field may be volatile.
|
||||
__ fence();
|
||||
} else {
|
||||
// Using acquire to order wrt. JVMTI check and load of result.
|
||||
__ isync(); // order wrt. to following load(s)
|
||||
}
|
||||
|
||||
if (JvmtiExport::can_post_field_access()) {
|
||||
// Check to see if a field access watch has been set before we
|
||||
// take the fast path.
|
||||
int fac_offs = __ load_const_optimized(Rtmp, JvmtiExport::get_field_access_count_addr(),
|
||||
R0, true);
|
||||
__ lwa(Rtmp, fac_offs, Rtmp);
|
||||
__ cmpwi(CCR0, Rtmp, 0);
|
||||
__ bne(CCR0, slow);
|
||||
}
|
||||
|
||||
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||
bs->try_resolve_jobject_in_native(masm, Robj, R3_ARG1, R4_ARG2, Rtmp, slow);
|
||||
|
||||
__ srwi(Rtmp, R5_ARG3, 2); // offset
|
||||
|
||||
assert(count < LIST_CAPACITY, "LIST_CAPACITY too small");
|
||||
speculative_load_pclist[count] = __ pc(); // Used by the segfault handler
|
||||
bool is_fp = false;
|
||||
switch (type) {
|
||||
case T_BOOLEAN: __ lbzx(Rtmp, Rtmp, Robj); break;
|
||||
case T_BYTE: __ lbzx(Rtmp, Rtmp, Robj); __ extsb(Rtmp, Rtmp); break;
|
||||
case T_CHAR: __ lhzx(Rtmp, Rtmp, Robj); break;
|
||||
case T_SHORT: __ lhax(Rtmp, Rtmp, Robj); break;
|
||||
case T_INT: __ lwax(Rtmp, Rtmp, Robj); break;
|
||||
case T_LONG: __ ldx( Rtmp, Rtmp, Robj); break;
|
||||
case T_FLOAT: __ lfsx(F1_RET, Rtmp, Robj); is_fp = true; break;
|
||||
case T_DOUBLE: __ lfdx(F1_RET, Rtmp, Robj); is_fp = true; break;
|
||||
default: ShouldNotReachHere();
|
||||
}
|
||||
|
||||
// Order preceding load(s) wrt. succeeding check (LoadStore for volatile field).
|
||||
if (is_fp) {
|
||||
Label next;
|
||||
__ fcmpu(CCR0, F1_RET, F1_RET);
|
||||
__ bne(CCR0, next);
|
||||
__ bind(next);
|
||||
} else {
|
||||
__ twi_0(Rtmp);
|
||||
}
|
||||
__ isync();
|
||||
|
||||
__ ld(R0, counter_offs, Rcounter_addr);
|
||||
__ cmpd(CCR0, R0, Rcounter);
|
||||
__ bne(CCR0, slow);
|
||||
|
||||
if (!is_fp) {
|
||||
__ mr(R3_RET, Rtmp);
|
||||
}
|
||||
__ blr();
|
||||
|
||||
slowcase_entry_pclist[count++] = __ pc();
|
||||
__ bind(slow);
|
||||
address slow_case_addr;
|
||||
switch (type) {
|
||||
case T_BOOLEAN: slow_case_addr = jni_GetBooleanField_addr(); break;
|
||||
case T_BYTE: slow_case_addr = jni_GetByteField_addr(); break;
|
||||
case T_CHAR: slow_case_addr = jni_GetCharField_addr(); break;
|
||||
case T_SHORT: slow_case_addr = jni_GetShortField_addr(); break;
|
||||
case T_INT: slow_case_addr = jni_GetIntField_addr(); break;
|
||||
case T_LONG: slow_case_addr = jni_GetLongField_addr(); break;
|
||||
case T_FLOAT: slow_case_addr = jni_GetFloatField_addr(); break;
|
||||
case T_DOUBLE: slow_case_addr = jni_GetDoubleField_addr(); break;
|
||||
default: ShouldNotReachHere();
|
||||
slow_case_addr = NULL; // unreachable
|
||||
}
|
||||
__ load_const_optimized(R12, slow_case_addr, R0);
|
||||
__ call_c_and_return_to_caller(R12); // tail call
|
||||
|
||||
__ flush();
|
||||
|
||||
return fast_entry;
|
||||
}
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_boolean_field() {
|
||||
@ -57,19 +179,13 @@ address JNI_FastGetField::generate_fast_get_int_field() {
|
||||
}
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_long_field() {
|
||||
// We don't have fast jni accessors.
|
||||
return (address) -1;
|
||||
}
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) {
|
||||
// We don't have fast jni accessors.
|
||||
return (address) -1;
|
||||
return generate_fast_get_int_field0(T_LONG);
|
||||
}
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_float_field() {
|
||||
return generate_fast_get_float_field0(T_FLOAT);
|
||||
return generate_fast_get_int_field0(T_FLOAT);
|
||||
}
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_double_field() {
|
||||
return generate_fast_get_float_field0(T_DOUBLE);
|
||||
return generate_fast_get_int_field0(T_DOUBLE);
|
||||
}
|
||||
|
@ -111,3 +111,9 @@ void BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value,
|
||||
__ verify_oop(value);
|
||||
__ bind(Ldone);
|
||||
}
|
||||
|
||||
void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,
|
||||
Register obj, Register tmp, Label& slowpath) {
|
||||
__ z_nill(obj, ~JNIHandles::weak_tag_mask);
|
||||
__ z_lg(obj, 0, obj); // Resolve (untagged) jobject.
|
||||
}
|
||||
|
@ -46,6 +46,9 @@ public:
|
||||
|
||||
virtual void resolve_jobject(MacroAssembler* masm, Register value, Register tmp1, Register tmp2);
|
||||
|
||||
virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,
|
||||
Register obj, Register tmp, Label& slowpath);
|
||||
|
||||
virtual void barrier_stubs_init() {}
|
||||
};
|
||||
|
||||
|
@ -24,8 +24,13 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "gc/shared/barrierSetAssembler.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "prims/jniFastGetField.hpp"
|
||||
#include "prims/jvm_misc.hpp"
|
||||
#include "runtime/safepoint.hpp"
|
||||
|
||||
// TSO ensures that loads are blocking and ordered with respect to
|
||||
// to earlier loads, so we don't need LoadLoad membars.
|
||||
@ -34,9 +39,103 @@
|
||||
|
||||
#define BUFFER_SIZE 30*sizeof(jint)
|
||||
|
||||
// Common register usage:
|
||||
// Z_RET/Z_FRET: result
|
||||
// Z_ARG1: jni env
|
||||
// Z_ARG2: obj
|
||||
// Z_ARG3: jfield id
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
|
||||
// Don't use fast jni accessors.
|
||||
return (address) -1;
|
||||
const char *name;
|
||||
switch (type) {
|
||||
case T_BOOLEAN: name = "jni_fast_GetBooleanField"; break;
|
||||
case T_BYTE: name = "jni_fast_GetByteField"; break;
|
||||
case T_CHAR: name = "jni_fast_GetCharField"; break;
|
||||
case T_SHORT: name = "jni_fast_GetShortField"; break;
|
||||
case T_INT: name = "jni_fast_GetIntField"; break;
|
||||
case T_LONG: name = "jni_fast_GetLongField"; break;
|
||||
case T_FLOAT: name = "jni_fast_GetFloatField"; break;
|
||||
case T_DOUBLE: name = "jni_fast_GetDoubleField"; break;
|
||||
default: ShouldNotReachHere();
|
||||
name = NULL; // unreachable
|
||||
}
|
||||
ResourceMark rm;
|
||||
BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE);
|
||||
CodeBuffer cbuf(blob);
|
||||
MacroAssembler* masm = new MacroAssembler(&cbuf);
|
||||
address fast_entry = __ pc();
|
||||
|
||||
Label slow;
|
||||
|
||||
// We can only kill the remaining volatile registers.
|
||||
const Register Rcounter = Z_ARG4,
|
||||
Robj = Z_R1_scratch,
|
||||
Rtmp = Z_R0_scratch;
|
||||
__ load_const_optimized(Robj, SafepointSynchronize::safepoint_counter_addr());
|
||||
__ z_lg(Rcounter, Address(Robj));
|
||||
__ z_tmll(Rcounter, 1);
|
||||
__ z_brnaz(slow);
|
||||
|
||||
if (JvmtiExport::can_post_field_access()) {
|
||||
// Check to see if a field access watch has been set before we
|
||||
// take the fast path.
|
||||
__ load_const_optimized(Robj, JvmtiExport::get_field_access_count_addr());
|
||||
__ z_lt(Robj, Address(Robj));
|
||||
__ z_brne(slow);
|
||||
}
|
||||
|
||||
__ z_lgr(Robj, Z_ARG2);
|
||||
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||
bs->try_resolve_jobject_in_native(masm, Z_ARG1, Robj, Rtmp, slow);
|
||||
|
||||
__ z_srlg(Rtmp, Z_ARG3, 2); // offset
|
||||
__ z_agr(Robj, Rtmp);
|
||||
|
||||
assert(count < LIST_CAPACITY, "LIST_CAPACITY too small");
|
||||
speculative_load_pclist[count] = __ pc(); // Used by the segfault handler
|
||||
bool is_fp = false;
|
||||
switch (type) {
|
||||
case T_BOOLEAN: __ z_llgc(Rtmp, Address(Robj)); break;
|
||||
case T_BYTE: __ z_lgb( Rtmp, Address(Robj)); break;
|
||||
case T_CHAR: __ z_llgh(Rtmp, Address(Robj)); break;
|
||||
case T_SHORT: __ z_lgh( Rtmp, Address(Robj)); break;
|
||||
case T_INT: __ z_lgf( Rtmp, Address(Robj)); break;
|
||||
case T_LONG: __ z_lg( Rtmp, Address(Robj)); break;
|
||||
case T_FLOAT: __ mem2freg_opt(Z_FRET, Address(Robj), false); is_fp = true; break;
|
||||
case T_DOUBLE: __ mem2freg_opt(Z_FRET, Address(Robj), true ); is_fp = true; break;
|
||||
default: ShouldNotReachHere();
|
||||
}
|
||||
|
||||
__ load_const_optimized(Robj, SafepointSynchronize::safepoint_counter_addr());
|
||||
__ z_cg(Rcounter, Address(Robj));
|
||||
__ z_brne(slow);
|
||||
|
||||
if (!is_fp) {
|
||||
__ z_lgr(Z_RET, Rtmp);
|
||||
}
|
||||
__ z_br(Z_R14);
|
||||
|
||||
slowcase_entry_pclist[count++] = __ pc();
|
||||
__ bind(slow);
|
||||
address slow_case_addr;
|
||||
switch (type) {
|
||||
case T_BOOLEAN: slow_case_addr = jni_GetBooleanField_addr(); break;
|
||||
case T_BYTE: slow_case_addr = jni_GetByteField_addr(); break;
|
||||
case T_CHAR: slow_case_addr = jni_GetCharField_addr(); break;
|
||||
case T_SHORT: slow_case_addr = jni_GetShortField_addr(); break;
|
||||
case T_INT: slow_case_addr = jni_GetIntField_addr(); break;
|
||||
case T_LONG: slow_case_addr = jni_GetLongField_addr(); break;
|
||||
case T_FLOAT: slow_case_addr = jni_GetFloatField_addr(); break;
|
||||
case T_DOUBLE: slow_case_addr = jni_GetDoubleField_addr(); break;
|
||||
default: ShouldNotReachHere();
|
||||
slow_case_addr = NULL; // unreachable
|
||||
}
|
||||
__ load_const_optimized(Robj, slow_case_addr);
|
||||
__ z_br(Robj); // tail call
|
||||
|
||||
__ flush();
|
||||
|
||||
return fast_entry;
|
||||
}
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_boolean_field() {
|
||||
@ -60,19 +159,13 @@ address JNI_FastGetField::generate_fast_get_int_field() {
|
||||
}
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_long_field() {
|
||||
// Don't use fast jni accessors.
|
||||
return (address) -1;
|
||||
}
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) {
|
||||
// Don't use fast jni accessors.
|
||||
return (address) -1;
|
||||
return generate_fast_get_int_field0(T_LONG);
|
||||
}
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_float_field() {
|
||||
return generate_fast_get_float_field0(T_FLOAT);
|
||||
return generate_fast_get_int_field0(T_FLOAT);
|
||||
}
|
||||
|
||||
address JNI_FastGetField::generate_fast_get_double_field() {
|
||||
return generate_fast_get_float_field0(T_DOUBLE);
|
||||
return generate_fast_get_int_field0(T_DOUBLE);
|
||||
}
|
||||
|
@ -477,6 +477,15 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// jni_fast_Get<Primitive>Field can trap at certain pc's if a GC kicks in
|
||||
// and the heap gets shrunk before the field access.
|
||||
if ((sig == SIGSEGV) || (sig == SIGBUS)) {
|
||||
address addr = JNI_FastGetField::find_slowcase_pc(pc);
|
||||
if (addr != (address)-1) {
|
||||
stub = addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
run_stub:
|
||||
|
@ -502,6 +502,15 @@ JVM_handle_linux_signal(int sig,
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// jni_fast_Get<Primitive>Field can trap at certain pc's if a GC kicks in
|
||||
// and the heap gets shrunk before the field access.
|
||||
if ((sig == SIGSEGV) || (sig == SIGBUS)) {
|
||||
address addr = JNI_FastGetField::find_slowcase_pc(pc);
|
||||
if (addr != (address)-1) {
|
||||
stub = addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stub != NULL) {
|
||||
|
@ -479,6 +479,15 @@ JVM_handle_linux_signal(int sig,
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// jni_fast_Get<Primitive>Field can trap at certain pc's if a GC kicks in
|
||||
// and the heap gets shrunk before the field access.
|
||||
if ((sig == SIGSEGV) || (sig == SIGBUS)) {
|
||||
address addr = JNI_FastGetField::find_slowcase_pc(pc);
|
||||
if (addr != (address)-1) {
|
||||
stub = addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stub != NULL) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user