8201543: Modularize C1 GC barriers

Reviewed-by: pliden, rbackman, rkennke
This commit is contained in:
Erik Österlund 2018-04-26 20:42:43 +02:00
parent 0ef11c31c7
commit f4893f5a9a
63 changed files with 3484 additions and 3401 deletions

View File

@ -32,7 +32,7 @@ $(eval $(call IncludeCustomExtension, hotspot/lib/JvmFeatures.gmk))
ifeq ($(call check-jvm-feature, compiler1), true)
JVM_CFLAGS_FEATURES += -DCOMPILER1
else
JVM_EXCLUDE_PATTERNS += c1_
JVM_EXCLUDE_PATTERNS += c1_ c1/
endif
ifeq ($(call check-jvm-feature, compiler2), true)

View File

@ -32,9 +32,6 @@
#include "nativeInst_aarch64.hpp"
#include "runtime/sharedRuntime.hpp"
#include "vmreg_aarch64.inline.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#endif
#define __ ce->masm()->
@ -350,42 +347,4 @@ void ArrayCopyStub::emit_code(LIR_Assembler* ce) {
__ b(_continuation);
}
/////////////////////////////////////////////////////////////////////////////
#if INCLUDE_ALL_GCS
void G1PreBarrierStub::emit_code(LIR_Assembler* ce) {
// At this point we know that marking is in progress.
// If do_load() is true then we have to emit the
// load of the previous value; otherwise it has already
// been loaded into _pre_val.
__ bind(_entry);
assert(pre_val()->is_register(), "Precondition.");
Register pre_val_reg = pre_val()->as_register();
if (do_load()) {
ce->mem2reg(addr(), pre_val(), T_OBJECT, patch_code(), info(), false /*wide*/, false /*unaligned*/);
}
__ cbz(pre_val_reg, _continuation);
ce->store_parameter(pre_val()->as_register(), 0);
__ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::g1_pre_barrier_slow_id)));
__ b(_continuation);
}
void G1PostBarrierStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
assert(addr()->is_register(), "Precondition.");
assert(new_val()->is_register(), "Precondition.");
Register new_val_reg = new_val()->as_register();
__ cbz(new_val_reg, _continuation);
ce->store_parameter(addr()->as_pointer_register(), 0);
__ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::g1_post_barrier_slow_id)));
__ b(_continuation);
}
#endif // INCLUDE_ALL_GCS
/////////////////////////////////////////////////////////////////////////////
#undef __

View File

@ -1558,7 +1558,16 @@ void LIR_Assembler::casl(Register addr, Register newval, Register cmpval) {
void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) {
assert(VM_Version::supports_cx8(), "wrong machine");
Register addr = as_reg(op->addr());
Register addr;
if (op->addr()->is_register()) {
addr = as_reg(op->addr());
} else {
assert(op->addr()->is_address(), "what else?");
LIR_Address* addr_ptr = op->addr()->as_address_ptr();
assert(addr_ptr->disp() == 0, "need 0 disp");
assert(addr_ptr->index() == LIR_OprDesc::illegalOpr(), "need 0 index");
addr = as_reg(addr_ptr->base());
}
Register newval = as_reg(op->new_value());
Register cmpval = as_reg(op->cmp_value());
Label succeed, fail, around;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -144,8 +144,22 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index,
// accumulate fixed displacements
if (index->is_constant()) {
large_disp += (intx)(index->as_constant_ptr()->as_jint()) << shift;
index = LIR_OprFact::illegalOpr;
LIR_Const *constant = index->as_constant_ptr();
if (constant->type() == T_INT) {
large_disp += index->as_jint() << shift;
} else {
assert(constant->type() == T_LONG, "should be");
jlong c = index->as_jlong() << shift;
if ((jlong)((jint)c) == c) {
large_disp += c;
index = LIR_OprFact::illegalOpr;
} else {
LIR_Opr tmp = new_register(T_LONG);
__ move(index, tmp);
index = tmp;
// apply shift and displacement below
}
}
}
if (index->is_register()) {
@ -183,9 +197,8 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index,
}
}
LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr,
BasicType type, bool needs_card_mark) {
BasicType type) {
int offset_in_bytes = arrayOopDesc::base_offset_in_bytes(type);
int elem_size = type2aelembytes(type);
int shift = exact_log2(elem_size);
@ -206,16 +219,7 @@ LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_o
LIR_Address::scale(type),
offset_in_bytes, type);
}
if (needs_card_mark) {
// This store will need a precise card mark, so go ahead and
// compute the full adddres instead of computing once for the
// store and again for the card mark.
LIR_Opr tmp = new_pointer_register();
__ leal(LIR_OprFact::address(addr), tmp);
return new LIR_Address(tmp, type);
} else {
return addr;
}
return addr;
}
LIR_Opr LIRGenerator::load_immediate(int x, BasicType type) {
@ -305,87 +309,17 @@ void LIRGenerator::store_stack_parameter (LIR_Opr item, ByteSize offset_from_sp)
__ store(item, new LIR_Address(FrameMap::sp_opr, in_bytes(offset_from_sp), type));
}
//----------------------------------------------------------------------
// visitor functions
//----------------------------------------------------------------------
void LIRGenerator::do_StoreIndexed(StoreIndexed* x) {
assert(x->is_pinned(),"");
bool needs_range_check = x->compute_needs_range_check();
bool use_length = x->length() != NULL;
bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT;
bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL ||
!get_jobject_constant(x->value())->is_null_object() ||
x->should_profile());
LIRItem array(x->array(), this);
LIRItem index(x->index(), this);
LIRItem value(x->value(), this);
LIRItem length(this);
array.load_item();
index.load_nonconstant();
if (use_length && needs_range_check) {
length.set_instruction(x->length());
length.load_item();
}
if (needs_store_check || x->check_boolean()) {
value.load_item();
} else {
value.load_for_store(x->elt_type());
}
set_no_result(x);
// the CodeEmitInfo must be duplicated for each different
// LIR-instruction because spilling can occur anywhere between two
// instructions and so the debug information must be different
CodeEmitInfo* range_check_info = state_for(x);
CodeEmitInfo* null_check_info = NULL;
if (x->needs_null_check()) {
null_check_info = new CodeEmitInfo(range_check_info);
}
// emit array address setup early so it schedules better
// FIXME? No harm in this on aarch64, and it might help
LIR_Address* array_addr = emit_array_address(array.result(), index.result(), x->elt_type(), obj_store);
if (GenerateRangeChecks && needs_range_check) {
if (use_length) {
__ cmp(lir_cond_belowEqual, length.result(), index.result());
__ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result()));
} else {
array_range_check(array.result(), index.result(), null_check_info, range_check_info);
// range_check also does the null check
null_check_info = NULL;
}
}
if (GenerateArrayStoreCheck && needs_store_check) {
void LIRGenerator::array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, ciMethod* profiled_method, int profiled_bci) {
LIR_Opr tmp1 = new_register(objectType);
LIR_Opr tmp2 = new_register(objectType);
LIR_Opr tmp3 = new_register(objectType);
CodeEmitInfo* store_check_info = new CodeEmitInfo(range_check_info);
__ store_check(value.result(), array.result(), tmp1, tmp2, tmp3, store_check_info, x->profiled_method(), x->profiled_bci());
}
if (obj_store) {
// Needs GC write barriers.
pre_barrier(LIR_OprFact::address(array_addr), LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
__ move(value.result(), array_addr, null_check_info);
// Seems to be a precise
post_barrier(LIR_OprFact::address(array_addr), value.result());
} else {
LIR_Opr result = maybe_mask_boolean(x, array.result(), value.result(), null_check_info);
__ move(result, array_addr, null_check_info);
}
__ store_check(value, array, tmp1, tmp2, tmp3, store_check_info, profiled_method, profiled_bci);
}
//----------------------------------------------------------------------
// visitor functions
//----------------------------------------------------------------------
void LIRGenerator::do_MonitorEnter(MonitorEnter* x) {
assert(x->is_pinned(),"");
LIRItem obj(x->obj(), this);
@ -771,76 +705,42 @@ void LIRGenerator::do_CompareOp(CompareOp* x) {
}
}
void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) {
assert(x->number_of_arguments() == 4, "wrong type");
LIRItem obj (x->argument_at(0), this); // object
LIRItem offset(x->argument_at(1), this); // offset of field
LIRItem cmp (x->argument_at(2), this); // value to compare with field
LIRItem val (x->argument_at(3), this); // replace field with val if matches cmp
assert(obj.type()->tag() == objectTag, "invalid type");
// In 64bit the type can be long, sparc doesn't have this assert
// assert(offset.type()->tag() == intTag, "invalid type");
assert(cmp.type()->tag() == type->tag(), "invalid type");
assert(val.type()->tag() == type->tag(), "invalid type");
// get address of field
obj.load_item();
offset.load_nonconstant();
val.load_item();
cmp.load_item();
LIR_Address* a;
if(offset.result()->is_constant()) {
jlong c = offset.result()->as_jlong();
if ((jlong)((jint)c) == c) {
a = new LIR_Address(obj.result(),
(jint)c,
as_BasicType(type));
} else {
LIR_Opr tmp = new_register(T_LONG);
__ move(offset.result(), tmp);
a = new LIR_Address(obj.result(),
tmp,
as_BasicType(type));
}
} else {
a = new LIR_Address(obj.result(),
offset.result(),
0,
as_BasicType(type));
}
LIR_Opr addr = new_pointer_register();
__ leal(LIR_OprFact::address(a), addr);
if (type == objectType) { // Write-barrier needed for Object fields.
// Do the pre-write barrier, if any.
pre_barrier(addr, LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
}
LIR_Opr result = rlock_result(x);
LIR_Opr LIRGenerator::atomic_cmpxchg(BasicType type, LIR_Opr addr, LIRItem& cmp_value, LIRItem& new_value) {
LIR_Opr ill = LIR_OprFact::illegalOpr; // for convenience
if (type == objectType)
__ cas_obj(addr, cmp.result(), val.result(), new_register(T_INT), new_register(T_INT),
result);
else if (type == intType)
__ cas_int(addr, cmp.result(), val.result(), ill, ill);
else if (type == longType)
__ cas_long(addr, cmp.result(), val.result(), ill, ill);
else {
new_value.load_item();
cmp_value.load_item();
LIR_Opr result = new_register(T_INT);
if (type == T_OBJECT || type == T_ARRAY) {
__ cas_obj(addr, cmp_value.result(), new_value.result(), new_register(T_INT), new_register(T_INT), result);
} else if (type == T_INT) {
__ cas_int(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), ill, ill);
} else if (type == T_LONG) {
__ cas_long(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), ill, ill);
} else {
ShouldNotReachHere();
Unimplemented();
}
__ logical_xor(FrameMap::r8_opr, LIR_OprFact::intConst(1), result);
return result;
}
if (type == objectType) { // Write-barrier needed for Object fields.
// Seems to be precise
post_barrier(addr, val.result());
}
LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) {
bool is_oop = type == T_OBJECT || type == T_ARRAY;
LIR_Opr result = new_register(type);
value.load_item();
assert(type == T_INT || is_oop LP64_ONLY( || type == T_LONG ), "unexpected type");
LIR_Opr tmp = new_register(T_INT);
__ xchg(addr, value.result(), result, tmp);
return result;
}
LIR_Opr LIRGenerator::atomic_add(BasicType type, LIR_Opr addr, LIRItem& value) {
LIR_Opr result = new_register(type);
value.load_item();
assert(type == T_INT LP64_ONLY( || type == T_LONG ), "unexpected type");
LIR_Opr tmp = new_register(T_INT);
__ xadd(addr, value.result(), result, tmp);
return result;
}
void LIRGenerator::do_MathIntrinsic(Intrinsic* x) {
@ -1433,84 +1333,3 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result,
__ volatile_load_mem_reg(address, result, info);
}
void LIRGenerator::get_Object_unsafe(LIR_Opr dst, LIR_Opr src, LIR_Opr offset,
BasicType type, bool is_volatile) {
LIR_Address* addr = new LIR_Address(src, offset, type);
__ load(addr, dst);
}
void LIRGenerator::put_Object_unsafe(LIR_Opr src, LIR_Opr offset, LIR_Opr data,
BasicType type, bool is_volatile) {
LIR_Address* addr = new LIR_Address(src, offset, type);
bool is_obj = (type == T_ARRAY || type == T_OBJECT);
if (is_obj) {
// Do the pre-write barrier, if any.
pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
__ move(data, addr);
assert(src->is_register(), "must be register");
// Seems to be a precise address
post_barrier(LIR_OprFact::address(addr), data);
} else {
__ move(data, addr);
}
}
void LIRGenerator::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {
BasicType type = x->basic_type();
LIRItem src(x->object(), this);
LIRItem off(x->offset(), this);
LIRItem value(x->value(), this);
src.load_item();
off.load_nonconstant();
// We can cope with a constant increment in an xadd
if (! (x->is_add()
&& value.is_constant()
&& can_inline_as_constant(x->value()))) {
value.load_item();
}
LIR_Opr dst = rlock_result(x, type);
LIR_Opr data = value.result();
bool is_obj = (type == T_ARRAY || type == T_OBJECT);
LIR_Opr offset = off.result();
if (data == dst) {
LIR_Opr tmp = new_register(data->type());
__ move(data, tmp);
data = tmp;
}
LIR_Address* addr;
if (offset->is_constant()) {
jlong l = offset->as_jlong();
assert((jlong)((jint)l) == l, "offset too large for constant");
jint c = (jint)l;
addr = new LIR_Address(src.result(), c, type);
} else {
addr = new LIR_Address(src.result(), offset, type);
}
LIR_Opr tmp = new_register(T_INT);
LIR_Opr ptr = LIR_OprFact::illegalOpr;
if (x->is_add()) {
__ xadd(LIR_OprFact::address(addr), data, dst, tmp);
} else {
if (is_obj) {
// Do the pre-write barrier, if any.
ptr = new_pointer_register();
__ add(src.result(), off.result(), ptr);
pre_barrier(ptr, LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
}
__ xchg(LIR_OprFact::address(addr), data, dst, tmp);
if (is_obj) {
post_barrier(ptr, data);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -358,6 +358,16 @@ void C1_MacroAssembler::remove_frame(int framesize) {
void C1_MacroAssembler::verified_entry() {
}
void C1_MacroAssembler::load_parameter(int offset_in_words, Register reg) {
// rbp, + 0: link
// + 1: return address
// + 2: argument with offset 0
// + 3: argument with offset 1
// + 4: ...
ldr(reg, Address(rfp, (offset_in_words + 2) * BytesPerWord));
}
#ifndef PRODUCT
void C1_MacroAssembler::verify_stack_oop(int stack_offset) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -109,4 +109,6 @@ using MacroAssembler::null_check;
// This platform only uses signal-based null checks. The Label is not needed.
void null_check(Register r, Label *Lnull = NULL) { MacroAssembler::null_check(r); }
void load_parameter(int offset_in_words, Register reg);
#endif // CPU_AARCH64_VM_C1_MACROASSEMBLER_AARCH64_HPP

View File

@ -43,11 +43,6 @@
#include "runtime/vframe.hpp"
#include "runtime/vframeArray.hpp"
#include "vmreg_aarch64.inline.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CardTable.hpp"
#include "gc/g1/g1ThreadLocalData.hpp"
#endif
// Implementation of StubAssembler
@ -173,31 +168,32 @@ class StubFrame: public StackObj {
~StubFrame();
};;
void StubAssembler::prologue(const char* name, bool must_gc_arguments) {
set_info(name, must_gc_arguments);
enter();
}
void StubAssembler::epilogue() {
leave();
ret(lr);
}
#define __ _sasm->
StubFrame::StubFrame(StubAssembler* sasm, const char* name, bool must_gc_arguments) {
_sasm = sasm;
__ set_info(name, must_gc_arguments);
__ enter();
__ prologue(name, must_gc_arguments);
}
// load parameters that were stored with LIR_Assembler::store_parameter
// Note: offsets for store_parameter and load_argument must match
void StubFrame::load_argument(int offset_in_words, Register reg) {
// rbp, + 0: link
// + 1: return address
// + 2: argument with offset 0
// + 3: argument with offset 1
// + 4: ...
__ ldr(reg, Address(rfp, (offset_in_words + 2) * BytesPerWord));
__ load_parameter(offset_in_words, reg);
}
StubFrame::~StubFrame() {
__ leave();
__ ret(lr);
__ epilogue();
}
#undef __
@ -1100,136 +1096,6 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
#if INCLUDE_ALL_GCS
case g1_pre_barrier_slow_id:
{
StubFrame f(sasm, "g1_pre_barrier", dont_gc_arguments);
// arg0 : previous value of memory
BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ mov(r0, (int)id);
__ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), r0);
__ should_not_reach_here();
break;
}
const Register pre_val = r0;
const Register thread = rthread;
const Register tmp = rscratch1;
Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
Address queue_index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
Label done;
Label runtime;
// Is marking still active?
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
__ ldrw(tmp, in_progress);
} else {
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
__ ldrb(tmp, in_progress);
}
__ cbzw(tmp, done);
// Can we store original value in the thread's buffer?
__ ldr(tmp, queue_index);
__ cbz(tmp, runtime);
__ sub(tmp, tmp, wordSize);
__ str(tmp, queue_index);
__ ldr(rscratch2, buffer);
__ add(tmp, tmp, rscratch2);
f.load_argument(0, rscratch2);
__ str(rscratch2, Address(tmp, 0));
__ b(done);
__ bind(runtime);
__ push_call_clobbered_registers();
f.load_argument(0, pre_val);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), pre_val, thread);
__ pop_call_clobbered_registers();
__ bind(done);
}
break;
case g1_post_barrier_slow_id:
{
StubFrame f(sasm, "g1_post_barrier", dont_gc_arguments);
BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ mov(r0, (int)id);
__ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), r0);
__ should_not_reach_here();
break;
}
// arg0: store_address
Address store_addr(rfp, 2*BytesPerWord);
Label done;
Label runtime;
// At this point we know new_value is non-NULL and the new_value crosses regions.
// Must check to see if card is already dirty
const Register thread = rthread;
Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
const Register card_offset = rscratch2;
// LR is free here, so we can use it to hold the byte_map_base.
const Register byte_map_base = lr;
assert_different_registers(card_offset, byte_map_base, rscratch1);
f.load_argument(0, card_offset);
__ lsr(card_offset, card_offset, CardTable::card_shift);
__ load_byte_map_base(byte_map_base);
__ ldrb(rscratch1, Address(byte_map_base, card_offset));
__ cmpw(rscratch1, (int)G1CardTable::g1_young_card_val());
__ br(Assembler::EQ, done);
assert((int)CardTable::dirty_card_val() == 0, "must be 0");
__ membar(Assembler::StoreLoad);
__ ldrb(rscratch1, Address(byte_map_base, card_offset));
__ cbzw(rscratch1, done);
// storing region crossing non-NULL, card is clean.
// dirty card and log.
__ strb(zr, Address(byte_map_base, card_offset));
// Convert card offset into an address in card_addr
Register card_addr = card_offset;
__ add(card_addr, byte_map_base, card_addr);
__ ldr(rscratch1, queue_index);
__ cbz(rscratch1, runtime);
__ sub(rscratch1, rscratch1, wordSize);
__ str(rscratch1, queue_index);
// Reuse LR to hold buffer_addr
const Register buffer_addr = lr;
__ ldr(buffer_addr, buffer);
__ str(card_addr, Address(buffer_addr, rscratch1));
__ b(done);
__ bind(runtime);
__ push_call_clobbered_registers();
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, thread);
__ pop_call_clobbered_registers();
__ bind(done);
}
break;
#endif
case predicate_failed_trap_id:
{
StubFrame f(sasm, "predicate_failed_trap", dont_gc_arguments);

View File

@ -24,6 +24,9 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "c1/c1_LIRAssembler.hpp"
#include "c1/c1_MacroAssembler.hpp"
#include "gc/g1/c1/g1BarrierSetC1.hpp"
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1BarrierSetAssembler.hpp"
#include "gc/g1/g1CardTable.hpp"
@ -307,4 +310,167 @@ void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet deco
}
#ifdef COMPILER1
#undef __
#define __ ce->masm()->
void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) {
G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
// At this point we know that marking is in progress.
// If do_load() is true then we have to emit the
// load of the previous value; otherwise it has already
// been loaded into _pre_val.
__ bind(*stub->entry());
assert(stub->pre_val()->is_register(), "Precondition.");
Register pre_val_reg = stub->pre_val()->as_register();
if (stub->do_load()) {
ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/, false /*unaligned*/);
}
__ cbz(pre_val_reg, *stub->continuation());
ce->store_parameter(stub->pre_val()->as_register(), 0);
__ far_call(RuntimeAddress(bs->pre_barrier_c1_runtime_code_blob()->code_begin()));
__ b(*stub->continuation());
}
void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) {
G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
__ bind(*stub->entry());
assert(stub->addr()->is_register(), "Precondition.");
assert(stub->new_val()->is_register(), "Precondition.");
Register new_val_reg = stub->new_val()->as_register();
__ cbz(new_val_reg, *stub->continuation());
ce->store_parameter(stub->addr()->as_pointer_register(), 0);
__ far_call(RuntimeAddress(bs->post_barrier_c1_runtime_code_blob()->code_begin()));
__ b(*stub->continuation());
}
#undef __
#define __ sasm->
void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) {
__ prologue("g1_pre_barrier", false);
// arg0 : previous value of memory
BarrierSet* bs = BarrierSet::barrier_set();
const Register pre_val = r0;
const Register thread = rthread;
const Register tmp = rscratch1;
Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
Address queue_index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
Label done;
Label runtime;
// Is marking still active?
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
__ ldrw(tmp, in_progress);
} else {
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
__ ldrb(tmp, in_progress);
}
__ cbzw(tmp, done);
// Can we store original value in the thread's buffer?
__ ldr(tmp, queue_index);
__ cbz(tmp, runtime);
__ sub(tmp, tmp, wordSize);
__ str(tmp, queue_index);
__ ldr(rscratch2, buffer);
__ add(tmp, tmp, rscratch2);
__ load_parameter(0, rscratch2);
__ str(rscratch2, Address(tmp, 0));
__ b(done);
__ bind(runtime);
__ push_call_clobbered_registers();
__ load_parameter(0, pre_val);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), pre_val, thread);
__ pop_call_clobbered_registers();
__ bind(done);
__ epilogue();
}
void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) {
__ prologue("g1_post_barrier", false);
// arg0: store_address
Address store_addr(rfp, 2*BytesPerWord);
BarrierSet* bs = BarrierSet::barrier_set();
CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
CardTable* ct = ctbs->card_table();
assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
Label done;
Label runtime;
// At this point we know new_value is non-NULL and the new_value crosses regions.
// Must check to see if card is already dirty
const Register thread = rthread;
Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
const Register card_offset = rscratch2;
// LR is free here, so we can use it to hold the byte_map_base.
const Register byte_map_base = lr;
assert_different_registers(card_offset, byte_map_base, rscratch1);
__ load_parameter(0, card_offset);
__ lsr(card_offset, card_offset, CardTable::card_shift);
__ load_byte_map_base(byte_map_base);
__ ldrb(rscratch1, Address(byte_map_base, card_offset));
__ cmpw(rscratch1, (int)G1CardTable::g1_young_card_val());
__ br(Assembler::EQ, done);
assert((int)CardTable::dirty_card_val() == 0, "must be 0");
__ membar(Assembler::StoreLoad);
__ ldrb(rscratch1, Address(byte_map_base, card_offset));
__ cbzw(rscratch1, done);
// storing region crossing non-NULL, card is clean.
// dirty card and log.
__ strb(zr, Address(byte_map_base, card_offset));
// Convert card offset into an address in card_addr
Register card_addr = card_offset;
__ add(card_addr, byte_map_base, card_addr);
__ ldr(rscratch1, queue_index);
__ cbz(rscratch1, runtime);
__ sub(rscratch1, rscratch1, wordSize);
__ str(rscratch1, queue_index);
// Reuse LR to hold buffer_addr
const Register buffer_addr = lr;
__ ldr(buffer_addr, buffer);
__ str(card_addr, Address(buffer_addr, rscratch1));
__ b(done);
__ bind(runtime);
__ push_call_clobbered_registers();
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, thread);
__ pop_call_clobbered_registers();
__ bind(done);
__ epilogue();
}
#undef __
#endif // COMPILER1

View File

@ -27,6 +27,12 @@
#include "asm/macroAssembler.hpp"
#include "gc/shared/modRefBarrierSetAssembler.hpp"
#include "utilities/macros.hpp"
class LIR_Assembler;
class StubAssembler;
class G1PreBarrierStub;
class G1PostBarrierStub;
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
@ -54,6 +60,14 @@ protected:
Address dst, Register val, Register tmp1, Register tmp2);
public:
#ifdef COMPILER1
void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub);
void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
#endif
void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register dst, Address src, Register tmp1, Register tmp_thread);
};

View File

@ -33,9 +33,6 @@
#include "runtime/sharedRuntime.hpp"
#include "utilities/macros.hpp"
#include "vmreg_arm.inline.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#endif // INCLUDE_ALL_GCS
#define __ ce->masm()->
@ -466,45 +463,4 @@ void ArrayCopyStub::emit_code(LIR_Assembler* ce) {
__ b(_continuation);
}
/////////////////////////////////////////////////////////////////////////////
#if INCLUDE_ALL_GCS
void G1PreBarrierStub::emit_code(LIR_Assembler* ce) {
// At this point we know that marking is in progress.
// If do_load() is true then we have to emit the
// load of the previous value; otherwise it has already
// been loaded into _pre_val.
__ bind(_entry);
assert(pre_val()->is_register(), "Precondition.");
Register pre_val_reg = pre_val()->as_register();
if (do_load()) {
ce->mem2reg(addr(), pre_val(), T_OBJECT, patch_code(), info(), false /*wide*/, false /*unaligned*/);
}
__ cbz(pre_val_reg, _continuation);
ce->verify_reserved_argument_area_size(1);
__ str(pre_val_reg, Address(SP));
__ call(Runtime1::entry_for(Runtime1::g1_pre_barrier_slow_id), relocInfo::runtime_call_type);
__ b(_continuation);
}
void G1PostBarrierStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
assert(addr()->is_register(), "Precondition.");
assert(new_val()->is_register(), "Precondition.");
Register new_val_reg = new_val()->as_register();
__ cbz(new_val_reg, _continuation);
ce->verify_reserved_argument_area_size(1);
__ str(addr()->as_pointer_register(), Address(SP));
__ call(Runtime1::entry_for(Runtime1::g1_post_barrier_slow_id), relocInfo::runtime_call_type);
__ b(_continuation);
}
#endif // INCLUDE_ALL_GCS
/////////////////////////////////////////////////////////////////////////////
#undef __

View File

@ -34,6 +34,7 @@
#include "ci/ciObjArrayKlass.hpp"
#include "ci/ciTypeArrayKlass.hpp"
#include "ci/ciUtilities.hpp"
#include "gc/shared/c1/barrierSetC1.hpp"
#include "gc/shared/cardTable.hpp"
#include "gc/shared/cardTableBarrierSet.hpp"
#include "runtime/sharedRuntime.hpp"
@ -542,88 +543,17 @@ void LIRGenerator::CardTableBarrierSet_post_barrier_helper(LIR_OprDesc* addr, LI
}
}
void LIRGenerator::array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, ciMethod* profiled_method, int profiled_bci) {
LIR_Opr tmp1 = FrameMap::R0_oop_opr;
LIR_Opr tmp2 = FrameMap::R1_oop_opr;
LIR_Opr tmp3 = LIR_OprFact::illegalOpr;
__ store_check(value, array, tmp1, tmp2, tmp3, store_check_info, profiled_method, profiled_bci);
}
//----------------------------------------------------------------------
// visitor functions
//----------------------------------------------------------------------
void LIRGenerator::do_StoreIndexed(StoreIndexed* x) {
assert(x->is_pinned(),"");
bool needs_range_check = x->compute_needs_range_check();
bool use_length = x->length() != NULL;
bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT;
bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL ||
!get_jobject_constant(x->value())->is_null_object() ||
x->should_profile());
LIRItem array(x->array(), this);
LIRItem index(x->index(), this);
LIRItem value(x->value(), this);
LIRItem length(this);
array.load_item();
index.load_nonconstant();
if (use_length && needs_range_check) {
length.set_instruction(x->length());
length.load_item();
}
if (needs_store_check || x->check_boolean()) {
value.load_item();
} else {
value.load_for_store(x->elt_type());
}
set_no_result(x);
// the CodeEmitInfo must be duplicated for each different
// LIR-instruction because spilling can occur anywhere between two
// instructions and so the debug information must be different
CodeEmitInfo* range_check_info = state_for(x);
CodeEmitInfo* null_check_info = NULL;
if (x->needs_null_check()) {
null_check_info = new CodeEmitInfo(range_check_info);
}
// emit array address setup early so it schedules better
LIR_Address* array_addr = emit_array_address(array.result(), index.result(), x->elt_type(), obj_store);
if (GenerateRangeChecks && needs_range_check) {
if (use_length) {
__ cmp(lir_cond_belowEqual, length.result(), index.result());
__ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result()));
} else {
array_range_check(array.result(), index.result(), null_check_info, range_check_info);
// range_check also does the null check
null_check_info = NULL;
}
}
if (GenerateArrayStoreCheck && needs_store_check) {
LIR_Opr tmp1 = FrameMap::R0_oop_opr;
LIR_Opr tmp2 = FrameMap::R1_oop_opr;
CodeEmitInfo* store_check_info = new CodeEmitInfo(range_check_info);
__ store_check(value.result(), array.result(), tmp1, tmp2,
LIR_OprFact::illegalOpr, store_check_info,
x->profiled_method(), x->profiled_bci());
}
#if INCLUDE_ALL_GCS
if (obj_store) {
// Needs GC write barriers.
pre_barrier(LIR_OprFact::address(array_addr), LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
}
#endif // INCLUDE_ALL_GCS
LIR_Opr result = maybe_mask_boolean(x, array.result(), value.result(), null_check_info);
__ move(result, array_addr, null_check_info);
if (obj_store) {
post_barrier(LIR_OprFact::address(array_addr), value.result());
}
}
void LIRGenerator::do_MonitorEnter(MonitorEnter* x) {
assert(x->is_pinned(),"");
LIRItem obj(x->obj(), this);
@ -1060,56 +990,52 @@ void LIRGenerator::do_CompareOp(CompareOp* x) {
#endif // __SOFTFP__
}
void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) {
assert(x->number_of_arguments() == 4, "wrong type");
LIRItem obj (x->argument_at(0), this); // object
LIRItem offset(x->argument_at(1), this); // offset of field
LIRItem cmp (x->argument_at(2), this); // value to compare with field
LIRItem val (x->argument_at(3), this); // replace field with val if matches cmp
LIR_Opr addr = new_pointer_register();
LIR_Opr LIRGenerator::atomic_cmpxchg(BasicType type, LIR_Opr addr, LIRItem& cmp_value, LIRItem& new_value) {
LIR_Opr ill = LIR_OprFact::illegalOpr; // for convenience
LIR_Opr tmp1 = LIR_OprFact::illegalOpr;
LIR_Opr tmp2 = LIR_OprFact::illegalOpr;
// get address of field
obj.load_item();
offset.load_item();
cmp.load_item();
val.load_item();
__ add(obj.result(), offset.result(), addr);
LIR_Opr result = rlock_result(x);
if (type == objectType) {
#if INCLUDE_ALL_GCS
// Do the pre-write barrier, if any.
pre_barrier(addr, LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
#endif // INCLUDE_ALL_GCS
new_value.load_item();
cmp_value.load_item();
LIR_Opr result = new_register(T_INT);
if (type == T_OBJECT || type == T_ARRAY) {
#ifdef AARCH64
if (UseCompressedOops) {
tmp1 = new_pointer_register();
tmp2 = new_pointer_register();
}
#endif // AARCH64
__ cas_obj(addr, cmp.result(), val.result(), tmp1, tmp2, result);
post_barrier(addr, val.result());
}
else if (type == intType) {
__ cas_int(addr, cmp.result(), val.result(), tmp1, tmp1, result);
}
else if (type == longType) {
#endif
__ cas_obj(addr, cmp_value.result(), new_value.result(), new_register(T_INT), new_register(T_INT), result);
} else if (type == T_INT) {
__ cas_int(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), tmp1, tmp1, result);
} else if (type == T_LONG) {
#ifndef AARCH64
tmp1 = new_register(T_LONG);
#endif // !AARCH64
__ cas_long(addr, cmp.result(), val.result(), tmp1, tmp2, result);
}
else {
__ cas_long(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), tmp1, tmp2, result);
} else {
ShouldNotReachHere();
}
return result;
}
LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) {
bool is_oop = type == T_OBJECT || type == T_ARRAY;
LIR_Opr result = new_register(type);
value.load_item();
assert(type == T_INT || is_oop LP64_ONLY( || type == T_LONG ), "unexpected type");
LIR_Opr tmp = (UseCompressedOops && is_oop) ? new_pointer_register() : LIR_OprFact::illegalOpr;
__ xchg(addr_ptr, data, dst, tmp);
return result;
}
LIR_Opr LIRGenerator::atomic_add(BasicType type, LIR_Opr addr, LIRItem& value) {
LIR_Opr result = new_register(type);
value.load_item();
assert(type == T_INT LP64_ONLY( || type == T_LONG), "unexpected type");
LIR_Opr tmp = new_register(type);
__ xadd(addr, value.result(), result, tmp);
return result;
}
void LIRGenerator::do_MathIntrinsic(Intrinsic* x) {
address runtime_func;
@ -1669,110 +1595,3 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result,
// TODO-AARCH64 implement with ldar instruction
__ load(address, result, info, lir_patch_none);
}
void LIRGenerator::get_Object_unsafe(LIR_Opr dst, LIR_Opr src, LIR_Opr offset,
BasicType type, bool is_volatile) {
#ifdef AARCH64
__ load(new LIR_Address(src, offset, type), dst);
#else
assert(offset->is_single_cpu(), "must be");
if (is_volatile && dst->is_double_cpu()) {
LIR_Opr tmp = new_pointer_register();
__ add(src, offset, tmp);
__ volatile_load_mem_reg(new LIR_Address(tmp, (intx)0, type), dst, NULL);
} else if (type == T_FLOAT || type == T_DOUBLE) {
// fld doesn't have indexed addressing mode
LIR_Opr tmp = new_register(T_INT);
__ add(src, offset, tmp);
__ load(new LIR_Address(tmp, (intx)0, type), dst);
} else {
__ load(new LIR_Address(src, offset, type), dst);
}
#endif // AARCH64
}
void LIRGenerator::put_Object_unsafe(LIR_Opr src, LIR_Opr offset, LIR_Opr data,
BasicType type, bool is_volatile) {
#ifdef AARCH64
LIR_Address* addr = new LIR_Address(src, offset, type);
if (type == T_ARRAY || type == T_OBJECT) {
pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
__ move(data, addr);
assert(src->is_register(), "must be register");
post_barrier(LIR_OprFact::address(addr), data);
} else {
__ move(data, addr);
}
#else
assert(offset->is_single_cpu(), "must be");
if (is_volatile && data->is_double_cpu()) {
LIR_Opr tmp = new_register(T_INT);
__ add(src, offset, tmp);
__ volatile_store_mem_reg(data, new LIR_Address(tmp, (intx)0, type), NULL);
} else if (type == T_FLOAT || type == T_DOUBLE) {
// fst doesn't have indexed addressing mode
LIR_Opr tmp = new_register(T_INT);
__ add(src, offset, tmp);
__ move(data, new LIR_Address(tmp, (intx)0, type));
} else {
LIR_Address* addr = new LIR_Address(src, offset, type);
bool is_obj = (type == T_ARRAY || type == T_OBJECT);
#if INCLUDE_ALL_GCS
if (is_obj) {
// Do the pre-write barrier, if any.
pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
}
#endif // INCLUDE_ALL_GCS
__ move(data, addr);
if (is_obj) {
assert(src->is_register(), "must be register");
post_barrier(LIR_OprFact::address(addr), data);
}
}
#endif // AARCH64
}
void LIRGenerator::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {
BasicType type = x->basic_type();
LIRItem src(x->object(), this);
LIRItem off(x->offset(), this);
LIRItem value(x->value(), this);
src.load_item();
if (x->is_add()) {
value.load_nonconstant();
} else {
value.load_item();
}
off.load_nonconstant();
LIR_Opr dst = rlock_result(x, type);
LIR_Opr data = value.result();
bool is_obj = (type == T_ARRAY || type == T_OBJECT);
assert (type == T_INT || type == T_LONG || (!x->is_add() && is_obj), "unexpected type");
LIR_Opr addr_ptr = new_pointer_register();
__ add(src.result(), off.result(), addr_ptr);
LIR_Address* addr = new LIR_Address(addr_ptr, (intx)0, type);
if (x->is_add()) {
LIR_Opr tmp = new_register(type);
__ xadd(addr_ptr, data, dst, tmp);
} else {
LIR_Opr tmp = (UseCompressedOops && is_obj) ? new_pointer_register() : LIR_OprFact::illegalOpr;
if (is_obj) {
// Do the pre-write barrier, if any.
pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
}
__ xchg(addr_ptr, data, dst, tmp);
if (is_obj) {
// Seems to be a precise address
post_barrier(LIR_OprFact::address(addr), data);
}
}
}

View File

@ -42,11 +42,6 @@
#include "runtime/vframeArray.hpp"
#include "utilities/align.hpp"
#include "vmreg_arm.inline.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CardTable.hpp"
#include "gc/g1/g1ThreadLocalData.hpp"
#endif
// Note: Rtemp usage is this file should not impact C2 and should be
// correct as long as it is not implicitly used in lower layers (the
@ -356,6 +351,13 @@ static void restore_live_registers_without_return(StubAssembler* sasm, bool rest
restore_live_registers(sasm, true, true, false, restore_fpu_registers);
}
void StubAssembler::save_live_registers() {
save_live_registers(this);
}
void StubAssembler::restore_live_registers_without_return() {
restore_live_registers_without_return(this);
}
void Runtime1::initialize_pd() {
}
@ -533,201 +535,6 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
#if INCLUDE_ALL_GCS
case g1_pre_barrier_slow_id:
{
// Input:
// - pre_val pushed on the stack
__ set_info("g1_pre_barrier_slow_id", dont_gc_arguments);
BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ mov(R0, (int)id);
__ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), R0);
__ should_not_reach_here();
break;
}
// save at least the registers that need saving if the runtime is called
#ifdef AARCH64
__ raw_push(R0, R1);
__ raw_push(R2, R3);
const int nb_saved_regs = 4;
#else // AARCH64
const RegisterSet saved_regs = RegisterSet(R0,R3) | RegisterSet(R12) | RegisterSet(LR);
const int nb_saved_regs = 6;
assert(nb_saved_regs == saved_regs.size(), "fix nb_saved_regs");
__ push(saved_regs);
#endif // AARCH64
const Register r_pre_val_0 = R0; // must be R0, to be ready for the runtime call
const Register r_index_1 = R1;
const Register r_buffer_2 = R2;
Address queue_active(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
Address queue_index(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
Address buffer(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
Label done;
Label runtime;
// Is marking still active?
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
__ ldrb(R1, queue_active);
__ cbz(R1, done);
__ ldr(r_index_1, queue_index);
__ ldr(r_pre_val_0, Address(SP, nb_saved_regs*wordSize));
__ ldr(r_buffer_2, buffer);
__ subs(r_index_1, r_index_1, wordSize);
__ b(runtime, lt);
__ str(r_index_1, queue_index);
__ str(r_pre_val_0, Address(r_buffer_2, r_index_1));
__ bind(done);
#ifdef AARCH64
__ raw_pop(R2, R3);
__ raw_pop(R0, R1);
#else // AARCH64
__ pop(saved_regs);
#endif // AARCH64
__ ret();
__ bind(runtime);
save_live_registers(sasm);
assert(r_pre_val_0 == c_rarg0, "pre_val should be in R0");
__ mov(c_rarg1, Rthread);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), c_rarg0, c_rarg1);
restore_live_registers_without_return(sasm);
__ b(done);
}
break;
case g1_post_barrier_slow_id:
{
// Input:
// - store_addr, pushed on the stack
__ set_info("g1_post_barrier_slow_id", dont_gc_arguments);
BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ mov(R0, (int)id);
__ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), R0);
__ should_not_reach_here();
break;
}
Label done;
Label recheck;
Label runtime;
Address queue_index(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
Address buffer(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
AddressLiteral cardtable(ci_card_table_address_as<address>(), relocInfo::none);
// save at least the registers that need saving if the runtime is called
#ifdef AARCH64
__ raw_push(R0, R1);
__ raw_push(R2, R3);
const int nb_saved_regs = 4;
#else // AARCH64
const RegisterSet saved_regs = RegisterSet(R0,R3) | RegisterSet(R12) | RegisterSet(LR);
const int nb_saved_regs = 6;
assert(nb_saved_regs == saved_regs.size(), "fix nb_saved_regs");
__ push(saved_regs);
#endif // AARCH64
const Register r_card_addr_0 = R0; // must be R0 for the slow case
const Register r_obj_0 = R0;
const Register r_card_base_1 = R1;
const Register r_tmp2 = R2;
const Register r_index_2 = R2;
const Register r_buffer_3 = R3;
const Register tmp1 = Rtemp;
__ ldr(r_obj_0, Address(SP, nb_saved_regs*wordSize));
// Note: there is a comment in x86 code about not using
// ExternalAddress / lea, due to relocation not working
// properly for that address. Should be OK for arm, where we
// explicitly specify that 'cardtable' has a relocInfo::none
// type.
__ lea(r_card_base_1, cardtable);
__ add(r_card_addr_0, r_card_base_1, AsmOperand(r_obj_0, lsr, CardTable::card_shift));
// first quick check without barrier
__ ldrb(r_tmp2, Address(r_card_addr_0));
__ cmp(r_tmp2, (int)G1CardTable::g1_young_card_val());
__ b(recheck, ne);
__ bind(done);
#ifdef AARCH64
__ raw_pop(R2, R3);
__ raw_pop(R0, R1);
#else // AARCH64
__ pop(saved_regs);
#endif // AARCH64
__ ret();
__ bind(recheck);
__ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp1);
// reload card state after the barrier that ensures the stored oop was visible
__ ldrb(r_tmp2, Address(r_card_addr_0));
assert(CardTable::dirty_card_val() == 0, "adjust this code");
__ cbz(r_tmp2, done);
// storing region crossing non-NULL, card is clean.
// dirty card and log.
assert(0 == (int)CardTable::dirty_card_val(), "adjust this code");
if ((ci_card_table_address_as<intptr_t>() & 0xff) == 0) {
// Card table is aligned so the lowest byte of the table address base is zero.
__ strb(r_card_base_1, Address(r_card_addr_0));
} else {
__ strb(__ zero_register(r_tmp2), Address(r_card_addr_0));
}
__ ldr(r_index_2, queue_index);
__ ldr(r_buffer_3, buffer);
__ subs(r_index_2, r_index_2, wordSize);
__ b(runtime, lt); // go to runtime if now negative
__ str(r_index_2, queue_index);
__ str(r_card_addr_0, Address(r_buffer_3, r_index_2));
__ b(done);
__ bind(runtime);
save_live_registers(sasm);
assert(r_card_addr_0 == c_rarg0, "card_addr should be in R0");
__ mov(c_rarg1, Rthread);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), c_rarg0, c_rarg1);
restore_live_registers_without_return(sasm);
__ b(done);
}
break;
#endif // INCLUDE_ALL_GCS
case new_instance_id:
case fast_new_instance_id:
case fast_new_instance_init_check_id:

View File

@ -32,6 +32,11 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/thread.hpp"
#include "utilities/macros.hpp"
#ifdef COMPILER1
#include "c1/c1_LIRAssembler.hpp"
#include "c1/c1_MacroAssembler.hpp"
#include "gc/g1/c1/g1BarrierSetC1.hpp"
#endif
#define __ masm->
@ -120,3 +125,243 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas
#endif // !R9_IS_SCRATCHED
#endif // !AARCH64
}
#ifdef COMPILER1
#undef __
#define __ ce->masm()->
void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) {
G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
// At this point we know that marking is in progress.
// If do_load() is true then we have to emit the
// load of the previous value; otherwise it has already
// been loaded into _pre_val.
__ bind(*stub->entry());
assert(stub->pre_val()->is_register(), "Precondition.");
Register pre_val_reg = stub->pre_val()->as_register();
if (stub->do_load()) {
ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/, false /*unaligned*/);
}
__ cbz(pre_val_reg, *stub->continuation());
ce->verify_reserved_argument_area_size(1);
__ str(pre_val_reg, Address(SP));
__ call(bs->pre_barrier_c1_runtime_code_blob()->code_begin(), relocInfo::runtime_call_type);
__ b(*stub->continuation());
}
void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) {
G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
__ bind(*stub->entry());
assert(stub->addr()->is_register(), "Precondition.");
assert(stub->new_val()->is_register(), "Precondition.");
Register new_val_reg = stub->new_val()->as_register();
__ cbz(new_val_reg, *stub->continuation());
ce->verify_reserved_argument_area_size(1);
__ str(stub->addr()->as_pointer_register(), Address(SP));
__ call(bs->post_barrier_c1_runtime_code_blob()->code_begin(), relocInfo::runtime_call_type);
__ b(*stub->continuation());
}
#undef __
#define __ sasm->
void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) {
// Input:
// - pre_val pushed on the stack
__ set_info("g1_pre_barrier_slow_id", dont_gc_arguments);
BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ mov(R0, (int)id);
__ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), R0);
__ should_not_reach_here();
break;
}
// save at least the registers that need saving if the runtime is called
#ifdef AARCH64
__ raw_push(R0, R1);
__ raw_push(R2, R3);
const int nb_saved_regs = 4;
#else // AARCH64
const RegisterSet saved_regs = RegisterSet(R0,R3) | RegisterSet(R12) | RegisterSet(LR);
const int nb_saved_regs = 6;
assert(nb_saved_regs == saved_regs.size(), "fix nb_saved_regs");
__ push(saved_regs);
#endif // AARCH64
const Register r_pre_val_0 = R0; // must be R0, to be ready for the runtime call
const Register r_index_1 = R1;
const Register r_buffer_2 = R2;
Address queue_active(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
Address queue_index(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
Address buffer(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
Label done;
Label runtime;
// Is marking still active?
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
__ ldrb(R1, queue_active);
__ cbz(R1, done);
__ ldr(r_index_1, queue_index);
__ ldr(r_pre_val_0, Address(SP, nb_saved_regs*wordSize));
__ ldr(r_buffer_2, buffer);
__ subs(r_index_1, r_index_1, wordSize);
__ b(runtime, lt);
__ str(r_index_1, queue_index);
__ str(r_pre_val_0, Address(r_buffer_2, r_index_1));
__ bind(done);
#ifdef AARCH64
__ raw_pop(R2, R3);
__ raw_pop(R0, R1);
#else // AARCH64
__ pop(saved_regs);
#endif // AARCH64
__ ret();
__ bind(runtime);
__ save_live_registers();
assert(r_pre_val_0 == c_rarg0, "pre_val should be in R0");
__ mov(c_rarg1, Rthread);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), c_rarg0, c_rarg1);
__ restore_live_registers_without_return();
__ b(done);
}
void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) {
// Input:
// - store_addr, pushed on the stack
__ set_info("g1_post_barrier_slow_id", dont_gc_arguments);
BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ mov(R0, (int)id);
__ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), R0);
__ should_not_reach_here();
break;
}
Label done;
Label recheck;
Label runtime;
Address queue_index(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
Address buffer(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
AddressLiteral cardtable(ci_card_table_address_as<address>(), relocInfo::none);
// save at least the registers that need saving if the runtime is called
#ifdef AARCH64
__ raw_push(R0, R1);
__ raw_push(R2, R3);
const int nb_saved_regs = 4;
#else // AARCH64
const RegisterSet saved_regs = RegisterSet(R0,R3) | RegisterSet(R12) | RegisterSet(LR);
const int nb_saved_regs = 6;
assert(nb_saved_regs == saved_regs.size(), "fix nb_saved_regs");
__ push(saved_regs);
#endif // AARCH64
const Register r_card_addr_0 = R0; // must be R0 for the slow case
const Register r_obj_0 = R0;
const Register r_card_base_1 = R1;
const Register r_tmp2 = R2;
const Register r_index_2 = R2;
const Register r_buffer_3 = R3;
const Register tmp1 = Rtemp;
__ ldr(r_obj_0, Address(SP, nb_saved_regs*wordSize));
// Note: there is a comment in x86 code about not using
// ExternalAddress / lea, due to relocation not working
// properly for that address. Should be OK for arm, where we
// explicitly specify that 'cardtable' has a relocInfo::none
// type.
__ lea(r_card_base_1, cardtable);
__ add(r_card_addr_0, r_card_base_1, AsmOperand(r_obj_0, lsr, CardTable::card_shift));
// first quick check without barrier
__ ldrb(r_tmp2, Address(r_card_addr_0));
__ cmp(r_tmp2, (int)G1CardTable::g1_young_card_val());
__ b(recheck, ne);
__ bind(done);
#ifdef AARCH64
__ raw_pop(R2, R3);
__ raw_pop(R0, R1);
#else // AARCH64
__ pop(saved_regs);
#endif // AARCH64
__ ret();
__ bind(recheck);
__ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp1);
// reload card state after the barrier that ensures the stored oop was visible
__ ldrb(r_tmp2, Address(r_card_addr_0));
assert(CardTable::dirty_card_val() == 0, "adjust this code");
__ cbz(r_tmp2, done);
// storing region crossing non-NULL, card is clean.
// dirty card and log.
assert(0 == (int)CardTable::dirty_card_val(), "adjust this code");
if ((ci_card_table_address_as<intptr_t>() & 0xff) == 0) {
// Card table is aligned so the lowest byte of the table address base is zero.
__ strb(r_card_base_1, Address(r_card_addr_0));
} else {
__ strb(__ zero_register(r_tmp2), Address(r_card_addr_0));
}
__ ldr(r_index_2, queue_index);
__ ldr(r_buffer_3, buffer);
__ subs(r_index_2, r_index_2, wordSize);
__ b(runtime, lt); // go to runtime if now negative
__ str(r_index_2, queue_index);
__ str(r_card_addr_0, Address(r_buffer_3, r_index_2));
__ b(done);
__ bind(runtime);
__ save_live_registers();
assert(r_card_addr_0 == c_rarg0, "card_addr should be in R0");
__ mov(c_rarg1, Rthread);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), c_rarg0, c_rarg1);
__ restore_live_registers_without_return();
__ b(done);
}
#undef __
#endif // COMPILER1

View File

@ -27,6 +27,12 @@
#include "asm/macroAssembler.hpp"
#include "gc/shared/modRefBarrierSetAssembler.hpp"
#include "utilities/macros.hpp"
class LIR_Assembler;
class StubAssembler;
class G1PreBarrierStub;
class G1PostBarrierStub;
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
@ -34,6 +40,14 @@ protected:
Register addr, Register count, int callee_saved_regs);
void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register addr, Register count, Register tmp);
#ifdef COMPILER1
void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub);
void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
#endif
};
#endif // CPU_ARM_GC_G1_G1BARRIERSETASSEMBLER_ARM_HPP

View File

@ -33,9 +33,6 @@
#include "runtime/sharedRuntime.hpp"
#include "utilities/macros.hpp"
#include "vmreg_ppc.inline.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#endif // INCLUDE_ALL_GCS
#define __ ce->masm()->
@ -470,58 +467,4 @@ void ArrayCopyStub::emit_code(LIR_Assembler* ce) {
__ b(_continuation);
}
///////////////////////////////////////////////////////////////////////////////////
#if INCLUDE_ALL_GCS
void G1PreBarrierStub::emit_code(LIR_Assembler* ce) {
// At this point we know that marking is in progress.
// If do_load() is true then we have to emit the
// load of the previous value; otherwise it has already
// been loaded into _pre_val.
__ bind(_entry);
assert(pre_val()->is_register(), "Precondition.");
Register pre_val_reg = pre_val()->as_register();
if (do_load()) {
ce->mem2reg(addr(), pre_val(), T_OBJECT, patch_code(), info(), false /*wide*/, false /*unaligned*/);
}
__ cmpdi(CCR0, pre_val_reg, 0);
__ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::equal), _continuation);
address stub = Runtime1::entry_for(Runtime1::Runtime1::g1_pre_barrier_slow_id);
//__ load_const_optimized(R0, stub);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
__ std(pre_val_reg, -8, R1_SP); // Pass pre_val on stack.
__ mtctr(R0);
__ bctrl();
__ b(_continuation);
}
void G1PostBarrierStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
assert(addr()->is_register(), "Precondition.");
assert(new_val()->is_register(), "Precondition.");
Register addr_reg = addr()->as_pointer_register();
Register new_val_reg = new_val()->as_register();
__ cmpdi(CCR0, new_val_reg, 0);
__ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::equal), _continuation);
address stub = Runtime1::entry_for(Runtime1::Runtime1::g1_post_barrier_slow_id);
//__ load_const_optimized(R0, stub);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
__ mtctr(R0);
__ mr(R0, addr_reg); // Pass addr in R0.
__ bctrl();
__ b(_continuation);
}
#endif // INCLUDE_ALL_GCS
///////////////////////////////////////////////////////////////////////////////////
#undef __

View File

@ -2978,7 +2978,9 @@ void LIR_Assembler::peephole(LIR_List* lir) {
void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr dest, LIR_Opr tmp) {
const Register Rptr = src->as_pointer_register(),
const LIR_Address *addr = src->as_address_ptr();
assert(addr->disp() == 0 && addr->index()->is_illegal(), "use leal!");
const Register Rptr = addr->base()->as_pointer_register(),
Rtmp = tmp->as_register();
Register Rco = noreg;
if (UseCompressedOops && data->is_oop()) {

View File

@ -149,7 +149,12 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index,
// Accumulate fixed displacements.
if (index->is_constant()) {
large_disp += (intx)(index->as_constant_ptr()->as_jint()) << shift;
LIR_Const *constant = index->as_constant_ptr();
if (constant->type() == T_LONG) {
large_disp += constant->as_jlong() << shift;
} else {
large_disp += (intx)(constant->as_jint()) << shift;
}
index = LIR_OprFact::illegalOpr;
}
@ -190,7 +195,7 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index,
LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr,
BasicType type, bool needs_card_mark) {
BasicType type) {
int elem_size = type2aelembytes(type);
int shift = exact_log2(elem_size);
@ -230,13 +235,7 @@ LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_o
__ add(index_opr, array_opr, base_opr);
}
}
if (needs_card_mark) {
LIR_Opr ptr = new_pointer_register();
__ add(base_opr, LIR_OprFact::intptrConst(offset), ptr);
return new LIR_Address(ptr, type);
} else {
return new LIR_Address(base_opr, offset, type);
}
return new LIR_Address(base_opr, offset, type);
}
@ -320,80 +319,12 @@ void LIRGenerator::store_stack_parameter(LIR_Opr item, ByteSize offset_from_sp)
// visitor functions
//----------------------------------------------------------------------
void LIRGenerator::do_StoreIndexed(StoreIndexed* x) {
assert(x->is_pinned(),"");
bool needs_range_check = x->compute_needs_range_check();
bool use_length = x->length() != NULL;
bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT;
bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL ||
!get_jobject_constant(x->value())->is_null_object() ||
x->should_profile());
LIRItem array(x->array(), this);
LIRItem index(x->index(), this);
LIRItem value(x->value(), this);
LIRItem length(this);
array.load_item();
index.load_nonconstant();
if (use_length && needs_range_check) {
length.set_instruction(x->length());
length.load_item();
}
if (needs_store_check || x->check_boolean()) {
value.load_item();
} else {
value.load_for_store(x->elt_type());
}
set_no_result(x);
// The CodeEmitInfo must be duplicated for each different
// LIR-instruction because spilling can occur anywhere between two
// instructions and so the debug information must be different.
CodeEmitInfo* range_check_info = state_for(x);
CodeEmitInfo* null_check_info = NULL;
if (x->needs_null_check()) {
null_check_info = new CodeEmitInfo(range_check_info);
}
// Emit array address setup early so it schedules better.
LIR_Address* array_addr = emit_array_address(array.result(), index.result(), x->elt_type(), obj_store);
if (GenerateRangeChecks && needs_range_check) {
if (use_length) {
__ cmp(lir_cond_belowEqual, length.result(), index.result());
__ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result()));
} else {
array_range_check(array.result(), index.result(), null_check_info, range_check_info);
// Range_check also does the null check.
null_check_info = NULL;
}
}
if (GenerateArrayStoreCheck && needs_store_check) {
// Following registers are used by slow_subtype_check:
LIR_Opr tmp1 = FrameMap::R4_opr; // super_klass
LIR_Opr tmp2 = FrameMap::R5_opr; // sub_klass
LIR_Opr tmp3 = FrameMap::R6_opr; // temp
CodeEmitInfo* store_check_info = new CodeEmitInfo(range_check_info);
__ store_check(value.result(), array.result(), tmp1, tmp2, tmp3,
store_check_info, x->profiled_method(), x->profiled_bci());
}
if (obj_store) {
// Needs GC write barriers.
pre_barrier(LIR_OprFact::address(array_addr), LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
}
LIR_Opr result = maybe_mask_boolean(x, array.result(), value.result(), null_check_info);
__ move(result, array_addr, null_check_info);
if (obj_store) {
// Precise card mark.
post_barrier(LIR_OprFact::address(array_addr), value.result());
}
void LIRGenerator::array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, ciMethod* profiled_method, int profiled_bci) {
// Following registers are used by slow_subtype_check:
LIR_Opr tmp1 = FrameMap::R4_opr; // super_klass
LIR_Opr tmp2 = FrameMap::R5_opr; // sub_klass
LIR_Opr tmp3 = FrameMap::R6_opr; // temp
__ store_check(value, array, tmp1, tmp2, tmp3, store_check_info, profiled_method, profiled_bci);
}
@ -702,24 +633,68 @@ void LIRGenerator::do_CompareOp(CompareOp* x) {
}
void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) {
assert(x->number_of_arguments() == 4, "wrong type");
LIRItem obj (x->argument_at(0), this); // object
LIRItem offset(x->argument_at(1), this); // offset of field
LIRItem cmp (x->argument_at(2), this); // Value to compare with field.
LIRItem val (x->argument_at(3), this); // Replace field with val if matches cmp.
LIR_Opr LIRGenerator::atomic_cmpxchg(BasicType type, LIR_Opr addr, LIRItem& cmp_value, LIRItem& new_value) {
LIR_Opr result = new_register(T_INT);
LIR_Opr t1 = LIR_OprFact::illegalOpr;
LIR_Opr t2 = LIR_OprFact::illegalOpr;
LIR_Opr addr = new_pointer_register();
cmp_value.load_item();
new_value.load_item();
// Get address of field.
obj.load_item();
offset.load_item();
cmp.load_item();
val.load_item();
// Volatile load may be followed by Unsafe CAS.
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
__ membar();
} else {
__ membar_release();
}
__ add(obj.result(), offset.result(), addr);
if (type == T_OBJECT || type == T_ARRAY) {
if (UseCompressedOops) {
t1 = new_register(T_OBJECT);
t2 = new_register(T_OBJECT);
}
__ cas_obj(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2);
} else if (type == T_INT) {
__ cas_int(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2);
} else if (type == T_LONG) {
__ cas_long(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2);
} else {
Unimplemented();
}
__ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0),
result, type);
return result;
}
LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) {
LIR_Opr result = new_register(type);
LIR_Opr tmp = FrameMap::R0_opr;
value.load_item();
// Volatile load may be followed by Unsafe CAS.
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
__ membar();
} else {
__ membar_release();
}
__ xchg(addr, value.result(), result, tmp);
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
__ membar_acquire();
} else {
__ membar();
}
return result;
}
LIR_Opr LIRGenerator::atomic_add(BasicType type, LIR_Opr addr, LIRItem& value) {
LIR_Opr result = new_register(type);
LIR_Opr tmp = FrameMap::R0_opr;
value.load_item();
// Volatile load may be followed by Unsafe CAS.
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
@ -728,33 +703,14 @@ void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) {
__ membar_release();
}
if (type == objectType) { // Write-barrier needed for Object fields.
// Only cmp value can get overwritten, no do_load required.
pre_barrier(LIR_OprFact::illegalOpr /* addr */, cmp.result() /* pre_val */,
false /* do_load */, false /* patch */, NULL);
}
__ xadd(addr, value.result(), result, tmp);
if (type == objectType) {
if (UseCompressedOops) {
t1 = new_register(T_OBJECT);
t2 = new_register(T_OBJECT);
}
__ cas_obj(addr, cmp.result(), val.result(), t1, t2);
} else if (type == intType) {
__ cas_int(addr, cmp.result(), val.result(), t1, t2);
} else if (type == longType) {
__ cas_long(addr, cmp.result(), val.result(), t1, t2);
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
__ membar_acquire();
} else {
ShouldNotReachHere();
}
// Benerate conditional move of boolean result.
LIR_Opr result = rlock_result(x);
__ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0),
result, as_BasicType(type));
if (type == objectType) { // Write-barrier needed for Object fields.
// Precise card mark since could either be object or array.
post_barrier(addr, val.result());
__ membar();
}
return result;
}
@ -1255,110 +1211,6 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result,
}
void LIRGenerator::put_Object_unsafe(LIR_Opr src, LIR_Opr offset, LIR_Opr data,
BasicType type, bool is_volatile) {
LIR_Opr base_op = src;
LIR_Opr index_op = offset;
bool is_obj = (type == T_ARRAY || type == T_OBJECT);
#ifndef _LP64
if (is_volatile && type == T_LONG) {
__ volatile_store_unsafe_reg(data, src, offset, type, NULL, lir_patch_none);
} else
#endif
{
if (type == T_BOOLEAN) {
type = T_BYTE;
}
LIR_Address* addr;
if (type == T_ARRAY || type == T_OBJECT) {
LIR_Opr tmp = new_pointer_register();
__ add(base_op, index_op, tmp);
addr = new LIR_Address(tmp, type);
} else {
addr = new LIR_Address(base_op, index_op, type);
}
if (is_obj) {
pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
// _bs->c1_write_barrier_pre(this, LIR_OprFact::address(addr));
}
__ move(data, addr);
if (is_obj) {
// This address is precise.
post_barrier(LIR_OprFact::address(addr), data);
}
}
}
void LIRGenerator::get_Object_unsafe(LIR_Opr dst, LIR_Opr src, LIR_Opr offset,
BasicType type, bool is_volatile) {
#ifndef _LP64
if (is_volatile && type == T_LONG) {
__ volatile_load_unsafe_reg(src, offset, dst, type, NULL, lir_patch_none);
} else
#endif
{
LIR_Address* addr = new LIR_Address(src, offset, type);
__ load(addr, dst);
}
}
void LIRGenerator::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {
BasicType type = x->basic_type();
LIRItem src(x->object(), this);
LIRItem off(x->offset(), this);
LIRItem value(x->value(), this);
src.load_item();
value.load_item();
off.load_nonconstant();
LIR_Opr dst = rlock_result(x, type);
LIR_Opr data = value.result();
bool is_obj = (type == T_ARRAY || type == T_OBJECT);
LIR_Opr tmp = FrameMap::R0_opr;
LIR_Opr ptr = new_pointer_register();
__ add(src.result(), off.result(), ptr);
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
__ membar();
} else {
__ membar_release();
}
if (x->is_add()) {
__ xadd(ptr, data, dst, tmp);
} else {
const bool can_move_barrier = true; // TODO: port GraphKit::can_move_pre_barrier() from C2
if (!can_move_barrier && is_obj) {
// Do the pre-write barrier, if any.
pre_barrier(ptr, LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
}
__ xchg(ptr, data, dst, tmp);
if (is_obj) {
// Seems to be a precise address.
post_barrier(ptr, data);
if (can_move_barrier) {
pre_barrier(LIR_OprFact::illegalOpr, dst /* pre_val */,
false /* do_load */, false /* patch */, NULL);
}
}
}
if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
__ membar_acquire();
} else {
__ membar();
}
}
void LIRGenerator::do_update_CRC32(Intrinsic* x) {
assert(UseCRC32Intrinsics, "or should not be here");
LIR_Opr result = rlock_result(x);

View File

@ -42,11 +42,6 @@
#include "utilities/align.hpp"
#include "utilities/macros.hpp"
#include "vmreg_ppc.inline.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CardTable.hpp"
#include "gc/g1/g1ThreadLocalData.hpp"
#endif
// Implementation of StubAssembler
@ -708,164 +703,6 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
#if INCLUDE_ALL_GCS
case g1_pre_barrier_slow_id:
{
BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
goto unimplemented_entry;
}
__ set_info("g1_pre_barrier_slow_id", dont_gc_arguments);
// Using stack slots: pre_val (pre-pushed), spill tmp, spill tmp2.
const int stack_slots = 3;
Register pre_val = R0; // previous value of memory
Register tmp = R14;
Register tmp2 = R15;
Label refill, restart, marking_not_active;
int satb_q_active_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset());
int satb_q_index_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset());
int satb_q_buf_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset());
// Spill
__ std(tmp, -16, R1_SP);
__ std(tmp2, -24, R1_SP);
// Is marking still active?
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
__ lwz(tmp, satb_q_active_byte_offset, R16_thread);
} else {
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
__ lbz(tmp, satb_q_active_byte_offset, R16_thread);
}
__ cmpdi(CCR0, tmp, 0);
__ beq(CCR0, marking_not_active);
__ bind(restart);
// Load the index into the SATB buffer. SATBMarkQueue::_index is a
// size_t so ld_ptr is appropriate.
__ ld(tmp, satb_q_index_byte_offset, R16_thread);
// index == 0?
__ cmpdi(CCR0, tmp, 0);
__ beq(CCR0, refill);
__ ld(tmp2, satb_q_buf_byte_offset, R16_thread);
__ ld(pre_val, -8, R1_SP); // Load from stack.
__ addi(tmp, tmp, -oopSize);
__ std(tmp, satb_q_index_byte_offset, R16_thread);
__ stdx(pre_val, tmp2, tmp); // [_buf + index] := <address_of_card>
__ bind(marking_not_active);
// Restore temp registers and return-from-leaf.
__ ld(tmp2, -24, R1_SP);
__ ld(tmp, -16, R1_SP);
__ blr();
__ bind(refill);
const int nbytes_save = (MacroAssembler::num_volatile_regs + stack_slots) * BytesPerWord;
__ save_volatile_gprs(R1_SP, -nbytes_save); // except R0
__ mflr(R0);
__ std(R0, _abi(lr), R1_SP);
__ push_frame_reg_args(nbytes_save, R0); // dummy frame for C call
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SATBMarkQueueSet::handle_zero_index_for_thread), R16_thread);
__ pop_frame();
__ ld(R0, _abi(lr), R1_SP);
__ mtlr(R0);
__ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0
__ b(restart);
}
break;
case g1_post_barrier_slow_id:
{
BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
goto unimplemented_entry;
}
__ set_info("g1_post_barrier_slow_id", dont_gc_arguments);
// Using stack slots: spill addr, spill tmp2
const int stack_slots = 2;
Register tmp = R0;
Register addr = R14;
Register tmp2 = R15;
jbyte* byte_map_base = ci_card_table_address();
Label restart, refill, ret;
// Spill
__ std(addr, -8, R1_SP);
__ std(tmp2, -16, R1_SP);
__ srdi(addr, R0, CardTable::card_shift); // Addr is passed in R0.
__ load_const_optimized(/*cardtable*/ tmp2, byte_map_base, tmp);
__ add(addr, tmp2, addr);
__ lbz(tmp, 0, addr); // tmp := [addr + cardtable]
// Return if young card.
__ cmpwi(CCR0, tmp, G1CardTable::g1_young_card_val());
__ beq(CCR0, ret);
// Return if sequential consistent value is already dirty.
__ membar(Assembler::StoreLoad);
__ lbz(tmp, 0, addr); // tmp := [addr + cardtable]
__ cmpwi(CCR0, tmp, G1CardTable::dirty_card_val());
__ beq(CCR0, ret);
// Not dirty.
// First, dirty it.
__ li(tmp, G1CardTable::dirty_card_val());
__ stb(tmp, 0, addr);
int dirty_card_q_index_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset());
int dirty_card_q_buf_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset());
__ bind(restart);
// Get the index into the update buffer. DirtyCardQueue::_index is
// a size_t so ld_ptr is appropriate here.
__ ld(tmp2, dirty_card_q_index_byte_offset, R16_thread);
// index == 0?
__ cmpdi(CCR0, tmp2, 0);
__ beq(CCR0, refill);
__ ld(tmp, dirty_card_q_buf_byte_offset, R16_thread);
__ addi(tmp2, tmp2, -oopSize);
__ std(tmp2, dirty_card_q_index_byte_offset, R16_thread);
__ add(tmp2, tmp, tmp2);
__ std(addr, 0, tmp2); // [_buf + index] := <address_of_card>
// Restore temp registers and return-from-leaf.
__ bind(ret);
__ ld(tmp2, -16, R1_SP);
__ ld(addr, -8, R1_SP);
__ blr();
__ bind(refill);
const int nbytes_save = (MacroAssembler::num_volatile_regs + stack_slots) * BytesPerWord;
__ save_volatile_gprs(R1_SP, -nbytes_save); // except R0
__ mflr(R0);
__ std(R0, _abi(lr), R1_SP);
__ push_frame_reg_args(nbytes_save, R0); // dummy frame for C call
__ call_VM_leaf(CAST_FROM_FN_PTR(address, DirtyCardQueueSet::handle_zero_index_for_thread), R16_thread);
__ pop_frame();
__ ld(R0, _abi(lr), R1_SP);
__ mtlr(R0);
__ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0
__ b(restart);
}
break;
#endif // INCLUDE_ALL_GCS
case predicate_failed_trap_id:
{
__ set_info("predicate_failed_trap", dont_gc_arguments);
@ -889,7 +726,6 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
break;
default:
unimplemented_entry:
{
__ set_info("unimplemented entry", dont_gc_arguments);
__ mflr(R0);

View File

@ -26,12 +26,17 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CardTable.hpp"
#include "gc/g1/g1BarrierSetAssembler.hpp"
#include "gc/g1/g1CardTable.hpp"
#include "gc/g1/g1ThreadLocalData.hpp"
#include "gc/g1/heapRegion.hpp"
#include "interpreter/interp_masm.hpp"
#include "runtime/sharedRuntime.hpp"
#ifdef COMPILER1
#include "c1/c1_LIRAssembler.hpp"
#include "c1/c1_MacroAssembler.hpp"
#include "gc/g1/c1/g1BarrierSetC1.hpp"
#endif
#define __ masm->
@ -339,4 +344,209 @@ void G1BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value
__ bind(done);
}
#ifdef COMPILER1
#undef __
#define __ ce->masm()->
void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) {
G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
// At this point we know that marking is in progress.
// If do_load() is true then we have to emit the
// load of the previous value; otherwise it has already
// been loaded into _pre_val.
__ bind(*stub->entry());
assert(stub->pre_val()->is_register(), "Precondition.");
Register pre_val_reg = stub->pre_val()->as_register();
if (stub->do_load()) {
ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/, false /*unaligned*/);
}
__ cmpdi(CCR0, pre_val_reg, 0);
__ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::equal), *stub->continuation());
address c_code = bs->pre_barrier_c1_runtime_code_blob()->code_begin();
//__ load_const_optimized(R0, c_code);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(c_code));
__ std(pre_val_reg, -8, R1_SP); // Pass pre_val on stack.
__ mtctr(R0);
__ bctrl();
__ b(*stub->continuation());
}
void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) {
G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
__ bind(*stub->entry());
assert(stub->addr()->is_register(), "Precondition.");
assert(stub->new_val()->is_register(), "Precondition.");
Register addr_reg = stub->addr()->as_pointer_register();
Register new_val_reg = stub->new_val()->as_register();
__ cmpdi(CCR0, new_val_reg, 0);
__ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::equal), *stub->continuation());
address c_code = bs->post_barrier_c1_runtime_code_blob()->code_begin();
//__ load_const_optimized(R0, c_code);
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(c_code));
__ mtctr(R0);
__ mr(R0, addr_reg); // Pass addr in R0.
__ bctrl();
__ b(*stub->continuation());
}
#undef __
#define __ sasm->
void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) {
BarrierSet* bs = BarrierSet::barrier_set();
__ set_info("g1_pre_barrier_slow_id", false);
// Using stack slots: pre_val (pre-pushed), spill tmp, spill tmp2.
const int stack_slots = 3;
Register pre_val = R0; // previous value of memory
Register tmp = R14;
Register tmp2 = R15;
Label refill, restart, marking_not_active;
int satb_q_active_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset());
int satb_q_index_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset());
int satb_q_buf_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset());
// Spill
__ std(tmp, -16, R1_SP);
__ std(tmp2, -24, R1_SP);
// Is marking still active?
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
__ lwz(tmp, satb_q_active_byte_offset, R16_thread);
} else {
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
__ lbz(tmp, satb_q_active_byte_offset, R16_thread);
}
__ cmpdi(CCR0, tmp, 0);
__ beq(CCR0, marking_not_active);
__ bind(restart);
// Load the index into the SATB buffer. SATBMarkQueue::_index is a
// size_t so ld_ptr is appropriate.
__ ld(tmp, satb_q_index_byte_offset, R16_thread);
// index == 0?
__ cmpdi(CCR0, tmp, 0);
__ beq(CCR0, refill);
__ ld(tmp2, satb_q_buf_byte_offset, R16_thread);
__ ld(pre_val, -8, R1_SP); // Load from stack.
__ addi(tmp, tmp, -oopSize);
__ std(tmp, satb_q_index_byte_offset, R16_thread);
__ stdx(pre_val, tmp2, tmp); // [_buf + index] := <address_of_card>
__ bind(marking_not_active);
// Restore temp registers and return-from-leaf.
__ ld(tmp2, -24, R1_SP);
__ ld(tmp, -16, R1_SP);
__ blr();
__ bind(refill);
const int nbytes_save = (MacroAssembler::num_volatile_regs + stack_slots) * BytesPerWord;
__ save_volatile_gprs(R1_SP, -nbytes_save); // except R0
__ mflr(R0);
__ std(R0, _abi(lr), R1_SP);
__ push_frame_reg_args(nbytes_save, R0); // dummy frame for C call
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SATBMarkQueueSet::handle_zero_index_for_thread), R16_thread);
__ pop_frame();
__ ld(R0, _abi(lr), R1_SP);
__ mtlr(R0);
__ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0
__ b(restart);
}
void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) {
G1BarrierSet* bs = barrier_set_cast<G1BarrierSet>(BarrierSet::barrier_set());
__ set_info("g1_post_barrier_slow_id", false);
// Using stack slots: spill addr, spill tmp2
const int stack_slots = 2;
Register tmp = R0;
Register addr = R14;
Register tmp2 = R15;
jbyte* byte_map_base = bs->card_table()->byte_map_base();
Label restart, refill, ret;
// Spill
__ std(addr, -8, R1_SP);
__ std(tmp2, -16, R1_SP);
__ srdi(addr, R0, CardTable::card_shift); // Addr is passed in R0.
__ load_const_optimized(/*cardtable*/ tmp2, byte_map_base, tmp);
__ add(addr, tmp2, addr);
__ lbz(tmp, 0, addr); // tmp := [addr + cardtable]
// Return if young card.
__ cmpwi(CCR0, tmp, G1CardTable::g1_young_card_val());
__ beq(CCR0, ret);
// Return if sequential consistent value is already dirty.
__ membar(Assembler::StoreLoad);
__ lbz(tmp, 0, addr); // tmp := [addr + cardtable]
__ cmpwi(CCR0, tmp, G1CardTable::dirty_card_val());
__ beq(CCR0, ret);
// Not dirty.
// First, dirty it.
__ li(tmp, G1CardTable::dirty_card_val());
__ stb(tmp, 0, addr);
int dirty_card_q_index_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset());
int dirty_card_q_buf_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset());
__ bind(restart);
// Get the index into the update buffer. DirtyCardQueue::_index is
// a size_t so ld_ptr is appropriate here.
__ ld(tmp2, dirty_card_q_index_byte_offset, R16_thread);
// index == 0?
__ cmpdi(CCR0, tmp2, 0);
__ beq(CCR0, refill);
__ ld(tmp, dirty_card_q_buf_byte_offset, R16_thread);
__ addi(tmp2, tmp2, -oopSize);
__ std(tmp2, dirty_card_q_index_byte_offset, R16_thread);
__ add(tmp2, tmp, tmp2);
__ std(addr, 0, tmp2); // [_buf + index] := <address_of_card>
// Restore temp registers and return-from-leaf.
__ bind(ret);
__ ld(tmp2, -16, R1_SP);
__ ld(addr, -8, R1_SP);
__ blr();
__ bind(refill);
const int nbytes_save = (MacroAssembler::num_volatile_regs + stack_slots) * BytesPerWord;
__ save_volatile_gprs(R1_SP, -nbytes_save); // except R0
__ mflr(R0);
__ std(R0, _abi(lr), R1_SP);
__ push_frame_reg_args(nbytes_save, R0); // dummy frame for C call
__ call_VM_leaf(CAST_FROM_FN_PTR(address, DirtyCardQueueSet::handle_zero_index_for_thread), R16_thread);
__ pop_frame();
__ ld(R0, _abi(lr), R1_SP);
__ mtlr(R0);
__ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0
__ b(restart);
}
#undef __
#endif // COMPILER1

View File

@ -28,6 +28,12 @@
#include "asm/macroAssembler.hpp"
#include "gc/shared/modRefBarrierSetAssembler.hpp"
#include "utilities/macros.hpp"
class LIR_Assembler;
class StubAssembler;
class G1PreBarrierStub;
class G1PostBarrierStub;
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
@ -45,6 +51,14 @@ protected:
Register tmp1, Register tmp2, Register tmp3, bool needs_frame);
public:
#ifdef COMPILER1
void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub);
void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
#endif
virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register base, RegisterOrConstant ind_or_offs, Register dst,
Register tmp1, Register tmp2, bool needs_frame, Label *is_null = NULL);

View File

@ -34,9 +34,6 @@
#include "utilities/align.hpp"
#include "utilities/macros.hpp"
#include "vmreg_s390.inline.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#endif // INCLUDE_ALL_GCS
#define __ ce->masm()->
#undef CHECK_BAILOUT
@ -453,46 +450,4 @@ void ArrayCopyStub::emit_code(LIR_Assembler* ce) {
__ branch_optimized(Assembler::bcondAlways, _continuation);
}
///////////////////////////////////////////////////////////////////////////////////
#if INCLUDE_ALL_GCS
void G1PreBarrierStub::emit_code(LIR_Assembler* ce) {
// At this point we know that marking is in progress.
// If do_load() is true then we have to emit the
// load of the previous value; otherwise it has already
// been loaded into _pre_val.
__ bind(_entry);
ce->check_reserved_argument_area(16); // RT stub needs 2 spill slots.
assert(pre_val()->is_register(), "Precondition.");
Register pre_val_reg = pre_val()->as_register();
if (do_load()) {
ce->mem2reg(addr(), pre_val(), T_OBJECT, patch_code(), info(), false /*wide*/, false /*unaligned*/);
}
__ z_ltgr(Z_R1_scratch, pre_val_reg); // Pass oop in Z_R1_scratch to Runtime1::g1_pre_barrier_slow_id.
__ branch_optimized(Assembler::bcondZero, _continuation);
ce->emit_call_c(Runtime1::entry_for (Runtime1::g1_pre_barrier_slow_id));
CHECK_BAILOUT();
__ branch_optimized(Assembler::bcondAlways, _continuation);
}
void G1PostBarrierStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
ce->check_reserved_argument_area(16); // RT stub needs 2 spill slots.
assert(addr()->is_register(), "Precondition.");
assert(new_val()->is_register(), "Precondition.");
Register new_val_reg = new_val()->as_register();
__ z_ltgr(new_val_reg, new_val_reg);
__ branch_optimized(Assembler::bcondZero, _continuation);
__ z_lgr(Z_R1_scratch, addr()->as_pointer_register());
ce->emit_call_c(Runtime1::entry_for (Runtime1::g1_post_barrier_slow_id));
CHECK_BAILOUT();
__ branch_optimized(Assembler::bcondAlways, _continuation);
}
#endif // INCLUDE_ALL_GCS
#undef __

View File

@ -572,80 +572,143 @@ void LIR_Assembler::const2stack(LIR_Opr src, LIR_Opr dest) {
void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info, bool wide) {
assert(src->is_constant(), "should not call otherwise");
assert(dest->is_address(), "should not call otherwise");
// See special case in LIRGenerator::do_StoreIndexed.
// T_BYTE: Special case for card mark store.
assert(type == T_BYTE || !dest->as_address_ptr()->index()->is_valid(), "not supported");
LIR_Const* c = src->as_constant_ptr();
Address addr = as_Address(dest->as_address_ptr());
int store_offset = -1;
unsigned int lmem = 0;
unsigned int lcon = 0;
int64_t cbits = 0;
switch (type) {
case T_INT: // fall through
case T_FLOAT:
lmem = 4; lcon = 4; cbits = c->as_jint_bits();
break;
case T_ADDRESS:
lmem = 8; lcon = 4; cbits = c->as_jint_bits();
break;
case T_OBJECT: // fall through
case T_ARRAY:
if (c->as_jobject() == NULL) {
if (UseCompressedOops && !wide) {
store_offset = __ store_const(addr, (int32_t)NULL_WORD, 4, 4);
if (dest->as_address_ptr()->index()->is_valid()) {
switch (type) {
case T_INT: // fall through
case T_FLOAT:
__ load_const_optimized(Z_R0_scratch, c->as_jint_bits());
store_offset = __ offset();
if (Immediate::is_uimm12(addr.disp())) {
__ z_st(Z_R0_scratch, addr);
} else {
store_offset = __ store_const(addr, (int64_t)NULL_WORD, 8, 8);
__ z_sty(Z_R0_scratch, addr);
}
} else {
jobject2reg(c->as_jobject(), Z_R1_scratch);
if (UseCompressedOops && !wide) {
__ encode_heap_oop(Z_R1_scratch);
store_offset = __ reg2mem_opt(Z_R1_scratch, addr, false);
break;
case T_ADDRESS:
__ load_const_optimized(Z_R1_scratch, c->as_jint_bits());
store_offset = __ reg2mem_opt(Z_R1_scratch, addr, true);
break;
case T_OBJECT: // fall through
case T_ARRAY:
if (c->as_jobject() == NULL) {
if (UseCompressedOops && !wide) {
__ clear_reg(Z_R1_scratch, false);
store_offset = __ reg2mem_opt(Z_R1_scratch, addr, false);
} else {
__ clear_reg(Z_R1_scratch, true);
store_offset = __ reg2mem_opt(Z_R1_scratch, addr, true);
}
} else {
store_offset = __ reg2mem_opt(Z_R1_scratch, addr, true);
jobject2reg(c->as_jobject(), Z_R1_scratch);
if (UseCompressedOops && !wide) {
__ encode_heap_oop(Z_R1_scratch);
store_offset = __ reg2mem_opt(Z_R1_scratch, addr, false);
} else {
store_offset = __ reg2mem_opt(Z_R1_scratch, addr, true);
}
}
}
assert(store_offset >= 0, "check");
break;
assert(store_offset >= 0, "check");
break;
case T_LONG: // fall through
case T_DOUBLE:
lmem = 8; lcon = 8; cbits = (int64_t)(c->as_jlong_bits());
break;
case T_LONG: // fall through
case T_DOUBLE:
__ load_const_optimized(Z_R1_scratch, (int64_t)(c->as_jlong_bits()));
store_offset = __ reg2mem_opt(Z_R1_scratch, addr, true);
break;
case T_BOOLEAN: // fall through
case T_BYTE:
lmem = 1; lcon = 1; cbits = (int8_t)(c->as_jint());
break;
case T_BOOLEAN: // fall through
case T_BYTE:
__ load_const_optimized(Z_R0_scratch, (int8_t)(c->as_jint()));
store_offset = __ offset();
if (Immediate::is_uimm12(addr.disp())) {
__ z_stc(Z_R0_scratch, addr);
} else {
__ z_stcy(Z_R0_scratch, addr);
}
break;
case T_CHAR: // fall through
case T_SHORT:
lmem = 2; lcon = 2; cbits = (int16_t)(c->as_jint());
break;
case T_CHAR: // fall through
case T_SHORT:
__ load_const_optimized(Z_R0_scratch, (int16_t)(c->as_jint()));
store_offset = __ offset();
if (Immediate::is_uimm12(addr.disp())) {
__ z_sth(Z_R0_scratch, addr);
} else {
__ z_sthy(Z_R0_scratch, addr);
}
break;
default:
ShouldNotReachHere();
};
// Index register is normally not supported, but for
// LIRGenerator::CardTableBarrierSet_post_barrier we make an exception.
if (type == T_BYTE && dest->as_address_ptr()->index()->is_valid()) {
__ load_const_optimized(Z_R0_scratch, (int8_t)(c->as_jint()));
store_offset = __ offset();
if (Immediate::is_uimm12(addr.disp())) {
__ z_stc(Z_R0_scratch, addr);
} else {
__ z_stcy(Z_R0_scratch, addr);
default:
ShouldNotReachHere();
}
}
if (store_offset == -1) {
store_offset = __ store_const(addr, cbits, lmem, lcon);
assert(store_offset >= 0, "check");
} else { // no index
unsigned int lmem = 0;
unsigned int lcon = 0;
int64_t cbits = 0;
switch (type) {
case T_INT: // fall through
case T_FLOAT:
lmem = 4; lcon = 4; cbits = c->as_jint_bits();
break;
case T_ADDRESS:
lmem = 8; lcon = 4; cbits = c->as_jint_bits();
break;
case T_OBJECT: // fall through
case T_ARRAY:
if (c->as_jobject() == NULL) {
if (UseCompressedOops && !wide) {
store_offset = __ store_const(addr, (int32_t)NULL_WORD, 4, 4);
} else {
store_offset = __ store_const(addr, (int64_t)NULL_WORD, 8, 8);
}
} else {
jobject2reg(c->as_jobject(), Z_R1_scratch);
if (UseCompressedOops && !wide) {
__ encode_heap_oop(Z_R1_scratch);
store_offset = __ reg2mem_opt(Z_R1_scratch, addr, false);
} else {
store_offset = __ reg2mem_opt(Z_R1_scratch, addr, true);
}
}
assert(store_offset >= 0, "check");
break;
case T_LONG: // fall through
case T_DOUBLE:
lmem = 8; lcon = 8; cbits = (int64_t)(c->as_jlong_bits());
break;
case T_BOOLEAN: // fall through
case T_BYTE:
lmem = 1; lcon = 1; cbits = (int8_t)(c->as_jint());
break;
case T_CHAR: // fall through
case T_SHORT:
lmem = 2; lcon = 2; cbits = (int16_t)(c->as_jint());
break;
default:
ShouldNotReachHere();
}
if (store_offset == -1) {
store_offset = __ store_const(addr, cbits, lmem, lcon);
assert(store_offset >= 0, "check");
}
}
if (info != NULL) {

View File

@ -140,7 +140,13 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index,
int shift, int disp, BasicType type) {
assert(base->is_register(), "must be");
if (index->is_constant()) {
intptr_t large_disp = ((intx)(index->as_constant_ptr()->as_jint()) << shift) + disp;
intx large_disp = disp;
LIR_Const *constant = index->as_constant_ptr();
if (constant->type() == T_LONG) {
large_disp += constant->as_jlong() << shift;
} else {
large_disp += (intx)(constant->as_jint()) << shift;
}
if (Displacement::is_validDisp(large_disp)) {
return new LIR_Address(base, large_disp, type);
}
@ -159,7 +165,7 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index,
}
LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr,
BasicType type, bool needs_card_mark) {
BasicType type) {
int elem_size = type2aelembytes(type);
int shift = exact_log2(elem_size);
int offset_in_bytes = arrayOopDesc::base_offset_in_bytes(type);
@ -181,16 +187,7 @@ LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_o
index_opr,
offset_in_bytes, type);
}
if (needs_card_mark) {
// This store will need a precise card mark, so go ahead and
// compute the full adddres instead of computing once for the
// store and again for the card mark.
LIR_Opr tmp = new_pointer_register();
__ leal(LIR_OprFact::address(addr), tmp);
return new LIR_Address(tmp, type);
} else {
return addr;
}
return addr;
}
LIR_Opr LIRGenerator::load_immediate(int x, BasicType type) {
@ -252,86 +249,11 @@ void LIRGenerator::store_stack_parameter (LIR_Opr item, ByteSize offset_from_sp)
// visitor functions
//----------------------------------------------------------------------
void LIRGenerator::do_StoreIndexed(StoreIndexed* x) {
assert(x->is_pinned(),"");
bool needs_range_check = x->compute_needs_range_check();
bool use_length = x->length() != NULL;
bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT;
bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL ||
!get_jobject_constant(x->value())->is_null_object() ||
x->should_profile());
LIRItem array(x->array(), this);
LIRItem index(x->index(), this);
LIRItem value(x->value(), this);
LIRItem length(this);
array.load_item();
index.load_nonconstant(20);
if (use_length && needs_range_check) {
length.set_instruction(x->length());
length.load_item();
}
if (needs_store_check || x->check_boolean()) {
value.load_item();
} else {
value.load_for_store(x->elt_type());
}
set_no_result(x);
// The CodeEmitInfo must be duplicated for each different
// LIR-instruction because spilling can occur anywhere between two
// instructions and so the debug information must be different.
CodeEmitInfo* range_check_info = state_for (x);
CodeEmitInfo* null_check_info = NULL;
if (x->needs_null_check()) {
null_check_info = new CodeEmitInfo(range_check_info);
}
// Emit array address setup early so it schedules better.
LIR_Address* array_addr = emit_array_address(array.result(), index.result(), x->elt_type(), obj_store);
if (value.result()->is_constant() && array_addr->index()->is_valid()) {
// Constants cannot be stored with index register on ZARCH_64 (see LIR_Assembler::const2mem()).
LIR_Opr tmp = new_pointer_register();
__ leal(LIR_OprFact::address(array_addr), tmp);
array_addr = new LIR_Address(tmp, x->elt_type());
}
if (GenerateRangeChecks && needs_range_check) {
if (use_length) {
__ cmp(lir_cond_belowEqual, length.result(), index.result());
__ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result()));
} else {
array_range_check(array.result(), index.result(), null_check_info, range_check_info);
// Range_check also does the null check.
null_check_info = NULL;
}
}
if (GenerateArrayStoreCheck && needs_store_check) {
LIR_Opr tmp1 = new_register(objectType);
LIR_Opr tmp2 = new_register(objectType);
LIR_Opr tmp3 = LIR_OprFact::illegalOpr;
CodeEmitInfo* store_check_info = new CodeEmitInfo(range_check_info);
__ store_check(value.result(), array.result(), tmp1, tmp2, tmp3, store_check_info, x->profiled_method(), x->profiled_bci());
}
if (obj_store) {
// Needs GC write barriers.
pre_barrier(LIR_OprFact::address(array_addr), LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
}
LIR_Opr result = maybe_mask_boolean(x, array.result(), value.result(), null_check_info);
__ move(result, array_addr, null_check_info);
if (obj_store) {
// Precise card mark
post_barrier(LIR_OprFact::address(array_addr), value.result());
}
void LIRGenerator::array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, ciMethod* profiled_method, int profiled_bci) {
LIR_Opr tmp1 = new_register(objectType);
LIR_Opr tmp2 = new_register(objectType);
LIR_Opr tmp3 = LIR_OprFact::illegalOpr;
__ store_check(value, array, tmp1, tmp2, tmp3, store_check_info, profiled_method, profiled_bci);
}
void LIRGenerator::do_MonitorEnter(MonitorEnter* x) {
@ -665,59 +587,42 @@ void LIRGenerator::do_CompareOp(CompareOp* x) {
}
}
void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) {
assert(x->number_of_arguments() == 4, "wrong type");
LIRItem obj (x->argument_at(0), this); // object
LIRItem offset(x->argument_at(1), this); // offset of field
LIRItem cmp (x->argument_at(2), this); // Value to compare with field.
LIRItem val (x->argument_at(3), this); // Replace field with val if matches cmp.
// Get address of field.
obj.load_item();
offset.load_nonconstant(20);
cmp.load_item();
val.load_item();
LIR_Opr addr = new_pointer_register();
LIR_Address* a;
if (offset.result()->is_constant()) {
assert(Immediate::is_simm20(offset.result()->as_jlong()), "should have been loaded into register");
a = new LIR_Address(obj.result(),
offset.result()->as_jlong(),
as_BasicType(type));
} else {
a = new LIR_Address(obj.result(),
offset.result(),
0,
as_BasicType(type));
}
__ leal(LIR_OprFact::address(a), addr);
if (type == objectType) { // Write-barrier needed for Object fields.
pre_barrier(addr, LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
}
LIR_Opr ill = LIR_OprFact::illegalOpr; // for convenience
if (type == objectType) {
__ cas_obj(addr, cmp.result(), val.result(), new_register(T_OBJECT), new_register(T_OBJECT));
} else if (type == intType) {
__ cas_int(addr, cmp.result(), val.result(), ill, ill);
} else if (type == longType) {
__ cas_long(addr, cmp.result(), val.result(), ill, ill);
LIR_Opr LIRGenerator::atomic_cmpxchg(BasicType type, LIR_Opr addr, LIRItem& cmp_value, LIRItem& new_value) {
LIR_Opr t1 = LIR_OprFact::illegalOpr;
LIR_Opr t2 = LIR_OprFact::illegalOpr;
cmp_value.load_item();
new_value.load_item();
if (type == T_OBJECT) {
if (UseCompressedOops) {
t1 = new_register(T_OBJECT);
t2 = new_register(T_OBJECT);
}
__ cas_obj(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2);
} else if (type == T_INT) {
__ cas_int(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2);
} else if (type == T_LONG) {
__ cas_long(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2);
} else {
ShouldNotReachHere();
}
// Generate conditional move of boolean result.
LIR_Opr result = rlock_result(x);
LIR_Opr result = new_register(T_INT);
__ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0),
result, as_BasicType(type));
if (type == objectType) { // Write-barrier needed for Object fields.
// Precise card mark since could either be object or array
post_barrier(addr, val.result());
}
result, type);
return result;
}
LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) {
Unimplemented(); // Currently not supported on this platform.
return LIR_OprFact::illegalOpr;
}
LIR_Opr LIRGenerator::atomic_add(BasicType type, LIR_Opr addr, LIRItem& value) {
LIR_Opr result = new_register(type);
value.load_item();
__ xadd(addr, value.result(), result, LIR_OprFact::illegalOpr);
return result;
}
void LIRGenerator::do_MathIntrinsic(Intrinsic* x) {
switch (x->id()) {
@ -1104,57 +1009,6 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result,
__ load(address, result, info);
}
void LIRGenerator::put_Object_unsafe(LIR_Opr src, LIR_Opr offset, LIR_Opr data,
BasicType type, bool is_volatile) {
LIR_Address* addr = new LIR_Address(src, offset, type);
bool is_obj = (type == T_ARRAY || type == T_OBJECT);
if (is_obj) {
// Do the pre-write barrier, if any.
pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
__ move(data, addr);
assert(src->is_register(), "must be register");
// Seems to be a precise address.
post_barrier(LIR_OprFact::address(addr), data);
} else {
__ move(data, addr);
}
}
void LIRGenerator::get_Object_unsafe(LIR_Opr dst, LIR_Opr src, LIR_Opr offset,
BasicType type, bool is_volatile) {
LIR_Address* addr = new LIR_Address(src, offset, type);
__ load(addr, dst);
}
void LIRGenerator::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {
BasicType type = x->basic_type();
assert (x->is_add() && type != T_ARRAY && type != T_OBJECT, "not supported");
LIRItem src(x->object(), this);
LIRItem off(x->offset(), this);
LIRItem value(x->value(), this);
src.load_item();
value.load_item();
off.load_nonconstant(20);
LIR_Opr dst = rlock_result(x, type);
LIR_Opr data = value.result();
LIR_Opr offset = off.result();
LIR_Address* addr;
if (offset->is_constant()) {
assert(Immediate::is_simm20(offset->as_jlong()), "should have been loaded into register");
addr = new LIR_Address(src.result(), offset->as_jlong(), type);
} else {
addr = new LIR_Address(src.result(), offset, type);
}
__ xadd(LIR_OprFact::address(addr), data, dst, LIR_OprFact::illegalOpr);
}
void LIRGenerator::do_update_CRC32(Intrinsic* x) {
assert(UseCRC32Intrinsics, "or should not be here");
LIR_Opr result = rlock_result(x);

View File

@ -42,11 +42,6 @@
#include "utilities/macros.hpp"
#include "vmreg_s390.inline.hpp"
#include "registerSaver_s390.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CardTable.hpp"
#include "gc/g1/g1ThreadLocalData.hpp"
#endif
// Implementation of StubAssembler
@ -190,15 +185,6 @@ static OopMap* save_live_registers_except_r2(StubAssembler* sasm, bool save_fpu_
return RegisterSaver::save_live_registers(sasm, reg_set);
}
static OopMap* save_volatile_registers(StubAssembler* sasm, Register return_pc = Z_R14) {
__ block_comment("save_volatile_registers");
RegisterSaver::RegisterSet reg_set = RegisterSaver::all_volatile_registers;
int frame_size_in_slots =
RegisterSaver::live_reg_frame_size(reg_set) / VMRegImpl::stack_slot_size;
sasm->set_frame_size(frame_size_in_slots / VMRegImpl::slots_per_word);
return RegisterSaver::save_live_registers(sasm, reg_set, return_pc);
}
static void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registers = true) {
__ block_comment("restore_live_registers");
RegisterSaver::RegisterSet reg_set =
@ -214,12 +200,6 @@ static void restore_live_registers_except_r2(StubAssembler* sasm, bool restore_f
RegisterSaver::restore_live_registers(sasm, RegisterSaver::all_registers_except_r2);
}
static void restore_volatile_registers(StubAssembler* sasm) {
__ block_comment("restore_volatile_registers");
RegisterSaver::RegisterSet reg_set = RegisterSaver::all_volatile_registers;
RegisterSaver::restore_live_registers(sasm, reg_set);
}
void Runtime1::initialize_pd() {
// Nothing to do.
}
@ -764,160 +744,6 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
break;
#endif // TODO
#if INCLUDE_ALL_GCS
case g1_pre_barrier_slow_id:
{ // Z_R1_scratch: previous value of memory
BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ should_not_reach_here(FILE_AND_LINE);
break;
}
__ set_info("g1_pre_barrier_slow_id", dont_gc_arguments);
Register pre_val = Z_R1_scratch;
Register tmp = Z_R6; // Must be non-volatile because it is used to save pre_val.
Register tmp2 = Z_R7;
Label refill, restart, marking_not_active;
int satb_q_active_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset());
int satb_q_index_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset());
int satb_q_buf_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset());
// Save tmp registers (see assertion in G1PreBarrierStub::emit_code()).
__ z_stg(tmp, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
__ z_stg(tmp2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
// Is marking still active?
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
__ load_and_test_int(tmp, Address(Z_thread, satb_q_active_byte_offset));
} else {
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
__ load_and_test_byte(tmp, Address(Z_thread, satb_q_active_byte_offset));
}
__ z_bre(marking_not_active); // Activity indicator is zero, so there is no marking going on currently.
__ bind(restart);
// Load the index into the SATB buffer. SATBMarkQueue::_index is a
// size_t so ld_ptr is appropriate.
__ z_ltg(tmp, satb_q_index_byte_offset, Z_R0, Z_thread);
// index == 0?
__ z_brz(refill);
__ z_lg(tmp2, satb_q_buf_byte_offset, Z_thread);
__ add2reg(tmp, -oopSize);
__ z_stg(pre_val, 0, tmp, tmp2); // [_buf + index] := <address_of_card>
__ z_stg(tmp, satb_q_index_byte_offset, Z_thread);
__ bind(marking_not_active);
// Restore tmp registers (see assertion in G1PreBarrierStub::emit_code()).
__ z_lg(tmp, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
__ z_lg(tmp2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
__ z_br(Z_R14);
__ bind(refill);
save_volatile_registers(sasm);
__ z_lgr(tmp, pre_val); // save pre_val
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SATBMarkQueueSet::handle_zero_index_for_thread),
Z_thread);
__ z_lgr(pre_val, tmp); // restore pre_val
restore_volatile_registers(sasm);
__ z_bru(restart);
}
break;
case g1_post_barrier_slow_id:
{ // Z_R1_scratch: oop address, address of updated memory slot
BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ should_not_reach_here(FILE_AND_LINE);
break;
}
__ set_info("g1_post_barrier_slow_id", dont_gc_arguments);
Register addr_oop = Z_R1_scratch;
Register addr_card = Z_R1_scratch;
Register r1 = Z_R6; // Must be saved/restored.
Register r2 = Z_R7; // Must be saved/restored.
Register cardtable = r1; // Must be non-volatile, because it is used to save addr_card.
jbyte* byte_map_base = ci_card_table_address();
// Save registers used below (see assertion in G1PreBarrierStub::emit_code()).
__ z_stg(r1, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
Label not_already_dirty, restart, refill, young_card;
// Calculate address of card corresponding to the updated oop slot.
AddressLiteral rs(byte_map_base);
__ z_srlg(addr_card, addr_oop, CardTable::card_shift);
addr_oop = noreg; // dead now
__ load_const_optimized(cardtable, rs); // cardtable := <card table base>
__ z_agr(addr_card, cardtable); // addr_card := addr_oop>>card_shift + cardtable
__ z_cli(0, addr_card, (int)G1CardTable::g1_young_card_val());
__ z_bre(young_card);
__ z_sync(); // Required to support concurrent cleaning.
__ z_cli(0, addr_card, (int)CardTable::dirty_card_val());
__ z_brne(not_already_dirty);
__ bind(young_card);
// We didn't take the branch, so we're already dirty: restore
// used registers and return.
__ z_lg(r1, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
__ z_br(Z_R14);
// Not dirty.
__ bind(not_already_dirty);
// First, dirty it: [addr_card] := 0
__ z_mvi(0, addr_card, CardTable::dirty_card_val());
Register idx = cardtable; // Must be non-volatile, because it is used to save addr_card.
Register buf = r2;
cardtable = noreg; // now dead
// Save registers used below (see assertion in G1PreBarrierStub::emit_code()).
__ z_stg(r2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
ByteSize dirty_card_q_index_byte_offset = G1ThreadLocalData::dirty_card_queue_index_offset();
ByteSize dirty_card_q_buf_byte_offset = G1ThreadLocalData::dirty_card_queue_buffer_offset();
__ bind(restart);
// Get the index into the update buffer. DirtyCardQueue::_index is
// a size_t so z_ltg is appropriate here.
__ z_ltg(idx, Address(Z_thread, dirty_card_q_index_byte_offset));
// index == 0?
__ z_brz(refill);
__ z_lg(buf, Address(Z_thread, dirty_card_q_buf_byte_offset));
__ add2reg(idx, -oopSize);
__ z_stg(addr_card, 0, idx, buf); // [_buf + index] := <address_of_card>
__ z_stg(idx, Address(Z_thread, dirty_card_q_index_byte_offset));
// Restore killed registers and return.
__ z_lg(r1, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
__ z_lg(r2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
__ z_br(Z_R14);
__ bind(refill);
save_volatile_registers(sasm);
__ z_lgr(idx, addr_card); // Save addr_card, tmp3 must be non-volatile.
__ call_VM_leaf(CAST_FROM_FN_PTR(address, DirtyCardQueueSet::handle_zero_index_for_thread),
Z_thread);
__ z_lgr(addr_card, idx);
restore_volatile_registers(sasm); // Restore addr_card.
__ z_bru(restart);
}
break;
#endif // INCLUDE_ALL_GCS
case predicate_failed_trap_id:
{
__ set_info("predicate_failed_trap", dont_gc_arguments);

View File

@ -33,6 +33,11 @@
#include "gc/g1/heapRegion.hpp"
#include "interpreter/interp_masm.hpp"
#include "runtime/sharedRuntime.hpp"
#ifdef COMPILER1
#include "c1/c1_LIRAssembler.hpp"
#include "c1/c1_MacroAssembler.hpp"
#include "gc/g1/c1/g1BarrierSetC1.hpp"
#endif
#define __ masm->
@ -406,4 +411,209 @@ void G1BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value
__ bind(Ldone);
}
#ifdef COMPILER1
#undef __
#define __ ce->masm()->
void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) {
G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
// At this point we know that marking is in progress.
// If do_load() is true then we have to emit the
// load of the previous value; otherwise it has already
// been loaded into _pre_val.
__ bind(*stub->entry());
ce->check_reserved_argument_area(16); // RT stub needs 2 spill slots.
assert(stub->pre_val()->is_register(), "Precondition.");
Register pre_val_reg = stub->pre_val()->as_register();
if (stub->do_load()) {
ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/, false /*unaligned*/);
}
__ z_ltgr(Z_R1_scratch, pre_val_reg); // Pass oop in Z_R1_scratch to Runtime1::g1_pre_barrier_slow_id.
__ branch_optimized(Assembler::bcondZero, *stub->continuation());
ce->emit_call_c(bs->pre_barrier_c1_runtime_code_blob()->code_begin());
__ branch_optimized(Assembler::bcondAlways, *stub->continuation());
}
void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) {
G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
__ bind(*stub->entry());
ce->check_reserved_argument_area(16); // RT stub needs 2 spill slots.
assert(stub->addr()->is_register(), "Precondition.");
assert(stub->new_val()->is_register(), "Precondition.");
Register new_val_reg = stub->new_val()->as_register();
__ z_ltgr(new_val_reg, new_val_reg);
__ branch_optimized(Assembler::bcondZero, *stub->continuation());
__ z_lgr(Z_R1_scratch, stub->addr()->as_pointer_register());
ce->emit_call_c(bs->post_barrier_c1_runtime_code_blob()->code_begin());
__ branch_optimized(Assembler::bcondAlways, *stub->continuation());
}
#undef __
#define __ sasm->
static OopMap* save_volatile_registers(StubAssembler* sasm, Register return_pc = Z_R14) {
__ block_comment("save_volatile_registers");
RegisterSaver::RegisterSet reg_set = RegisterSaver::all_volatile_registers;
int frame_size_in_slots = RegisterSaver::live_reg_frame_size(reg_set) / VMRegImpl::stack_slot_size;
sasm->set_frame_size(frame_size_in_slots / VMRegImpl::slots_per_word);
return RegisterSaver::save_live_registers(sasm, reg_set, return_pc);
}
static void restore_volatile_registers(StubAssembler* sasm) {
__ block_comment("restore_volatile_registers");
RegisterSaver::RegisterSet reg_set = RegisterSaver::all_volatile_registers;
RegisterSaver::restore_live_registers(sasm, reg_set);
}
void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) {
// Z_R1_scratch: previous value of memory
BarrierSet* bs = BarrierSet::barrier_set();
__ set_info("g1_pre_barrier_slow_id", false);
Register pre_val = Z_R1_scratch;
Register tmp = Z_R6; // Must be non-volatile because it is used to save pre_val.
Register tmp2 = Z_R7;
Label refill, restart, marking_not_active;
int satb_q_active_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset());
int satb_q_index_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset());
int satb_q_buf_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset());
// Save tmp registers (see assertion in G1PreBarrierStub::emit_code()).
__ z_stg(tmp, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
__ z_stg(tmp2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
// Is marking still active?
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
__ load_and_test_int(tmp, Address(Z_thread, satb_q_active_byte_offset));
} else {
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
__ load_and_test_byte(tmp, Address(Z_thread, satb_q_active_byte_offset));
}
__ z_bre(marking_not_active); // Activity indicator is zero, so there is no marking going on currently.
__ bind(restart);
// Load the index into the SATB buffer. SATBMarkQueue::_index is a
// size_t so ld_ptr is appropriate.
__ z_ltg(tmp, satb_q_index_byte_offset, Z_R0, Z_thread);
// index == 0?
__ z_brz(refill);
__ z_lg(tmp2, satb_q_buf_byte_offset, Z_thread);
__ add2reg(tmp, -oopSize);
__ z_stg(pre_val, 0, tmp, tmp2); // [_buf + index] := <address_of_card>
__ z_stg(tmp, satb_q_index_byte_offset, Z_thread);
__ bind(marking_not_active);
// Restore tmp registers (see assertion in G1PreBarrierStub::emit_code()).
__ z_lg(tmp, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
__ z_lg(tmp2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
__ z_br(Z_R14);
__ bind(refill);
save_volatile_registers(sasm);
__ z_lgr(tmp, pre_val); // save pre_val
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SATBMarkQueueSet::handle_zero_index_for_thread),
Z_thread);
__ z_lgr(pre_val, tmp); // restore pre_val
restore_volatile_registers(sasm);
__ z_bru(restart);
}
void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) {
// Z_R1_scratch: oop address, address of updated memory slot
BarrierSet* bs = BarrierSet::barrier_set();
__ set_info("g1_post_barrier_slow_id", false);
Register addr_oop = Z_R1_scratch;
Register addr_card = Z_R1_scratch;
Register r1 = Z_R6; // Must be saved/restored.
Register r2 = Z_R7; // Must be saved/restored.
Register cardtable = r1; // Must be non-volatile, because it is used to save addr_card.
CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
CardTable* ct = ctbs->card_table();
jbyte* byte_map_base = ct->byte_map_base();
// Save registers used below (see assertion in G1PreBarrierStub::emit_code()).
__ z_stg(r1, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
Label not_already_dirty, restart, refill, young_card;
// Calculate address of card corresponding to the updated oop slot.
AddressLiteral rs(byte_map_base);
__ z_srlg(addr_card, addr_oop, CardTable::card_shift);
addr_oop = noreg; // dead now
__ load_const_optimized(cardtable, rs); // cardtable := <card table base>
__ z_agr(addr_card, cardtable); // addr_card := addr_oop>>card_shift + cardtable
__ z_cli(0, addr_card, (int)G1CardTable::g1_young_card_val());
__ z_bre(young_card);
__ z_sync(); // Required to support concurrent cleaning.
__ z_cli(0, addr_card, (int)CardTable::dirty_card_val());
__ z_brne(not_already_dirty);
__ bind(young_card);
// We didn't take the branch, so we're already dirty: restore
// used registers and return.
__ z_lg(r1, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
__ z_br(Z_R14);
// Not dirty.
__ bind(not_already_dirty);
// First, dirty it: [addr_card] := 0
__ z_mvi(0, addr_card, CardTable::dirty_card_val());
Register idx = cardtable; // Must be non-volatile, because it is used to save addr_card.
Register buf = r2;
cardtable = noreg; // now dead
// Save registers used below (see assertion in G1PreBarrierStub::emit_code()).
__ z_stg(r2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
ByteSize dirty_card_q_index_byte_offset = G1ThreadLocalData::dirty_card_queue_index_offset();
ByteSize dirty_card_q_buf_byte_offset = G1ThreadLocalData::dirty_card_queue_buffer_offset();
__ bind(restart);
// Get the index into the update buffer. DirtyCardQueue::_index is
// a size_t so z_ltg is appropriate here.
__ z_ltg(idx, Address(Z_thread, dirty_card_q_index_byte_offset));
// index == 0?
__ z_brz(refill);
__ z_lg(buf, Address(Z_thread, dirty_card_q_buf_byte_offset));
__ add2reg(idx, -oopSize);
__ z_stg(addr_card, 0, idx, buf); // [_buf + index] := <address_of_card>
__ z_stg(idx, Address(Z_thread, dirty_card_q_index_byte_offset));
// Restore killed registers and return.
__ z_lg(r1, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
__ z_lg(r2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
__ z_br(Z_R14);
__ bind(refill);
save_volatile_registers(sasm);
__ z_lgr(idx, addr_card); // Save addr_card, tmp3 must be non-volatile.
__ call_VM_leaf(CAST_FROM_FN_PTR(address, DirtyCardQueueSet::handle_zero_index_for_thread),
Z_thread);
__ z_lgr(addr_card, idx);
restore_volatile_registers(sasm); // Restore addr_card.
__ z_bru(restart);
}
#undef __
#endif // COMPILER1

View File

@ -28,6 +28,12 @@
#include "asm/macroAssembler.hpp"
#include "gc/shared/modRefBarrierSetAssembler.hpp"
#include "utilities/macros.hpp"
class LIR_Assembler;
class StubAssembler;
class G1PreBarrierStub;
class G1PostBarrierStub;
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
@ -50,6 +56,14 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
const Address& dst, Register val, Register tmp1, Register tmp2, Register tmp3);
public:
#ifdef COMPILER1
void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub);
void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
#endif
virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
const Address& src, Register dst, Register tmp1, Register tmp2, Label *is_null = NULL);

View File

@ -32,9 +32,6 @@
#include "runtime/sharedRuntime.hpp"
#include "utilities/macros.hpp"
#include "vmreg_sparc.inline.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#endif // INCLUDE_ALL_GCS
#define __ ce->masm()->
@ -454,63 +451,4 @@ void ArrayCopyStub::emit_code(LIR_Assembler* ce) {
__ delayed()->nop();
}
///////////////////////////////////////////////////////////////////////////////////
#if INCLUDE_ALL_GCS
void G1PreBarrierStub::emit_code(LIR_Assembler* ce) {
// At this point we know that marking is in progress.
// If do_load() is true then we have to emit the
// load of the previous value; otherwise it has already
// been loaded into _pre_val.
__ bind(_entry);
assert(pre_val()->is_register(), "Precondition.");
Register pre_val_reg = pre_val()->as_register();
if (do_load()) {
ce->mem2reg(addr(), pre_val(), T_OBJECT, patch_code(), info(), false /*wide*/, false /*unaligned*/);
}
if (__ is_in_wdisp16_range(_continuation)) {
__ br_null(pre_val_reg, /*annul*/false, Assembler::pt, _continuation);
} else {
__ cmp(pre_val_reg, G0);
__ brx(Assembler::equal, false, Assembler::pn, _continuation);
}
__ delayed()->nop();
__ call(Runtime1::entry_for(Runtime1::Runtime1::g1_pre_barrier_slow_id));
__ delayed()->mov(pre_val_reg, G4);
__ br(Assembler::always, false, Assembler::pt, _continuation);
__ delayed()->nop();
}
void G1PostBarrierStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
assert(addr()->is_register(), "Precondition.");
assert(new_val()->is_register(), "Precondition.");
Register addr_reg = addr()->as_pointer_register();
Register new_val_reg = new_val()->as_register();
if (__ is_in_wdisp16_range(_continuation)) {
__ br_null(new_val_reg, /*annul*/false, Assembler::pt, _continuation);
} else {
__ cmp(new_val_reg, G0);
__ brx(Assembler::equal, false, Assembler::pn, _continuation);
}
__ delayed()->nop();
__ call(Runtime1::entry_for(Runtime1::Runtime1::g1_post_barrier_slow_id));
__ delayed()->mov(addr_reg, G4);
__ br(Assembler::always, false, Assembler::pt, _continuation);
__ delayed()->nop();
}
#endif // INCLUDE_ALL_GCS
///////////////////////////////////////////////////////////////////////////////////
#undef __

View File

@ -193,7 +193,7 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index,
LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr,
BasicType type, bool needs_card_mark) {
BasicType type) {
int elem_size = type2aelembytes(type);
int shift = exact_log2(elem_size);
@ -231,13 +231,8 @@ LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_o
__ add(index_opr, array_opr, base_opr);
}
}
if (needs_card_mark) {
LIR_Opr ptr = new_pointer_register();
__ add(base_opr, LIR_OprFact::intptrConst(offset), ptr);
return new LIR_Address(ptr, type);
} else {
return new LIR_Address(base_opr, offset, type);
}
return new LIR_Address(base_opr, offset, type);
}
LIR_Opr LIRGenerator::load_immediate(int x, BasicType type) {
@ -311,86 +306,17 @@ void LIRGenerator::store_stack_parameter (LIR_Opr item, ByteSize offset_from_sp)
}
}
void LIRGenerator::array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, ciMethod* profiled_method, int profiled_bci) {
LIR_Opr tmp1 = FrameMap::G1_opr;
LIR_Opr tmp2 = FrameMap::G3_opr;
LIR_Opr tmp3 = FrameMap::G5_opr;
__ store_check(value, array, tmp1, tmp2, tmp3, store_check_info, profiled_method, profiled_bci);
}
//----------------------------------------------------------------------
// visitor functions
//----------------------------------------------------------------------
void LIRGenerator::do_StoreIndexed(StoreIndexed* x) {
assert(x->is_pinned(),"");
bool needs_range_check = x->compute_needs_range_check();
bool use_length = x->length() != NULL;
bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT;
bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL ||
!get_jobject_constant(x->value())->is_null_object() ||
x->should_profile());
LIRItem array(x->array(), this);
LIRItem index(x->index(), this);
LIRItem value(x->value(), this);
LIRItem length(this);
array.load_item();
index.load_nonconstant();
if (use_length && needs_range_check) {
length.set_instruction(x->length());
length.load_item();
}
if (needs_store_check || x->check_boolean()) {
value.load_item();
} else {
value.load_for_store(x->elt_type());
}
set_no_result(x);
// the CodeEmitInfo must be duplicated for each different
// LIR-instruction because spilling can occur anywhere between two
// instructions and so the debug information must be different
CodeEmitInfo* range_check_info = state_for(x);
CodeEmitInfo* null_check_info = NULL;
if (x->needs_null_check()) {
null_check_info = new CodeEmitInfo(range_check_info);
}
// emit array address setup early so it schedules better
LIR_Address* array_addr = emit_array_address(array.result(), index.result(), x->elt_type(), obj_store);
if (GenerateRangeChecks && needs_range_check) {
if (use_length) {
__ cmp(lir_cond_belowEqual, length.result(), index.result());
__ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result()));
} else {
array_range_check(array.result(), index.result(), null_check_info, range_check_info);
// range_check also does the null check
null_check_info = NULL;
}
}
if (GenerateArrayStoreCheck && needs_store_check) {
LIR_Opr tmp1 = FrameMap::G1_opr;
LIR_Opr tmp2 = FrameMap::G3_opr;
LIR_Opr tmp3 = FrameMap::G5_opr;
CodeEmitInfo* store_check_info = new CodeEmitInfo(range_check_info);
__ store_check(value.result(), array.result(), tmp1, tmp2, tmp3, store_check_info, x->profiled_method(), x->profiled_bci());
}
if (obj_store) {
// Needs GC write barriers.
pre_barrier(LIR_OprFact::address(array_addr), LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
}
LIR_Opr result = maybe_mask_boolean(x, array.result(), value.result(), null_check_info);
__ move(result, array_addr, null_check_info);
if (obj_store) {
// Precise card mark
post_barrier(LIR_OprFact::address(array_addr), value.result());
}
}
void LIRGenerator::do_MonitorEnter(MonitorEnter* x) {
assert(x->is_pinned(),"");
LIRItem obj(x->obj(), this);
@ -635,51 +561,47 @@ void LIRGenerator::do_CompareOp(CompareOp* x) {
}
}
void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) {
assert(x->number_of_arguments() == 4, "wrong type");
LIRItem obj (x->argument_at(0), this); // object
LIRItem offset(x->argument_at(1), this); // offset of field
LIRItem cmp (x->argument_at(2), this); // value to compare with field
LIRItem val (x->argument_at(3), this); // replace field with val if matches cmp
// Use temps to avoid kills
LIR_Opr LIRGenerator::atomic_cmpxchg(BasicType type, LIR_Opr addr, LIRItem& cmp_value, LIRItem& new_value) {
LIR_Opr result = new_register(T_INT);
LIR_Opr t1 = FrameMap::G1_opr;
LIR_Opr t2 = FrameMap::G3_opr;
LIR_Opr addr = new_pointer_register();
// get address of field
obj.load_item();
offset.load_item();
cmp.load_item();
val.load_item();
__ add(obj.result(), offset.result(), addr);
if (type == objectType) { // Write-barrier needed for Object fields.
pre_barrier(addr, LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
cmp_value.load_item();
new_value.load_item();
if (type == T_OBJECT || type == T_ARRAY) {
__ cas_obj(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2);
} else if (type == T_INT) {
__ cas_int(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2);
} else if (type == T_LONG) {
__ cas_long(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2);
} else {
Unimplemented();
}
if (type == objectType)
__ cas_obj(addr, cmp.result(), val.result(), t1, t2);
else if (type == intType)
__ cas_int(addr, cmp.result(), val.result(), t1, t2);
else if (type == longType)
__ cas_long(addr, cmp.result(), val.result(), t1, t2);
else {
ShouldNotReachHere();
}
// generate conditional move of boolean result
LIR_Opr result = rlock_result(x);
__ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0),
result, as_BasicType(type));
if (type == objectType) { // Write-barrier needed for Object fields.
// Precise card mark since could either be object or array
post_barrier(addr, val.result());
}
result, type);
return result;
}
LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) {
bool is_obj = type == T_OBJECT || type == T_ARRAY;
LIR_Opr result = new_register(type);
LIR_Opr tmp = LIR_OprFact::illegalOpr;
value.load_item();
if (is_obj) {
tmp = FrameMap::G3_opr;
}
// Because we want a 2-arg form of xchg
__ move(value.result(), result);
__ xchg(addr, result, result, tmp);
return result;
}
LIR_Opr LIRGenerator::atomic_add(BasicType type, LIR_Opr addr, LIRItem& value) {
Unimplemented();
return LIR_OprFact::illegalOpr;
}
void LIRGenerator::do_MathIntrinsic(Intrinsic* x) {
switch (x->id()) {
@ -1338,94 +1260,3 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result,
CodeEmitInfo* info) {
__ load(address, result, info);
}
void LIRGenerator::put_Object_unsafe(LIR_Opr src, LIR_Opr offset, LIR_Opr data,
BasicType type, bool is_volatile) {
LIR_Opr base_op = src;
LIR_Opr index_op = offset;
bool is_obj = (type == T_ARRAY || type == T_OBJECT);
{
if (type == T_BOOLEAN) {
type = T_BYTE;
}
LIR_Address* addr;
if (type == T_ARRAY || type == T_OBJECT) {
LIR_Opr tmp = new_pointer_register();
__ add(base_op, index_op, tmp);
addr = new LIR_Address(tmp, type);
} else {
addr = new LIR_Address(base_op, index_op, type);
}
if (is_obj) {
pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
// _bs->c1_write_barrier_pre(this, LIR_OprFact::address(addr));
}
__ move(data, addr);
if (is_obj) {
// This address is precise
post_barrier(LIR_OprFact::address(addr), data);
}
}
}
void LIRGenerator::get_Object_unsafe(LIR_Opr dst, LIR_Opr src, LIR_Opr offset,
BasicType type, bool is_volatile) {
{
LIR_Address* addr = new LIR_Address(src, offset, type);
__ load(addr, dst);
}
}
void LIRGenerator::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {
BasicType type = x->basic_type();
LIRItem src(x->object(), this);
LIRItem off(x->offset(), this);
LIRItem value(x->value(), this);
src.load_item();
value.load_item();
off.load_nonconstant();
LIR_Opr dst = rlock_result(x, type);
LIR_Opr data = value.result();
bool is_obj = (type == T_ARRAY || type == T_OBJECT);
LIR_Opr offset = off.result();
// Because we want a 2-arg form of xchg
__ move(data, dst);
assert (!x->is_add() && (type == T_INT || (is_obj && UseCompressedOops)), "unexpected type");
LIR_Address* addr;
if (offset->is_constant()) {
jlong l = offset->as_jlong();
assert((jlong)((jint)l) == l, "offset too large for constant");
jint c = (jint)l;
addr = new LIR_Address(src.result(), c, type);
} else {
addr = new LIR_Address(src.result(), offset, type);
}
LIR_Opr tmp = LIR_OprFact::illegalOpr;
LIR_Opr ptr = LIR_OprFact::illegalOpr;
if (is_obj) {
// Do the pre-write barrier, if any.
// barriers on sparc don't work with a base + index address
tmp = FrameMap::G3_opr;
ptr = new_pointer_register();
__ add(src.result(), off.result(), ptr);
pre_barrier(ptr, LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
}
__ xchg(LIR_OprFact::address(addr), dst, dst, tmp);
if (is_obj) {
// Seems to be a precise address
post_barrier(ptr, data);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -92,4 +92,7 @@
// This platform only uses signal-based null checks. The Label is not needed.
void null_check(Register r, Label *Lnull = NULL) { MacroAssembler::null_check(r); }
void save_live_registers_no_oop_map(bool save_fpu_registers);
void restore_live_registers(bool restore_fpu_registers);
#endif // CPU_SPARC_VM_C1_MACROASSEMBLER_SPARC_HPP

View File

@ -40,11 +40,6 @@
#include "utilities/macros.hpp"
#include "utilities/align.hpp"
#include "vmreg_sparc.inline.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CardTable.hpp"
#include "gc/g1/g1ThreadLocalData.hpp"
#endif
// Implementation of StubAssembler
@ -145,10 +140,16 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre
return call_RT(oop_result1, metadata_result, entry, 3);
}
void StubAssembler::prologue(const char* name, bool must_gc_arguments) {
set_info(name, must_gc_arguments);
}
void StubAssembler::epilogue() {
delayed()->restore();
}
// Implementation of Runtime1
#define __ sasm->
static int cpu_reg_save_offsets[FrameMap::nof_cpu_regs];
static int fpu_reg_save_offsets[FrameMap::nof_fpu_regs];
@ -156,7 +157,7 @@ static int reg_save_size_in_words;
static int frame_size_in_bytes = -1;
static OopMap* generate_oop_map(StubAssembler* sasm, bool save_fpu_registers) {
assert(frame_size_in_bytes == __ total_frame_size_in_bytes(reg_save_size_in_words),
assert(frame_size_in_bytes == sasm->total_frame_size_in_bytes(reg_save_size_in_words),
"mismatch in calculation");
sasm->set_frame_size(frame_size_in_bytes / BytesPerWord);
int frame_size_in_slots = frame_size_in_bytes / sizeof(jint);
@ -183,7 +184,9 @@ static OopMap* generate_oop_map(StubAssembler* sasm, bool save_fpu_registers) {
return oop_map;
}
static OopMap* save_live_registers(StubAssembler* sasm, bool save_fpu_registers = true) {
#define __ this->
void C1_MacroAssembler::save_live_registers_no_oop_map(bool save_fpu_registers) {
assert(frame_size_in_bytes == __ total_frame_size_in_bytes(reg_save_size_in_words),
"mismatch in calculation");
__ save_frame_c1(frame_size_in_bytes);
@ -211,11 +214,9 @@ static OopMap* save_live_registers(StubAssembler* sasm, bool save_fpu_registers
__ stf(FloatRegisterImpl::S, r, SP, (sp_offset * BytesPerWord) + STACK_BIAS);
}
}
return generate_oop_map(sasm, save_fpu_registers);
}
static void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registers = true) {
void C1_MacroAssembler::restore_live_registers(bool restore_fpu_registers) {
for (int i = 0; i < FrameMap::nof_cpu_regs; i++) {
Register r = as_Register(i);
if (r == G1 || r == G3 || r == G4 || r == G5) {
@ -231,6 +232,18 @@ static void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registe
}
}
#undef __
#define __ sasm->
static OopMap* save_live_registers(StubAssembler* sasm, bool save_fpu_registers = true) {
sasm->save_live_registers_no_oop_map(save_fpu_registers);
return generate_oop_map(sasm, save_fpu_registers);
}
static void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registers = true) {
sasm->restore_live_registers(restore_fpu_registers);
}
void Runtime1::initialize_pd() {
// compute word offsets from SP at which live (non-windowed) registers are captured by stub routines
@ -759,165 +772,6 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
#if INCLUDE_ALL_GCS
case g1_pre_barrier_slow_id:
{ // G4: previous value of memory
BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ save_frame(0);
__ set((int)id, O1);
__ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), I0);
__ should_not_reach_here();
break;
}
__ set_info("g1_pre_barrier_slow_id", dont_gc_arguments);
Register pre_val = G4;
Register tmp = G1_scratch;
Register tmp2 = G3_scratch;
Label refill, restart;
int satb_q_active_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset());
int satb_q_index_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset());
int satb_q_buf_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset());
// Is marking still active?
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
__ ld(G2_thread, satb_q_active_byte_offset, tmp);
} else {
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
__ ldsb(G2_thread, satb_q_active_byte_offset, tmp);
}
__ cmp_and_br_short(tmp, G0, Assembler::notEqual, Assembler::pt, restart);
__ retl();
__ delayed()->nop();
__ bind(restart);
// Load the index into the SATB buffer. SATBMarkQueue::_index is a
// size_t so ld_ptr is appropriate
__ ld_ptr(G2_thread, satb_q_index_byte_offset, tmp);
// index == 0?
__ cmp_and_brx_short(tmp, G0, Assembler::equal, Assembler::pn, refill);
__ ld_ptr(G2_thread, satb_q_buf_byte_offset, tmp2);
__ sub(tmp, oopSize, tmp);
__ st_ptr(pre_val, tmp2, tmp); // [_buf + index] := <address_of_card>
// Use return-from-leaf
__ retl();
__ delayed()->st_ptr(tmp, G2_thread, satb_q_index_byte_offset);
__ bind(refill);
save_live_registers(sasm);
__ call_VM_leaf(L7_thread_cache,
CAST_FROM_FN_PTR(address,
SATBMarkQueueSet::handle_zero_index_for_thread),
G2_thread);
restore_live_registers(sasm);
__ br(Assembler::always, /*annul*/false, Assembler::pt, restart);
__ delayed()->restore();
}
break;
case g1_post_barrier_slow_id:
{
BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ save_frame(0);
__ set((int)id, O1);
__ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), I0);
__ should_not_reach_here();
break;
}
__ set_info("g1_post_barrier_slow_id", dont_gc_arguments);
Register addr = G4;
Register cardtable = G5;
Register tmp = G1_scratch;
Register tmp2 = G3_scratch;
jbyte* byte_map_base = ci_card_table_address();
Label not_already_dirty, restart, refill, young_card;
__ srlx(addr, CardTable::card_shift, addr);
AddressLiteral rs(byte_map_base);
__ set(rs, cardtable); // cardtable := <card table base>
__ ldub(addr, cardtable, tmp); // tmp := [addr + cardtable]
__ cmp_and_br_short(tmp, G1CardTable::g1_young_card_val(), Assembler::equal, Assembler::pt, young_card);
__ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad));
__ ldub(addr, cardtable, tmp); // tmp := [addr + cardtable]
assert(CardTable::dirty_card_val() == 0, "otherwise check this code");
__ cmp_and_br_short(tmp, G0, Assembler::notEqual, Assembler::pt, not_already_dirty);
__ bind(young_card);
// We didn't take the branch, so we're already dirty: return.
// Use return-from-leaf
__ retl();
__ delayed()->nop();
// Not dirty.
__ bind(not_already_dirty);
// Get cardtable + tmp into a reg by itself
__ add(addr, cardtable, tmp2);
// First, dirty it.
__ stb(G0, tmp2, 0); // [cardPtr] := 0 (i.e., dirty).
Register tmp3 = cardtable;
Register tmp4 = tmp;
// these registers are now dead
addr = cardtable = tmp = noreg;
int dirty_card_q_index_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset());
int dirty_card_q_buf_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset());
__ bind(restart);
// Get the index into the update buffer. DirtyCardQueue::_index is
// a size_t so ld_ptr is appropriate here.
__ ld_ptr(G2_thread, dirty_card_q_index_byte_offset, tmp3);
// index == 0?
__ cmp_and_brx_short(tmp3, G0, Assembler::equal, Assembler::pn, refill);
__ ld_ptr(G2_thread, dirty_card_q_buf_byte_offset, tmp4);
__ sub(tmp3, oopSize, tmp3);
__ st_ptr(tmp2, tmp4, tmp3); // [_buf + index] := <address_of_card>
// Use return-from-leaf
__ retl();
__ delayed()->st_ptr(tmp3, G2_thread, dirty_card_q_index_byte_offset);
__ bind(refill);
save_live_registers(sasm);
__ call_VM_leaf(L7_thread_cache,
CAST_FROM_FN_PTR(address,
DirtyCardQueueSet::handle_zero_index_for_thread),
G2_thread);
restore_live_registers(sasm);
__ br(Assembler::always, /*annul*/false, Assembler::pt, restart);
__ delayed()->restore();
}
break;
#endif // INCLUDE_ALL_GCS
case predicate_failed_trap_id:
{
__ set_info("predicate_failed_trap", dont_gc_arguments);

View File

@ -25,13 +25,18 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CardTable.hpp"
#include "gc/g1/g1BarrierSetAssembler.hpp"
#include "gc/g1/g1CardTable.hpp"
#include "gc/g1/g1ThreadLocalData.hpp"
#include "gc/g1/heapRegion.hpp"
#include "interpreter/interp_masm.hpp"
#include "runtime/sharedRuntime.hpp"
#include "utilities/macros.hpp"
#ifdef COMPILER1
#include "c1/c1_LIRAssembler.hpp"
#include "c1/c1_MacroAssembler.hpp"
#include "gc/g1/c1/g1BarrierSetC1.hpp"
#endif
#define __ masm->
@ -476,8 +481,6 @@ void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorator
}
}
#undef __
void G1BarrierSetAssembler::barrier_stubs_init() {
if (dirty_card_log_enqueue == 0) {
G1BarrierSet* bs = barrier_set_cast<G1BarrierSet>(BarrierSet::barrier_set());
@ -494,3 +497,211 @@ void G1BarrierSetAssembler::barrier_stubs_init() {
assert(satb_log_enqueue_frameless != 0, "postcondition.");
}
}
#ifdef COMPILER1
#undef __
#define __ ce->masm()->
void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) {
G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
// At this point we know that marking is in progress.
// If do_load() is true then we have to emit the
// load of the previous value; otherwise it has already
// been loaded into _pre_val.
__ bind(*stub->entry());
assert(stub->pre_val()->is_register(), "Precondition.");
Register pre_val_reg = stub->pre_val()->as_register();
if (stub->do_load()) {
ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/, false /*unaligned*/);
}
if (__ is_in_wdisp16_range(*stub->continuation())) {
__ br_null(pre_val_reg, /*annul*/false, Assembler::pt, *stub->continuation());
} else {
__ cmp(pre_val_reg, G0);
__ brx(Assembler::equal, false, Assembler::pn, *stub->continuation());
}
__ delayed()->nop();
__ call(bs->pre_barrier_c1_runtime_code_blob()->code_begin());
__ delayed()->mov(pre_val_reg, G4);
__ br(Assembler::always, false, Assembler::pt, *stub->continuation());
__ delayed()->nop();
}
void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) {
G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
__ bind(*stub->entry());
assert(stub->addr()->is_register(), "Precondition.");
assert(stub->new_val()->is_register(), "Precondition.");
Register addr_reg = stub->addr()->as_pointer_register();
Register new_val_reg = stub->new_val()->as_register();
if (__ is_in_wdisp16_range(*stub->continuation())) {
__ br_null(new_val_reg, /*annul*/false, Assembler::pt, *stub->continuation());
} else {
__ cmp(new_val_reg, G0);
__ brx(Assembler::equal, false, Assembler::pn, *stub->continuation());
}
__ delayed()->nop();
__ call(bs->post_barrier_c1_runtime_code_blob()->code_begin());
__ delayed()->mov(addr_reg, G4);
__ br(Assembler::always, false, Assembler::pt, *stub->continuation());
__ delayed()->nop();
}
#undef __
#define __ sasm->
void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) {
__ prologue("g1_pre_barrier", false);
// G4: previous value of memory
Register pre_val = G4;
Register tmp = G1_scratch;
Register tmp2 = G3_scratch;
Label refill, restart;
int satb_q_active_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset());
int satb_q_index_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset());
int satb_q_buf_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset());
// Is marking still active?
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
__ ld(G2_thread, satb_q_active_byte_offset, tmp);
} else {
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
__ ldsb(G2_thread, satb_q_active_byte_offset, tmp);
}
__ cmp_and_br_short(tmp, G0, Assembler::notEqual, Assembler::pt, restart);
__ retl();
__ delayed()->nop();
__ bind(restart);
// Load the index into the SATB buffer. SATBMarkQueue::_index is a
// size_t so ld_ptr is appropriate
__ ld_ptr(G2_thread, satb_q_index_byte_offset, tmp);
// index == 0?
__ cmp_and_brx_short(tmp, G0, Assembler::equal, Assembler::pn, refill);
__ ld_ptr(G2_thread, satb_q_buf_byte_offset, tmp2);
__ sub(tmp, oopSize, tmp);
__ st_ptr(pre_val, tmp2, tmp); // [_buf + index] := <address_of_card>
// Use return-from-leaf
__ retl();
__ delayed()->st_ptr(tmp, G2_thread, satb_q_index_byte_offset);
__ bind(refill);
__ save_live_registers_no_oop_map(true);
__ call_VM_leaf(L7_thread_cache,
CAST_FROM_FN_PTR(address,
SATBMarkQueueSet::handle_zero_index_for_thread),
G2_thread);
__ restore_live_registers(true);
__ br(Assembler::always, /*annul*/false, Assembler::pt, restart);
__ epilogue();
}
void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) {
__ prologue("g1_post_barrier", false);
G1BarrierSet* bs = barrier_set_cast<G1BarrierSet>(BarrierSet::barrier_set());
Register addr = G4;
Register cardtable = G5;
Register tmp = G1_scratch;
Register tmp2 = G3_scratch;
jbyte* byte_map_base = bs->card_table()->byte_map_base();
Label not_already_dirty, restart, refill, young_card;
#ifdef _LP64
__ srlx(addr, CardTable::card_shift, addr);
#else
__ srl(addr, CardTable::card_shift, addr);
#endif
AddressLiteral rs((address)byte_map_base);
__ set(rs, cardtable); // cardtable := <card table base>
__ ldub(addr, cardtable, tmp); // tmp := [addr + cardtable]
__ cmp_and_br_short(tmp, G1CardTable::g1_young_card_val(), Assembler::equal, Assembler::pt, young_card);
__ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad));
__ ldub(addr, cardtable, tmp); // tmp := [addr + cardtable]
assert(G1CardTable::dirty_card_val() == 0, "otherwise check this code");
__ cmp_and_br_short(tmp, G0, Assembler::notEqual, Assembler::pt, not_already_dirty);
__ bind(young_card);
// We didn't take the branch, so we're already dirty: return.
// Use return-from-leaf
__ retl();
__ delayed()->nop();
// Not dirty.
__ bind(not_already_dirty);
// Get cardtable + tmp into a reg by itself
__ add(addr, cardtable, tmp2);
// First, dirty it.
__ stb(G0, tmp2, 0); // [cardPtr] := 0 (i.e., dirty).
Register tmp3 = cardtable;
Register tmp4 = tmp;
// these registers are now dead
addr = cardtable = tmp = noreg;
int dirty_card_q_index_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset());
int dirty_card_q_buf_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset());
__ bind(restart);
// Get the index into the update buffer. DirtyCardQueue::_index is
// a size_t so ld_ptr is appropriate here.
__ ld_ptr(G2_thread, dirty_card_q_index_byte_offset, tmp3);
// index == 0?
__ cmp_and_brx_short(tmp3, G0, Assembler::equal, Assembler::pn, refill);
__ ld_ptr(G2_thread, dirty_card_q_buf_byte_offset, tmp4);
__ sub(tmp3, oopSize, tmp3);
__ st_ptr(tmp2, tmp4, tmp3); // [_buf + index] := <address_of_card>
// Use return-from-leaf
__ retl();
__ delayed()->st_ptr(tmp3, G2_thread, dirty_card_q_index_byte_offset);
__ bind(refill);
__ save_live_registers_no_oop_map(true);
__ call_VM_leaf(L7_thread_cache,
CAST_FROM_FN_PTR(address,
DirtyCardQueueSet::handle_zero_index_for_thread),
G2_thread);
__ restore_live_registers(true);
__ br(Assembler::always, /*annul*/false, Assembler::pt, restart);
__ epilogue();
}
#undef __
#endif // COMPILER1

View File

@ -27,6 +27,12 @@
#include "asm/macroAssembler.hpp"
#include "gc/shared/modRefBarrierSetAssembler.hpp"
#include "utilities/macros.hpp"
class LIR_Assembler;
class StubAssembler;
class G1PreBarrierStub;
class G1PostBarrierStub;
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
@ -40,6 +46,14 @@ protected:
Register val, Address dst, Register tmp);
public:
#ifdef COMPILER1
void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub);
void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
#endif
virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Address src, Register dst, Register tmp);
virtual void barrier_stubs_init();

View File

@ -33,9 +33,6 @@
#include "utilities/align.hpp"
#include "utilities/macros.hpp"
#include "vmreg_x86.inline.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#endif // INCLUDE_ALL_GCS
#define __ ce->masm()->
@ -521,45 +518,4 @@ void ArrayCopyStub::emit_code(LIR_Assembler* ce) {
__ jmp(_continuation);
}
/////////////////////////////////////////////////////////////////////////////
#if INCLUDE_ALL_GCS
void G1PreBarrierStub::emit_code(LIR_Assembler* ce) {
// At this point we know that marking is in progress.
// If do_load() is true then we have to emit the
// load of the previous value; otherwise it has already
// been loaded into _pre_val.
__ bind(_entry);
assert(pre_val()->is_register(), "Precondition.");
Register pre_val_reg = pre_val()->as_register();
if (do_load()) {
ce->mem2reg(addr(), pre_val(), T_OBJECT, patch_code(), info(), false /*wide*/, false /*unaligned*/);
}
__ cmpptr(pre_val_reg, (int32_t) NULL_WORD);
__ jcc(Assembler::equal, _continuation);
ce->store_parameter(pre_val()->as_register(), 0);
__ call(RuntimeAddress(Runtime1::entry_for(Runtime1::g1_pre_barrier_slow_id)));
__ jmp(_continuation);
}
void G1PostBarrierStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
assert(addr()->is_register(), "Precondition.");
assert(new_val()->is_register(), "Precondition.");
Register new_val_reg = new_val()->as_register();
__ cmpptr(new_val_reg, (int32_t) NULL_WORD);
__ jcc(Assembler::equal, _continuation);
ce->store_parameter(addr()->as_pointer_register(), 0);
__ call(RuntimeAddress(Runtime1::entry_for(Runtime1::g1_post_barrier_slow_id)));
__ jmp(_continuation);
}
#endif // INCLUDE_ALL_GCS
/////////////////////////////////////////////////////////////////////////////
#undef __

View File

@ -33,6 +33,7 @@
#include "ci/ciArray.hpp"
#include "ci/ciObjArrayKlass.hpp"
#include "ci/ciTypeArrayKlass.hpp"
#include "gc/shared/c1/barrierSetC1.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "vmreg_x86.inline.hpp"
@ -152,9 +153,27 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index,
int shift, int disp, BasicType type) {
assert(base->is_register(), "must be");
if (index->is_constant()) {
LIR_Const *constant = index->as_constant_ptr();
#ifdef _LP64
jlong c;
if (constant->type() == T_INT) {
c = (jlong(index->as_jint()) << shift) + disp;
} else {
assert(constant->type() == T_LONG, "should be");
c = (index->as_jlong() << shift) + disp;
}
if ((jlong)((jint)c) == c) {
return new LIR_Address(base, (jint)c, type);
} else {
LIR_Opr tmp = new_register(T_LONG);
__ move(index, tmp);
return new LIR_Address(base, tmp, type);
}
#else
return new LIR_Address(base,
((intx)(index->as_constant_ptr()->as_jint()) << shift) + disp,
((intx)(constant->as_jint()) << shift) + disp,
type);
#endif
} else {
return new LIR_Address(base, index, (LIR_Address::Scale)shift, disp, type);
}
@ -162,7 +181,7 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index,
LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr,
BasicType type, bool needs_card_mark) {
BasicType type) {
int offset_in_bytes = arrayOopDesc::base_offset_in_bytes(type);
LIR_Address* addr;
@ -183,16 +202,7 @@ LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_o
LIR_Address::scale(type),
offset_in_bytes, type);
}
if (needs_card_mark) {
// This store will need a precise card mark, so go ahead and
// compute the full adddres instead of computing once for the
// store and again for the card mark.
LIR_Opr tmp = new_pointer_register();
__ leal(LIR_OprFact::address(addr), tmp);
return new LIR_Address(tmp, type);
} else {
return addr;
}
return addr;
}
@ -253,87 +263,17 @@ void LIRGenerator::store_stack_parameter (LIR_Opr item, ByteSize offset_from_sp)
__ store(item, new LIR_Address(FrameMap::rsp_opr, in_bytes(offset_from_sp), type));
}
void LIRGenerator::array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, ciMethod* profiled_method, int profiled_bci) {
LIR_Opr tmp1 = new_register(objectType);
LIR_Opr tmp2 = new_register(objectType);
LIR_Opr tmp3 = new_register(objectType);
__ store_check(value, array, tmp1, tmp2, tmp3, store_check_info, profiled_method, profiled_bci);
}
//----------------------------------------------------------------------
// visitor functions
//----------------------------------------------------------------------
void LIRGenerator::do_StoreIndexed(StoreIndexed* x) {
assert(x->is_pinned(),"");
bool needs_range_check = x->compute_needs_range_check();
bool use_length = x->length() != NULL;
bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT;
bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL ||
!get_jobject_constant(x->value())->is_null_object() ||
x->should_profile());
LIRItem array(x->array(), this);
LIRItem index(x->index(), this);
LIRItem value(x->value(), this);
LIRItem length(this);
array.load_item();
index.load_nonconstant();
if (use_length && needs_range_check) {
length.set_instruction(x->length());
length.load_item();
}
if (needs_store_check || x->check_boolean()) {
value.load_item();
} else {
value.load_for_store(x->elt_type());
}
set_no_result(x);
// the CodeEmitInfo must be duplicated for each different
// LIR-instruction because spilling can occur anywhere between two
// instructions and so the debug information must be different
CodeEmitInfo* range_check_info = state_for(x);
CodeEmitInfo* null_check_info = NULL;
if (x->needs_null_check()) {
null_check_info = new CodeEmitInfo(range_check_info);
}
// emit array address setup early so it schedules better
LIR_Address* array_addr = emit_array_address(array.result(), index.result(), x->elt_type(), obj_store);
if (GenerateRangeChecks && needs_range_check) {
if (use_length) {
__ cmp(lir_cond_belowEqual, length.result(), index.result());
__ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result()));
} else {
array_range_check(array.result(), index.result(), null_check_info, range_check_info);
// range_check also does the null check
null_check_info = NULL;
}
}
if (GenerateArrayStoreCheck && needs_store_check) {
LIR_Opr tmp1 = new_register(objectType);
LIR_Opr tmp2 = new_register(objectType);
LIR_Opr tmp3 = new_register(objectType);
CodeEmitInfo* store_check_info = new CodeEmitInfo(range_check_info);
__ store_check(value.result(), array.result(), tmp1, tmp2, tmp3, store_check_info, x->profiled_method(), x->profiled_bci());
}
if (obj_store) {
// Needs GC write barriers.
pre_barrier(LIR_OprFact::address(array_addr), LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
__ move(value.result(), array_addr, null_check_info);
// Seems to be a precise
post_barrier(LIR_OprFact::address(array_addr), value.result());
} else {
LIR_Opr result = maybe_mask_boolean(x, array.result(), value.result(), null_check_info);
__ move(result, array_addr, null_check_info);
}
}
void LIRGenerator::do_MonitorEnter(MonitorEnter* x) {
assert(x->is_pinned(),"");
LIRItem obj(x->obj(), this);
@ -715,93 +655,48 @@ void LIRGenerator::do_CompareOp(CompareOp* x) {
}
}
void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) {
assert(x->number_of_arguments() == 4, "wrong type");
LIRItem obj (x->argument_at(0), this); // object
LIRItem offset(x->argument_at(1), this); // offset of field
LIRItem cmp (x->argument_at(2), this); // value to compare with field
LIRItem val (x->argument_at(3), this); // replace field with val if matches cmp
assert(obj.type()->tag() == objectTag, "invalid type");
// In 64bit the type can be long, sparc doesn't have this assert
// assert(offset.type()->tag() == intTag, "invalid type");
assert(cmp.type()->tag() == type->tag(), "invalid type");
assert(val.type()->tag() == type->tag(), "invalid type");
// get address of field
obj.load_item();
offset.load_nonconstant();
LIR_Opr addr = new_pointer_register();
LIR_Address* a;
if(offset.result()->is_constant()) {
#ifdef _LP64
jlong c = offset.result()->as_jlong();
if ((jlong)((jint)c) == c) {
a = new LIR_Address(obj.result(),
(jint)c,
as_BasicType(type));
} else {
LIR_Opr tmp = new_register(T_LONG);
__ move(offset.result(), tmp);
a = new LIR_Address(obj.result(),
tmp,
as_BasicType(type));
}
#else
a = new LIR_Address(obj.result(),
offset.result()->as_jint(),
as_BasicType(type));
#endif
} else {
a = new LIR_Address(obj.result(),
offset.result(),
0,
as_BasicType(type));
}
__ leal(LIR_OprFact::address(a), addr);
if (type == objectType) { // Write-barrier needed for Object fields.
// Do the pre-write barrier, if any.
pre_barrier(addr, LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
}
if (type == objectType) {
cmp.load_item_force(FrameMap::rax_oop_opr);
val.load_item();
} else if (type == intType) {
cmp.load_item_force(FrameMap::rax_opr);
val.load_item();
} else if (type == longType) {
cmp.load_item_force(FrameMap::long0_opr);
val.load_item_force(FrameMap::long1_opr);
} else {
ShouldNotReachHere();
}
LIR_Opr LIRGenerator::atomic_cmpxchg(BasicType type, LIR_Opr addr, LIRItem& cmp_value, LIRItem& new_value) {
LIR_Opr ill = LIR_OprFact::illegalOpr; // for convenience
if (type == objectType)
__ cas_obj(addr, cmp.result(), val.result(), ill, ill);
else if (type == intType)
__ cas_int(addr, cmp.result(), val.result(), ill, ill);
else if (type == longType)
__ cas_long(addr, cmp.result(), val.result(), ill, ill);
else {
ShouldNotReachHere();
if (type == T_OBJECT || type == T_ARRAY) {
cmp_value.load_item_force(FrameMap::rax_oop_opr);
new_value.load_item();
__ cas_obj(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), ill, ill);
} else if (type == T_INT) {
cmp_value.load_item_force(FrameMap::rax_opr);
new_value.load_item();
__ cas_int(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), ill, ill);
} else if (type == T_LONG) {
cmp_value.load_item_force(FrameMap::long0_opr);
new_value.load_item_force(FrameMap::long1_opr);
__ cas_long(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), ill, ill);
} else {
Unimplemented();
}
// generate conditional move of boolean result
LIR_Opr result = rlock_result(x);
LIR_Opr result = new_register(T_INT);
__ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0),
result, as_BasicType(type));
if (type == objectType) { // Write-barrier needed for Object fields.
// Seems to be precise
post_barrier(addr, val.result());
}
result, type);
return result;
}
LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) {
bool is_oop = type == T_OBJECT || type == T_ARRAY;
LIR_Opr result = new_register(type);
value.load_item();
// Because we want a 2-arg form of xchg and xadd
__ move(value.result(), result);
assert(type == T_INT || is_oop LP64_ONLY( || type == T_LONG ), "unexpected type");
__ xchg(addr, result, result, LIR_OprFact::illegalOpr);
return result;
}
LIR_Opr LIRGenerator::atomic_add(BasicType type, LIR_Opr addr, LIRItem& value) {
LIR_Opr result = new_register(type);
value.load_item();
// Because we want a 2-arg form of xchg and xadd
__ move(value.result(), result);
assert(type == T_INT LP64_ONLY( || type == T_LONG ), "unexpected type");
__ xadd(addr, result, result, LIR_OprFact::illegalOpr);
return result;
}
void LIRGenerator::do_FmaIntrinsic(Intrinsic* x) {
@ -1570,8 +1465,6 @@ void LIRGenerator::volatile_field_store(LIR_Opr value, LIR_Address* address,
}
}
void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result,
CodeEmitInfo* info) {
if (address->type() == T_LONG) {
@ -1593,100 +1486,3 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result,
__ load(address, result, info);
}
}
void LIRGenerator::get_Object_unsafe(LIR_Opr dst, LIR_Opr src, LIR_Opr offset,
BasicType type, bool is_volatile) {
if (is_volatile && type == T_LONG) {
LIR_Address* addr = new LIR_Address(src, offset, T_DOUBLE);
LIR_Opr tmp = new_register(T_DOUBLE);
__ load(addr, tmp);
LIR_Opr spill = new_register(T_LONG);
set_vreg_flag(spill, must_start_in_memory);
__ move(tmp, spill);
__ move(spill, dst);
} else {
LIR_Address* addr = new LIR_Address(src, offset, type);
__ load(addr, dst);
}
}
void LIRGenerator::put_Object_unsafe(LIR_Opr src, LIR_Opr offset, LIR_Opr data,
BasicType type, bool is_volatile) {
if (is_volatile && type == T_LONG) {
LIR_Address* addr = new LIR_Address(src, offset, T_DOUBLE);
LIR_Opr tmp = new_register(T_DOUBLE);
LIR_Opr spill = new_register(T_DOUBLE);
set_vreg_flag(spill, must_start_in_memory);
__ move(data, spill);
__ move(spill, tmp);
__ move(tmp, addr);
} else {
LIR_Address* addr = new LIR_Address(src, offset, type);
bool is_obj = (type == T_ARRAY || type == T_OBJECT);
if (is_obj) {
// Do the pre-write barrier, if any.
pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
__ move(data, addr);
assert(src->is_register(), "must be register");
// Seems to be a precise address
post_barrier(LIR_OprFact::address(addr), data);
} else {
__ move(data, addr);
}
}
}
void LIRGenerator::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {
BasicType type = x->basic_type();
LIRItem src(x->object(), this);
LIRItem off(x->offset(), this);
LIRItem value(x->value(), this);
src.load_item();
value.load_item();
off.load_nonconstant();
LIR_Opr dst = rlock_result(x, type);
LIR_Opr data = value.result();
bool is_obj = (type == T_ARRAY || type == T_OBJECT);
LIR_Opr offset = off.result();
assert (type == T_INT || (!x->is_add() && is_obj) LP64_ONLY( || type == T_LONG ), "unexpected type");
LIR_Address* addr;
if (offset->is_constant()) {
#ifdef _LP64
jlong c = offset->as_jlong();
if ((jlong)((jint)c) == c) {
addr = new LIR_Address(src.result(), (jint)c, type);
} else {
LIR_Opr tmp = new_register(T_LONG);
__ move(offset, tmp);
addr = new LIR_Address(src.result(), tmp, type);
}
#else
addr = new LIR_Address(src.result(), offset->as_jint(), type);
#endif
} else {
addr = new LIR_Address(src.result(), offset, type);
}
// Because we want a 2-arg form of xchg and xadd
__ move(data, dst);
if (x->is_add()) {
__ xadd(LIR_OprFact::address(addr), dst, dst, LIR_OprFact::illegalOpr);
} else {
if (is_obj) {
// Do the pre-write barrier, if any.
pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load */, false /* patch */, NULL);
}
__ xchg(LIR_OprFact::address(addr), dst, dst, LIR_OprFact::illegalOpr);
if (is_obj) {
// Seems to be a precise address
post_barrier(LIR_OprFact::address(addr), data);
}
}
}

View File

@ -356,6 +356,15 @@ void C1_MacroAssembler::verified_entry() {
verify_FPU(0, "method_entry");
}
void C1_MacroAssembler::load_parameter(int offset_in_words, Register reg) {
// rbp, + 0: link
// + 1: return address
// + 2: argument with offset 0
// + 3: argument with offset 1
// + 4: ...
movptr(reg, Address(rbp, (offset_in_words + 2) * BytesPerWord));
}
#ifndef PRODUCT

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2018, 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
@ -121,4 +121,9 @@
// This platform only uses signal-based null checks. The Label is not needed.
void null_check(Register r, Label *Lnull = NULL) { MacroAssembler::null_check(r); }
void load_parameter(int offset_in_words, Register reg);
void save_live_registers_no_oop_map(int num_rt_args, bool save_fpu_registers);
void restore_live_registers(bool restore_fpu_registers);
#endif // CPU_X86_VM_C1_MACROASSEMBLER_X86_HPP

View File

@ -41,12 +41,6 @@
#include "runtime/vframeArray.hpp"
#include "utilities/macros.hpp"
#include "vmreg_x86.inline.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CardTable.hpp"
#include "gc/g1/g1ThreadLocalData.hpp"
#endif
// Implementation of StubAssembler
@ -212,31 +206,32 @@ class StubFrame: public StackObj {
~StubFrame();
};
void StubAssembler::prologue(const char* name, bool must_gc_arguments) {
set_info(name, must_gc_arguments);
enter();
}
void StubAssembler::epilogue() {
leave();
ret(0);
}
#define __ _sasm->
StubFrame::StubFrame(StubAssembler* sasm, const char* name, bool must_gc_arguments) {
_sasm = sasm;
__ set_info(name, must_gc_arguments);
__ enter();
__ prologue(name, must_gc_arguments);
}
// load parameters that were stored with LIR_Assembler::store_parameter
// Note: offsets for store_parameter and load_argument must match
void StubFrame::load_argument(int offset_in_words, Register reg) {
// rbp, + 0: link
// + 1: return address
// + 2: argument with offset 0
// + 3: argument with offset 1
// + 4: ...
__ movptr(reg, Address(rbp, (offset_in_words + 2) * BytesPerWord));
__ load_parameter(offset_in_words, reg);
}
StubFrame::~StubFrame() {
__ leave();
__ ret(0);
__ epilogue();
}
#undef __
@ -244,8 +239,6 @@ StubFrame::~StubFrame() {
// Implementation of Runtime1
#define __ sasm->
const int float_regs_as_doubles_size_in_slots = pd_nof_fpu_regs_frame_map * 2;
const int xmm_regs_as_doubles_size_in_slots = FrameMap::nof_xmm_regs * 2;
@ -310,8 +303,6 @@ enum reg_save_layout {
reg_save_frame_size // As noted: neglects any parameters to runtime // 504
};
// Save off registers which might be killed by calls into the runtime.
// Tries to smart of about FP registers. In particular we separate
// saving and describing the FPU registers for deoptimization since we
@ -418,8 +409,9 @@ static OopMap* generate_oop_map(StubAssembler* sasm, int num_rt_args,
return map;
}
static OopMap* save_live_registers(StubAssembler* sasm, int num_rt_args,
bool save_fpu_registers = true) {
#define __ this->
void C1_MacroAssembler::save_live_registers_no_oop_map(int num_rt_args, bool save_fpu_registers) {
__ block_comment("save_live_registers");
__ pusha(); // integer registers
@ -493,12 +485,12 @@ static OopMap* save_live_registers(StubAssembler* sasm, int num_rt_args,
// FPU stack must be empty now
__ verify_FPU(0, "save_live_registers");
return generate_oop_map(sasm, num_rt_args, save_fpu_registers);
}
#undef __
#define __ sasm->
static void restore_fpu(StubAssembler* sasm, bool restore_fpu_registers = true) {
static void restore_fpu(C1_MacroAssembler* sasm, bool restore_fpu_registers) {
if (restore_fpu_registers) {
if (UseSSE >= 2) {
// restore XMM registers
@ -549,14 +541,28 @@ static void restore_fpu(StubAssembler* sasm, bool restore_fpu_registers = true)
__ addptr(rsp, extra_space_offset * VMRegImpl::stack_slot_size);
}
#undef __
#define __ this->
static void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registers = true) {
void C1_MacroAssembler::restore_live_registers(bool restore_fpu_registers) {
__ block_comment("restore_live_registers");
restore_fpu(sasm, restore_fpu_registers);
restore_fpu(this, restore_fpu_registers);
__ popa();
}
#undef __
#define __ sasm->
static OopMap* save_live_registers(StubAssembler* sasm, int num_rt_args,
bool save_fpu_registers = true) {
sasm->save_live_registers_no_oop_map(num_rt_args, save_fpu_registers);
return generate_oop_map(sasm, num_rt_args, save_fpu_registers);
}
static void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registers = true) {
sasm->restore_live_registers(restore_fpu_registers);
}
static void restore_live_registers_except_rax(StubAssembler* sasm, bool restore_fpu_registers = true) {
__ block_comment("restore_live_registers_except_rax");
@ -1557,159 +1563,6 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
}
break;
#if INCLUDE_ALL_GCS
case g1_pre_barrier_slow_id:
{
StubFrame f(sasm, "g1_pre_barrier", dont_gc_arguments);
// arg0 : previous value of memory
BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ movptr(rax, (int)id);
__ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), rax);
__ should_not_reach_here();
break;
}
__ push(rax);
__ push(rdx);
const Register pre_val = rax;
const Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread);
const Register tmp = rdx;
NOT_LP64(__ get_thread(thread);)
Address queue_active(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
Address queue_index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
Label done;
Label runtime;
// Is marking still active?
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
__ cmpl(queue_active, 0);
} else {
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
__ cmpb(queue_active, 0);
}
__ jcc(Assembler::equal, done);
// Can we store original value in the thread's buffer?
__ movptr(tmp, queue_index);
__ testptr(tmp, tmp);
__ jcc(Assembler::zero, runtime);
__ subptr(tmp, wordSize);
__ movptr(queue_index, tmp);
__ addptr(tmp, buffer);
// prev_val (rax)
f.load_argument(0, pre_val);
__ movptr(Address(tmp, 0), pre_val);
__ jmp(done);
__ bind(runtime);
save_live_registers(sasm, 3);
// load the pre-value
f.load_argument(0, rcx);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), rcx, thread);
restore_live_registers(sasm);
__ bind(done);
__ pop(rdx);
__ pop(rax);
}
break;
case g1_post_barrier_slow_id:
{
StubFrame f(sasm, "g1_post_barrier", dont_gc_arguments);
BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ movptr(rax, (int)id);
__ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), rax);
__ should_not_reach_here();
break;
}
// arg0: store_address
Address store_addr(rbp, 2*BytesPerWord);
Label done;
Label enqueued;
Label runtime;
// At this point we know new_value is non-NULL and the new_value crosses regions.
// Must check to see if card is already dirty
const Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread);
Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
__ push(rax);
__ push(rcx);
const Register cardtable = rax;
const Register card_addr = rcx;
f.load_argument(0, card_addr);
__ shrptr(card_addr, CardTable::card_shift);
// Do not use ExternalAddress to load 'byte_map_base', since 'byte_map_base' is NOT
// a valid address and therefore is not properly handled by the relocation code.
__ movptr(cardtable, ci_card_table_address_as<intptr_t>());
__ addptr(card_addr, cardtable);
NOT_LP64(__ get_thread(thread);)
__ cmpb(Address(card_addr, 0), (int)G1CardTable::g1_young_card_val());
__ jcc(Assembler::equal, done);
__ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad));
__ cmpb(Address(card_addr, 0), (int)CardTable::dirty_card_val());
__ jcc(Assembler::equal, done);
// storing region crossing non-NULL, card is clean.
// dirty card and log.
__ movb(Address(card_addr, 0), (int)CardTable::dirty_card_val());
const Register tmp = rdx;
__ push(rdx);
__ movptr(tmp, queue_index);
__ testptr(tmp, tmp);
__ jcc(Assembler::zero, runtime);
__ subptr(tmp, wordSize);
__ movptr(queue_index, tmp);
__ addptr(tmp, buffer);
__ movptr(Address(tmp, 0), card_addr);
__ jmp(enqueued);
__ bind(runtime);
save_live_registers(sasm, 3);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, thread);
restore_live_registers(sasm);
__ bind(enqueued);
__ pop(rdx);
__ bind(done);
__ pop(rcx);
__ pop(rax);
}
break;
#endif // INCLUDE_ALL_GCS
case predicate_failed_trap_id:
{
StubFrame f(sasm, "predicate_failed_trap", dont_gc_arguments);

View File

@ -32,6 +32,11 @@
#include "interpreter/interp_masm.hpp"
#include "runtime/sharedRuntime.hpp"
#include "utilities/macros.hpp"
#ifdef COMPILER1
#include "c1/c1_LIRAssembler.hpp"
#include "c1/c1_MacroAssembler.hpp"
#include "gc/g1/c1/g1BarrierSetC1.hpp"
#endif
#define __ masm->
@ -399,3 +404,193 @@ void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet deco
}
NOT_LP64(imasm->restore_bcp());
}
#ifdef COMPILER1
#undef __
#define __ ce->masm()->
void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) {
G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
// At this point we know that marking is in progress.
// If do_load() is true then we have to emit the
// load of the previous value; otherwise it has already
// been loaded into _pre_val.
__ bind(*stub->entry());
assert(stub->pre_val()->is_register(), "Precondition.");
Register pre_val_reg = stub->pre_val()->as_register();
if (stub->do_load()) {
ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/, false /*unaligned*/);
}
__ cmpptr(pre_val_reg, (int32_t)NULL_WORD);
__ jcc(Assembler::equal, *stub->continuation());
ce->store_parameter(stub->pre_val()->as_register(), 0);
__ call(RuntimeAddress(bs->pre_barrier_c1_runtime_code_blob()->code_begin()));
__ jmp(*stub->continuation());
}
void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) {
G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();
__ bind(*stub->entry());
assert(stub->addr()->is_register(), "Precondition.");
assert(stub->new_val()->is_register(), "Precondition.");
Register new_val_reg = stub->new_val()->as_register();
__ cmpptr(new_val_reg, (int32_t) NULL_WORD);
__ jcc(Assembler::equal, *stub->continuation());
ce->store_parameter(stub->addr()->as_pointer_register(), 0);
__ call(RuntimeAddress(bs->post_barrier_c1_runtime_code_blob()->code_begin()));
__ jmp(*stub->continuation());
}
#undef __
#define __ sasm->
void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) {
__ prologue("g1_pre_barrier", false);
// arg0 : previous value of memory
__ push(rax);
__ push(rdx);
const Register pre_val = rax;
const Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread);
const Register tmp = rdx;
NOT_LP64(__ get_thread(thread);)
Address queue_active(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
Address queue_index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
Label done;
Label runtime;
// Is marking still active?
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
__ cmpl(queue_active, 0);
} else {
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
__ cmpb(queue_active, 0);
}
__ jcc(Assembler::equal, done);
// Can we store original value in the thread's buffer?
__ movptr(tmp, queue_index);
__ testptr(tmp, tmp);
__ jcc(Assembler::zero, runtime);
__ subptr(tmp, wordSize);
__ movptr(queue_index, tmp);
__ addptr(tmp, buffer);
// prev_val (rax)
__ load_parameter(0, pre_val);
__ movptr(Address(tmp, 0), pre_val);
__ jmp(done);
__ bind(runtime);
__ save_live_registers_no_oop_map(3, true);
// load the pre-value
__ load_parameter(0, rcx);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), rcx, thread);
__ restore_live_registers(true);
__ bind(done);
__ pop(rdx);
__ pop(rax);
__ epilogue();
}
void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) {
__ prologue("g1_post_barrier", false);
// arg0: store_address
Address store_addr(rbp, 2*BytesPerWord);
CardTableBarrierSet* ct =
barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
assert(sizeof(*ct->card_table()->byte_map_base()) == sizeof(jbyte), "adjust this code");
Label done;
Label enqueued;
Label runtime;
// At this point we know new_value is non-NULL and the new_value crosses regions.
// Must check to see if card is already dirty
const Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread);
Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
__ push(rax);
__ push(rcx);
const Register cardtable = rax;
const Register card_addr = rcx;
__ load_parameter(0, card_addr);
__ shrptr(card_addr, CardTable::card_shift);
// Do not use ExternalAddress to load 'byte_map_base', since 'byte_map_base' is NOT
// a valid address and therefore is not properly handled by the relocation code.
__ movptr(cardtable, (intptr_t)ct->card_table()->byte_map_base());
__ addptr(card_addr, cardtable);
NOT_LP64(__ get_thread(thread);)
__ cmpb(Address(card_addr, 0), (int)G1CardTable::g1_young_card_val());
__ jcc(Assembler::equal, done);
__ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad));
__ cmpb(Address(card_addr, 0), (int)CardTable::dirty_card_val());
__ jcc(Assembler::equal, done);
// storing region crossing non-NULL, card is clean.
// dirty card and log.
__ movb(Address(card_addr, 0), (int)CardTable::dirty_card_val());
const Register tmp = rdx;
__ push(rdx);
__ movptr(tmp, queue_index);
__ testptr(tmp, tmp);
__ jcc(Assembler::zero, runtime);
__ subptr(tmp, wordSize);
__ movptr(queue_index, tmp);
__ addptr(tmp, buffer);
__ movptr(Address(tmp, 0), card_addr);
__ jmp(enqueued);
__ bind(runtime);
__ save_live_registers_no_oop_map(3, true);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, thread);
__ restore_live_registers(true);
__ bind(enqueued);
__ pop(rdx);
__ bind(done);
__ pop(rcx);
__ pop(rax);
__ epilogue();
}
#undef __
#endif // COMPILER1

View File

@ -28,6 +28,11 @@
#include "asm/macroAssembler.hpp"
#include "gc/shared/modRefBarrierSetAssembler.hpp"
class LIR_Assembler;
class StubAssembler;
class G1PreBarrierStub;
class G1PostBarrierStub;
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count);
@ -52,6 +57,12 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
Address dst, Register val, Register tmp1, Register tmp2);
public:
void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub);
void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm);
void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm);
virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register dst, Address src, Register tmp1, Register tmp_thread);
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2018, 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
@ -533,92 +533,4 @@ class ArrayCopyStub: public CodeStub {
#endif // PRODUCT
};
//////////////////////////////////////////////////////////////////////////////////////////
#if INCLUDE_ALL_GCS
// Code stubs for Garbage-First barriers.
class G1PreBarrierStub: public CodeStub {
private:
bool _do_load;
LIR_Opr _addr;
LIR_Opr _pre_val;
LIR_PatchCode _patch_code;
CodeEmitInfo* _info;
public:
// Version that _does_ generate a load of the previous value from addr.
// addr (the address of the field to be read) must be a LIR_Address
// pre_val (a temporary register) must be a register;
G1PreBarrierStub(LIR_Opr addr, LIR_Opr pre_val, LIR_PatchCode patch_code, CodeEmitInfo* info) :
_addr(addr), _pre_val(pre_val), _do_load(true),
_patch_code(patch_code), _info(info)
{
assert(_pre_val->is_register(), "should be temporary register");
assert(_addr->is_address(), "should be the address of the field");
}
// Version that _does not_ generate load of the previous value; the
// previous value is assumed to have already been loaded into pre_val.
G1PreBarrierStub(LIR_Opr pre_val) :
_addr(LIR_OprFact::illegalOpr), _pre_val(pre_val), _do_load(false),
_patch_code(lir_patch_none), _info(NULL)
{
assert(_pre_val->is_register(), "should be a register");
}
LIR_Opr addr() const { return _addr; }
LIR_Opr pre_val() const { return _pre_val; }
LIR_PatchCode patch_code() const { return _patch_code; }
CodeEmitInfo* info() const { return _info; }
bool do_load() const { return _do_load; }
virtual void emit_code(LIR_Assembler* e);
virtual void visit(LIR_OpVisitState* visitor) {
if (_do_load) {
// don't pass in the code emit info since it's processed in the fast
// path
if (_info != NULL)
visitor->do_slow_case(_info);
else
visitor->do_slow_case();
visitor->do_input(_addr);
visitor->do_temp(_pre_val);
} else {
visitor->do_slow_case();
visitor->do_input(_pre_val);
}
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("G1PreBarrierStub"); }
#endif // PRODUCT
};
class G1PostBarrierStub: public CodeStub {
private:
LIR_Opr _addr;
LIR_Opr _new_val;
public:
// addr (the address of the object head) and new_val must be registers.
G1PostBarrierStub(LIR_Opr addr, LIR_Opr new_val): _addr(addr), _new_val(new_val) { }
LIR_Opr addr() const { return _addr; }
LIR_Opr new_val() const { return _new_val; }
virtual void emit_code(LIR_Assembler* e);
virtual void visit(LIR_OpVisitState* visitor) {
// don't pass in the code emit info since it's processed in the fast path
visitor->do_slow_case();
visitor->do_input(_addr);
visitor->do_input(_new_val);
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("G1PostBarrierStub"); }
#endif // PRODUCT
};
#endif // INCLUDE_ALL_GCS
//////////////////////////////////////////////////////////////////////////////////////////
#endif // SHARE_VM_C1_C1_CODESTUBS_HPP

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2018, 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.
*
*/
#ifndef SHARE_VM_C1_C1_DECORATORS_HPP
#define SHARE_VM_C1_C1_DECORATORS_HPP
#include "oops/accessDecorators.hpp"
#include "utilities/globalDefinitions.hpp"
// Use the C1_NEEDS_PATCHING decorator for situations when the access is using
// an offset that is not yet known and will require patching
const DecoratorSet C1_NEEDS_PATCHING = DECORATOR_LAST << 1;
// Use the C1_MASK_BOOLEAN decorator for boolean accesses where the value
// needs to be masked.
const DecoratorSet C1_MASK_BOOLEAN = DECORATOR_LAST << 2;
// The C1_WRITE_ACCESS decorator is used to mark writing accesses.
const DecoratorSet C1_WRITE_ACCESS = DECORATOR_LAST << 3;
// The C1_READ_ACCESS decorator is used to mark reading accesses.
const DecoratorSet C1_READ_ACCESS = DECORATOR_LAST << 4;
#endif // SHARE_VM_C1_C1_DECORATORS_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2018, 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
@ -260,6 +260,8 @@ class LIR_Assembler: public CompilationResourceObj {
#include CPU_HEADER(c1_LIRAssembler)
public:
static int call_stub_size() {
if (UseAOT) {
return _call_stub_size + _call_aot_stub_size;

View File

@ -34,19 +34,14 @@
#include "ci/ciInstance.hpp"
#include "ci/ciObjArray.hpp"
#include "ci/ciUtilities.hpp"
#include "gc/shared/cardTable.hpp"
#include "gc/shared/cardTableBarrierSet.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/barrierSet.hpp"
#include "gc/shared/c1/barrierSetC1.hpp"
#include "runtime/arguments.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/vm_version.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1ThreadLocalData.hpp"
#include "gc/g1/heapRegion.hpp"
#endif // INCLUDE_ALL_GCS
#ifdef TRACE_HAVE_INTRINSICS
#include "trace/traceMacros.hpp"
#endif
@ -313,11 +308,6 @@ jlong LIRItem::get_jlong_constant() const {
//--------------------------------------------------------------
void LIRGenerator::init() {
_bs = BarrierSet::barrier_set();
}
void LIRGenerator::block_do_prolog(BlockBegin* block) {
#ifndef PRODUCT
if (PrintIRWithLIR) {
@ -1245,19 +1235,9 @@ void LIRGenerator::do_Reference_get(Intrinsic* x) {
info = state_for(x);
}
LIR_Address* referent_field_adr =
new LIR_Address(reference.result(), referent_offset, T_OBJECT);
LIR_Opr result = rlock_result(x);
__ load(referent_field_adr, result, info);
// Register the value in the referent field with the pre-barrier
pre_barrier(LIR_OprFact::illegalOpr /* addr_opr */,
result /* pre_val */,
false /* do_load */,
false /* patch */,
NULL /* info */);
LIR_Opr result = rlock_result(x, T_OBJECT);
access_load_at(IN_HEAP | ON_WEAK_OOP_REF, T_OBJECT,
reference, LIR_OprFact::intConst(referent_offset), result);
}
// Example: clazz.isInstance(object)
@ -1454,222 +1434,27 @@ LIR_Opr LIRGenerator::load_constant(LIR_Const* c) {
return result;
}
// Various barriers
void LIRGenerator::pre_barrier(LIR_Opr addr_opr, LIR_Opr pre_val,
bool do_load, bool patch, CodeEmitInfo* info) {
// Do the pre-write barrier, if any.
switch (_bs->kind()) {
#if INCLUDE_ALL_GCS
case BarrierSet::G1BarrierSet:
G1BarrierSet_pre_barrier(addr_opr, pre_val, do_load, patch, info);
break;
#endif // INCLUDE_ALL_GCS
case BarrierSet::CardTableBarrierSet:
// No pre barriers
break;
default :
ShouldNotReachHere();
}
}
void LIRGenerator::post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val) {
switch (_bs->kind()) {
#if INCLUDE_ALL_GCS
case BarrierSet::G1BarrierSet:
G1BarrierSet_post_barrier(addr, new_val);
break;
#endif // INCLUDE_ALL_GCS
case BarrierSet::CardTableBarrierSet:
CardTableBarrierSet_post_barrier(addr, new_val);
break;
default :
ShouldNotReachHere();
}
}
////////////////////////////////////////////////////////////////////////
#if INCLUDE_ALL_GCS
void LIRGenerator::G1BarrierSet_pre_barrier(LIR_Opr addr_opr, LIR_Opr pre_val,
bool do_load, bool patch, CodeEmitInfo* info) {
// First we test whether marking is in progress.
BasicType flag_type;
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
flag_type = T_INT;
} else {
guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1,
"Assumption");
// Use unsigned type T_BOOLEAN here rather than signed T_BYTE since some platforms, eg. ARM,
// need to use unsigned instructions to use the large offset to load the satb_mark_queue.
flag_type = T_BOOLEAN;
}
LIR_Opr thrd = getThreadPointer();
LIR_Address* mark_active_flag_addr =
new LIR_Address(thrd, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), flag_type);
// Read the marking-in-progress flag.
LIR_Opr flag_val = new_register(T_INT);
__ load(mark_active_flag_addr, flag_val);
__ cmp(lir_cond_notEqual, flag_val, LIR_OprFact::intConst(0));
LIR_PatchCode pre_val_patch_code = lir_patch_none;
CodeStub* slow;
if (do_load) {
assert(pre_val == LIR_OprFact::illegalOpr, "sanity");
assert(addr_opr != LIR_OprFact::illegalOpr, "sanity");
if (patch)
pre_val_patch_code = lir_patch_normal;
pre_val = new_register(T_OBJECT);
if (!addr_opr->is_address()) {
assert(addr_opr->is_register(), "must be");
addr_opr = LIR_OprFact::address(new LIR_Address(addr_opr, T_OBJECT));
}
slow = new G1PreBarrierStub(addr_opr, pre_val, pre_val_patch_code, info);
} else {
assert(addr_opr == LIR_OprFact::illegalOpr, "sanity");
assert(pre_val->is_register(), "must be");
assert(pre_val->type() == T_OBJECT, "must be an object");
assert(info == NULL, "sanity");
slow = new G1PreBarrierStub(pre_val);
}
__ branch(lir_cond_notEqual, T_INT, slow);
__ branch_destination(slow->continuation());
}
void LIRGenerator::G1BarrierSet_post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val) {
// If the "new_val" is a constant NULL, no barrier is necessary.
if (new_val->is_constant() &&
new_val->as_constant_ptr()->as_jobject() == NULL) return;
if (!new_val->is_register()) {
LIR_Opr new_val_reg = new_register(T_OBJECT);
if (new_val->is_constant()) {
__ move(new_val, new_val_reg);
} else {
__ leal(new_val, new_val_reg);
}
new_val = new_val_reg;
}
assert(new_val->is_register(), "must be a register at this point");
if (addr->is_address()) {
LIR_Address* address = addr->as_address_ptr();
LIR_Opr ptr = new_pointer_register();
if (!address->index()->is_valid() && address->disp() == 0) {
__ move(address->base(), ptr);
} else {
assert(address->disp() != max_jint, "lea doesn't support patched addresses!");
__ leal(addr, ptr);
}
addr = ptr;
}
assert(addr->is_register(), "must be a register at this point");
LIR_Opr xor_res = new_pointer_register();
LIR_Opr xor_shift_res = new_pointer_register();
if (TwoOperandLIRForm ) {
__ move(addr, xor_res);
__ logical_xor(xor_res, new_val, xor_res);
__ move(xor_res, xor_shift_res);
__ unsigned_shift_right(xor_shift_res,
LIR_OprFact::intConst(HeapRegion::LogOfHRGrainBytes),
xor_shift_res,
LIR_OprDesc::illegalOpr());
} else {
__ logical_xor(addr, new_val, xor_res);
__ unsigned_shift_right(xor_res,
LIR_OprFact::intConst(HeapRegion::LogOfHRGrainBytes),
xor_shift_res,
LIR_OprDesc::illegalOpr());
}
if (!new_val->is_register()) {
LIR_Opr new_val_reg = new_register(T_OBJECT);
__ leal(new_val, new_val_reg);
new_val = new_val_reg;
}
assert(new_val->is_register(), "must be a register at this point");
__ cmp(lir_cond_notEqual, xor_shift_res, LIR_OprFact::intptrConst(NULL_WORD));
CodeStub* slow = new G1PostBarrierStub(addr, new_val);
__ branch(lir_cond_notEqual, LP64_ONLY(T_LONG) NOT_LP64(T_INT), slow);
__ branch_destination(slow->continuation());
}
#endif // INCLUDE_ALL_GCS
////////////////////////////////////////////////////////////////////////
void LIRGenerator::CardTableBarrierSet_post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val) {
LIR_Const* card_table_base = new LIR_Const(ci_card_table_address());
if (addr->is_address()) {
LIR_Address* address = addr->as_address_ptr();
// ptr cannot be an object because we use this barrier for array card marks
// and addr can point in the middle of an array.
LIR_Opr ptr = new_pointer_register();
if (!address->index()->is_valid() && address->disp() == 0) {
__ move(address->base(), ptr);
} else {
assert(address->disp() != max_jint, "lea doesn't support patched addresses!");
__ leal(addr, ptr);
}
addr = ptr;
}
assert(addr->is_register(), "must be a register at this point");
#ifdef CARDTABLEBARRIERSET_POST_BARRIER_HELPER
CardTableBarrierSet_post_barrier_helper(addr, card_table_base);
#else
LIR_Opr tmp = new_pointer_register();
if (TwoOperandLIRForm) {
__ move(addr, tmp);
__ unsigned_shift_right(tmp, CardTable::card_shift, tmp);
} else {
__ unsigned_shift_right(addr, CardTable::card_shift, tmp);
}
LIR_Address* card_addr;
if (can_inline_as_constant(card_table_base)) {
card_addr = new LIR_Address(tmp, card_table_base->as_jint(), T_BYTE);
} else {
card_addr = new LIR_Address(tmp, load_constant(card_table_base), T_BYTE);
}
LIR_Opr dirty = LIR_OprFact::intConst(CardTable::dirty_card_val());
if (UseCondCardMark) {
LIR_Opr cur_value = new_register(T_INT);
if (UseConcMarkSweepGC) {
__ membar_storeload();
}
__ move(card_addr, cur_value);
LabelObj* L_already_dirty = new LabelObj();
__ cmp(lir_cond_equal, cur_value, dirty);
__ branch(lir_cond_equal, T_BYTE, L_already_dirty->label());
__ move(dirty, card_addr);
__ branch_destination(L_already_dirty->label());
} else {
#if INCLUDE_ALL_GCS
if (UseConcMarkSweepGC && CMSPrecleaningEnabled) {
__ membar_storestore();
}
#endif
__ move(dirty, card_addr);
}
#endif
}
//------------------------field access--------------------------------------
void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) {
assert(x->number_of_arguments() == 4, "wrong type");
LIRItem obj (x->argument_at(0), this); // object
LIRItem offset(x->argument_at(1), this); // offset of field
LIRItem cmp (x->argument_at(2), this); // value to compare with field
LIRItem val (x->argument_at(3), this); // replace field with val if matches cmp
assert(obj.type()->tag() == objectTag, "invalid type");
// In 64bit the type can be long, sparc doesn't have this assert
// assert(offset.type()->tag() == intTag, "invalid type");
assert(cmp.type()->tag() == type->tag(), "invalid type");
assert(val.type()->tag() == type->tag(), "invalid type");
LIR_Opr result = access_atomic_cmpxchg_at(IN_HEAP, as_BasicType(type),
obj, offset, cmp, val);
set_result(x, result);
}
// Comment copied form templateTable_i486.cpp
// ----------------------------------------------------------------------------
// Volatile variables demand their effects be made known to all CPU's in
@ -1702,7 +1487,6 @@ void LIRGenerator::do_StoreField(StoreField* x) {
bool needs_patching = x->needs_patching();
bool is_volatile = x->field()->is_volatile();
BasicType field_type = x->field_type();
bool is_oop = (field_type == T_ARRAY || field_type == T_OBJECT);
CodeEmitInfo* info = NULL;
if (needs_patching) {
@ -1717,7 +1501,6 @@ void LIRGenerator::do_StoreField(StoreField* x) {
}
}
LIRItem object(x->obj(), this);
LIRItem value(x->value(), this);
@ -1755,48 +1538,147 @@ void LIRGenerator::do_StoreField(StoreField* x) {
__ null_check(object.result(), new CodeEmitInfo(info), /* deoptimize */ needs_patching);
}
LIR_Address* address;
DecoratorSet decorators = IN_HEAP;
if (is_volatile) {
decorators |= MO_SEQ_CST;
}
if (needs_patching) {
// we need to patch the offset in the instruction so don't allow
// generate_address to try to be smart about emitting the -1.
// Otherwise the patching code won't know how to find the
// instruction to patch.
address = new LIR_Address(object.result(), PATCHED_ADDR, field_type);
decorators |= C1_NEEDS_PATCHING;
}
access_store_at(decorators, field_type, object, LIR_OprFact::intConst(x->offset()),
value.result(), info != NULL ? new CodeEmitInfo(info) : NULL, info);
}
void LIRGenerator::do_StoreIndexed(StoreIndexed* x) {
assert(x->is_pinned(),"");
bool needs_range_check = x->compute_needs_range_check();
bool use_length = x->length() != NULL;
bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT;
bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL ||
!get_jobject_constant(x->value())->is_null_object() ||
x->should_profile());
LIRItem array(x->array(), this);
LIRItem index(x->index(), this);
LIRItem value(x->value(), this);
LIRItem length(this);
array.load_item();
index.load_nonconstant();
if (use_length && needs_range_check) {
length.set_instruction(x->length());
length.load_item();
}
if (needs_store_check || x->check_boolean()) {
value.load_item();
} else {
address = generate_address(object.result(), x->offset(), field_type);
value.load_for_store(x->elt_type());
}
if (is_volatile && os::is_MP()) {
__ membar_release();
set_no_result(x);
// the CodeEmitInfo must be duplicated for each different
// LIR-instruction because spilling can occur anywhere between two
// instructions and so the debug information must be different
CodeEmitInfo* range_check_info = state_for(x);
CodeEmitInfo* null_check_info = NULL;
if (x->needs_null_check()) {
null_check_info = new CodeEmitInfo(range_check_info);
}
if (is_oop) {
// Do the pre-write barrier, if any.
pre_barrier(LIR_OprFact::address(address),
LIR_OprFact::illegalOpr /* pre_val */,
true /* do_load*/,
needs_patching,
(info ? new CodeEmitInfo(info) : NULL));
if (GenerateRangeChecks && needs_range_check) {
if (use_length) {
__ cmp(lir_cond_belowEqual, length.result(), index.result());
__ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result()));
} else {
array_range_check(array.result(), index.result(), null_check_info, range_check_info);
// range_check also does the null check
null_check_info = NULL;
}
}
bool needs_atomic_access = is_volatile || AlwaysAtomicAccesses;
if (needs_atomic_access && !needs_patching) {
volatile_field_store(value.result(), address, info);
if (GenerateArrayStoreCheck && needs_store_check) {
CodeEmitInfo* store_check_info = new CodeEmitInfo(range_check_info);
array_store_check(value.result(), array.result(), store_check_info, x->profiled_method(), x->profiled_bci());
}
DecoratorSet decorators = IN_HEAP | IN_HEAP_ARRAY;
if (x->check_boolean()) {
decorators |= C1_MASK_BOOLEAN;
}
access_store_at(decorators, x->elt_type(), array, index.result(), value.result(),
NULL, null_check_info);
}
void LIRGenerator::access_load_at(DecoratorSet decorators, BasicType type,
LIRItem& base, LIR_Opr offset, LIR_Opr result,
CodeEmitInfo* patch_info, CodeEmitInfo* load_emit_info) {
decorators |= C1_READ_ACCESS;
LIRAccess access(this, decorators, base, offset, type, patch_info, load_emit_info);
if (access.is_raw()) {
_barrier_set->BarrierSetC1::load_at(access, result);
} else {
LIR_PatchCode patch_code = needs_patching ? lir_patch_normal : lir_patch_none;
__ store(value.result(), address, info, patch_code);
}
if (is_oop) {
// Store to object so mark the card of the header
post_barrier(object.result(), value.result());
}
if (!support_IRIW_for_not_multiple_copy_atomic_cpu && is_volatile && os::is_MP()) {
__ membar();
_barrier_set->load_at(access, result);
}
}
void LIRGenerator::access_store_at(DecoratorSet decorators, BasicType type,
LIRItem& base, LIR_Opr offset, LIR_Opr value,
CodeEmitInfo* patch_info, CodeEmitInfo* store_emit_info) {
decorators |= C1_WRITE_ACCESS;
LIRAccess access(this, decorators, base, offset, type, patch_info, store_emit_info);
if (access.is_raw()) {
_barrier_set->BarrierSetC1::store_at(access, value);
} else {
_barrier_set->store_at(access, value);
}
}
LIR_Opr LIRGenerator::access_atomic_cmpxchg_at(DecoratorSet decorators, BasicType type,
LIRItem& base, LIRItem& offset, LIRItem& cmp_value, LIRItem& new_value) {
// Atomic operations are SEQ_CST by default
decorators |= C1_READ_ACCESS;
decorators |= C1_WRITE_ACCESS;
decorators |= ((decorators & MO_DECORATOR_MASK) != 0) ? MO_SEQ_CST : 0;
LIRAccess access(this, decorators, base, offset, type);
if (access.is_raw()) {
return _barrier_set->BarrierSetC1::atomic_cmpxchg_at(access, cmp_value, new_value);
} else {
return _barrier_set->atomic_cmpxchg_at(access, cmp_value, new_value);
}
}
LIR_Opr LIRGenerator::access_atomic_xchg_at(DecoratorSet decorators, BasicType type,
LIRItem& base, LIRItem& offset, LIRItem& value) {
// Atomic operations are SEQ_CST by default
decorators |= C1_READ_ACCESS;
decorators |= C1_WRITE_ACCESS;
decorators |= ((decorators & MO_DECORATOR_MASK) != 0) ? MO_SEQ_CST : 0;
LIRAccess access(this, decorators, base, offset, type);
if (access.is_raw()) {
return _barrier_set->BarrierSetC1::atomic_xchg_at(access, value);
} else {
return _barrier_set->atomic_xchg_at(access, value);
}
}
LIR_Opr LIRGenerator::access_atomic_add_at(DecoratorSet decorators, BasicType type,
LIRItem& base, LIRItem& offset, LIRItem& value) {
// Atomic operations are SEQ_CST by default
decorators |= C1_READ_ACCESS;
decorators |= C1_WRITE_ACCESS;
decorators |= ((decorators & MO_DECORATOR_MASK) != 0) ? MO_SEQ_CST : 0;
LIRAccess access(this, decorators, base, offset, type);
if (access.is_raw()) {
return _barrier_set->BarrierSetC1::atomic_add_at(access, value);
} else {
return _barrier_set->atomic_add_at(access, value);
}
}
void LIRGenerator::do_LoadField(LoadField* x) {
bool needs_patching = x->needs_patching();
@ -1843,33 +1725,18 @@ void LIRGenerator::do_LoadField(LoadField* x) {
__ null_check(obj, new CodeEmitInfo(info), /* deoptimize */ needs_patching);
}
LIR_Opr reg = rlock_result(x, field_type);
LIR_Address* address;
DecoratorSet decorators = IN_HEAP;
if (is_volatile) {
decorators |= MO_SEQ_CST;
}
if (needs_patching) {
// we need to patch the offset in the instruction so don't allow
// generate_address to try to be smart about emitting the -1.
// Otherwise the patching code won't know how to find the
// instruction to patch.
address = new LIR_Address(object.result(), PATCHED_ADDR, field_type);
} else {
address = generate_address(object.result(), x->offset(), field_type);
decorators |= C1_NEEDS_PATCHING;
}
if (support_IRIW_for_not_multiple_copy_atomic_cpu && is_volatile && os::is_MP()) {
__ membar();
}
bool needs_atomic_access = is_volatile || AlwaysAtomicAccesses;
if (needs_atomic_access && !needs_patching) {
volatile_field_load(address, reg, info);
} else {
LIR_PatchCode patch_code = needs_patching ? lir_patch_normal : lir_patch_none;
__ load(address, reg, info, patch_code);
}
if (is_volatile && os::is_MP()) {
__ membar_acquire();
}
LIR_Opr result = rlock_result(x, field_type);
access_load_at(decorators, field_type,
object, LIR_OprFact::intConst(x->offset()), result,
info ? new CodeEmitInfo(info) : NULL, info);
}
@ -1968,9 +1835,6 @@ void LIRGenerator::do_LoadIndexed(LoadIndexed* x) {
}
}
// emit array address setup early so it schedules better
LIR_Address* array_addr = emit_array_address(array.result(), index.result(), x->elt_type(), false);
if (GenerateRangeChecks && needs_range_check) {
if (StressLoopInvariantCodeMotion && range_check_info->deoptimize_on_exception()) {
__ branch(lir_cond_always, T_ILLEGAL, new RangeCheckStub(range_check_info, index.result()));
@ -1986,7 +1850,12 @@ void LIRGenerator::do_LoadIndexed(LoadIndexed* x) {
}
}
__ move(array_addr, rlock_result(x, x->elt_type()), null_check_info);
DecoratorSet decorators = IN_HEAP | IN_HEAP_ARRAY;
LIR_Opr result = rlock_result(x, x->elt_type());
access_load_at(decorators, x->elt_type(),
array, index.result(), result,
NULL, null_check_info);
}
@ -2272,157 +2141,21 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) {
off.load_item();
src.load_item();
LIR_Opr value = rlock_result(x, x->basic_type());
DecoratorSet decorators = IN_HEAP;
if (support_IRIW_for_not_multiple_copy_atomic_cpu && x->is_volatile() && os::is_MP()) {
__ membar();
if (x->is_volatile()) {
decorators |= MO_SEQ_CST;
}
get_Object_unsafe(value, src.result(), off.result(), type, x->is_volatile());
#if INCLUDE_ALL_GCS
// We might be reading the value of the referent field of a
// Reference object in order to attach it back to the live
// object graph. If G1 is enabled then we need to record
// the value that is being returned in an SATB log buffer.
//
// We need to generate code similar to the following...
//
// if (offset == java_lang_ref_Reference::referent_offset) {
// if (src != NULL) {
// if (klass(src)->reference_type() != REF_NONE) {
// pre_barrier(..., value, ...);
// }
// }
// }
if (UseG1GC && type == T_OBJECT) {
bool gen_pre_barrier = true; // Assume we need to generate pre_barrier.
bool gen_offset_check = true; // Assume we need to generate the offset guard.
bool gen_source_check = true; // Assume we need to check the src object for null.
bool gen_type_check = true; // Assume we need to check the reference_type.
if (off.is_constant()) {
jlong off_con = (off.type()->is_int() ?
(jlong) off.get_jint_constant() :
off.get_jlong_constant());
if (off_con != (jlong) java_lang_ref_Reference::referent_offset) {
// The constant offset is something other than referent_offset.
// We can skip generating/checking the remaining guards and
// skip generation of the code stub.
gen_pre_barrier = false;
} else {
// The constant offset is the same as referent_offset -
// we do not need to generate a runtime offset check.
gen_offset_check = false;
}
}
// We don't need to generate stub if the source object is an array
if (gen_pre_barrier && src.type()->is_array()) {
gen_pre_barrier = false;
}
if (gen_pre_barrier) {
// We still need to continue with the checks.
if (src.is_constant()) {
ciObject* src_con = src.get_jobject_constant();
guarantee(src_con != NULL, "no source constant");
if (src_con->is_null_object()) {
// The constant src object is null - We can skip
// generating the code stub.
gen_pre_barrier = false;
} else {
// Non-null constant source object. We still have to generate
// the slow stub - but we don't need to generate the runtime
// null object check.
gen_source_check = false;
}
}
}
if (gen_pre_barrier && !PatchALot) {
// Can the klass of object be statically determined to be
// a sub-class of Reference?
ciType* type = src.value()->declared_type();
if ((type != NULL) && type->is_loaded()) {
if (type->is_subtype_of(compilation()->env()->Reference_klass())) {
gen_type_check = false;
} else if (type->is_klass() &&
!compilation()->env()->Object_klass()->is_subtype_of(type->as_klass())) {
// Not Reference and not Object klass.
gen_pre_barrier = false;
}
}
}
if (gen_pre_barrier) {
LabelObj* Lcont = new LabelObj();
// We can have generate one runtime check here. Let's start with
// the offset check.
if (gen_offset_check) {
// if (offset != referent_offset) -> continue
// If offset is an int then we can do the comparison with the
// referent_offset constant; otherwise we need to move
// referent_offset into a temporary register and generate
// a reg-reg compare.
LIR_Opr referent_off;
if (off.type()->is_int()) {
referent_off = LIR_OprFact::intConst(java_lang_ref_Reference::referent_offset);
} else {
assert(off.type()->is_long(), "what else?");
referent_off = new_register(T_LONG);
__ move(LIR_OprFact::longConst(java_lang_ref_Reference::referent_offset), referent_off);
}
__ cmp(lir_cond_notEqual, off.result(), referent_off);
__ branch(lir_cond_notEqual, as_BasicType(off.type()), Lcont->label());
}
if (gen_source_check) {
// offset is a const and equals referent offset
// if (source == null) -> continue
__ cmp(lir_cond_equal, src.result(), LIR_OprFact::oopConst(NULL));
__ branch(lir_cond_equal, T_OBJECT, Lcont->label());
}
LIR_Opr src_klass = new_register(T_OBJECT);
if (gen_type_check) {
// We have determined that offset == referent_offset && src != null.
// if (src->_klass->_reference_type == REF_NONE) -> continue
__ move(new LIR_Address(src.result(), oopDesc::klass_offset_in_bytes(), T_ADDRESS), src_klass);
LIR_Address* reference_type_addr = new LIR_Address(src_klass, in_bytes(InstanceKlass::reference_type_offset()), T_BYTE);
LIR_Opr reference_type = new_register(T_INT);
__ move(reference_type_addr, reference_type);
__ cmp(lir_cond_equal, reference_type, LIR_OprFact::intConst(REF_NONE));
__ branch(lir_cond_equal, T_INT, Lcont->label());
}
{
// We have determined that src->_klass->_reference_type != REF_NONE
// so register the value in the referent field with the pre-barrier.
pre_barrier(LIR_OprFact::illegalOpr /* addr_opr */,
value /* pre_val */,
false /* do_load */,
false /* patch */,
NULL /* info */);
}
__ branch_destination(Lcont->label());
}
}
#endif // INCLUDE_ALL_GCS
if (x->is_volatile() && os::is_MP()) __ membar_acquire();
/* Normalize boolean value returned by unsafe operation, i.e., value != 0 ? value = true : value false. */
if (type == T_BOOLEAN) {
LabelObj* equalZeroLabel = new LabelObj();
__ cmp(lir_cond_equal, value, 0);
__ branch(lir_cond_equal, T_BOOLEAN, equalZeroLabel->label());
__ move(LIR_OprFact::intConst(1), value);
__ branch_destination(equalZeroLabel->label());
decorators |= C1_MASK_BOOLEAN;
}
if (type == T_ARRAY || type == T_OBJECT) {
decorators |= ON_UNKNOWN_OOP_REF;
}
LIR_Opr result = rlock_result(x, type);
access_load_at(decorators, type,
src, off.result(), result);
}
@ -2442,11 +2175,36 @@ void LIRGenerator::do_UnsafePutObject(UnsafePutObject* x) {
set_no_result(x);
if (x->is_volatile() && os::is_MP()) __ membar_release();
put_Object_unsafe(src.result(), off.result(), data.result(), type, x->is_volatile());
if (!support_IRIW_for_not_multiple_copy_atomic_cpu && x->is_volatile() && os::is_MP()) __ membar();
DecoratorSet decorators = IN_HEAP;
if (type == T_ARRAY || type == T_OBJECT) {
decorators |= ON_UNKNOWN_OOP_REF;
}
if (x->is_volatile()) {
decorators |= MO_SEQ_CST;
}
access_store_at(decorators, type, src, off.result(), data.result());
}
void LIRGenerator::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {
BasicType type = x->basic_type();
LIRItem src(x->object(), this);
LIRItem off(x->offset(), this);
LIRItem value(x->value(), this);
DecoratorSet decorators = IN_HEAP | MO_SEQ_CST;
if (type == T_ARRAY || type == T_OBJECT) {
decorators |= ON_UNKNOWN_OOP_REF;
}
LIR_Opr result;
if (x->is_add()) {
result = access_atomic_add_at(decorators, type, src, off, value);
} else {
result = access_atomic_xchg_at(decorators, type, src, off, value);
}
set_result(x, result);
}
void LIRGenerator::do_SwitchRanges(SwitchRangeArray* x, LIR_Opr value, BlockBegin* default_sux) {
int lng = x->length();
@ -3826,25 +3584,30 @@ void LIRGenerator::do_MemBar(MemBar* x) {
}
}
LIR_Opr LIRGenerator::mask_boolean(LIR_Opr array, LIR_Opr value, CodeEmitInfo*& null_check_info) {
LIR_Opr value_fixed = rlock_byte(T_BYTE);
if (TwoOperandLIRForm) {
__ move(value, value_fixed);
__ logical_and(value_fixed, LIR_OprFact::intConst(1), value_fixed);
} else {
__ logical_and(value, LIR_OprFact::intConst(1), value_fixed);
}
LIR_Opr klass = new_register(T_METADATA);
__ move(new LIR_Address(array, oopDesc::klass_offset_in_bytes(), T_ADDRESS), klass, null_check_info);
null_check_info = NULL;
LIR_Opr layout = new_register(T_INT);
__ move(new LIR_Address(klass, in_bytes(Klass::layout_helper_offset()), T_INT), layout);
int diffbit = Klass::layout_helper_boolean_diffbit();
__ logical_and(layout, LIR_OprFact::intConst(diffbit), layout);
__ cmp(lir_cond_notEqual, layout, LIR_OprFact::intConst(0));
__ cmove(lir_cond_notEqual, value_fixed, value, value_fixed, T_BYTE);
value = value_fixed;
return value;
}
LIR_Opr LIRGenerator::maybe_mask_boolean(StoreIndexed* x, LIR_Opr array, LIR_Opr value, CodeEmitInfo*& null_check_info) {
if (x->check_boolean()) {
LIR_Opr value_fixed = rlock_byte(T_BYTE);
if (TwoOperandLIRForm) {
__ move(value, value_fixed);
__ logical_and(value_fixed, LIR_OprFact::intConst(1), value_fixed);
} else {
__ logical_and(value, LIR_OprFact::intConst(1), value_fixed);
}
LIR_Opr klass = new_register(T_METADATA);
__ move(new LIR_Address(array, oopDesc::klass_offset_in_bytes(), T_ADDRESS), klass, null_check_info);
null_check_info = NULL;
LIR_Opr layout = new_register(T_INT);
__ move(new LIR_Address(klass, in_bytes(Klass::layout_helper_offset()), T_INT), layout);
int diffbit = Klass::layout_helper_boolean_diffbit();
__ logical_and(layout, LIR_OprFact::intConst(diffbit), layout);
__ cmp(lir_cond_notEqual, layout, LIR_OprFact::intConst(0));
__ cmove(lir_cond_notEqual, value_fixed, value, value_fixed, T_BYTE);
value = value_fixed;
value = mask_boolean(array, value, null_check_info);
}
return value;
}

View File

@ -25,12 +25,16 @@
#ifndef SHARE_VM_C1_C1_LIRGENERATOR_HPP
#define SHARE_VM_C1_C1_LIRGENERATOR_HPP
#include "c1/c1_Decorators.hpp"
#include "c1/c1_Instruction.hpp"
#include "c1/c1_LIR.hpp"
#include "ci/ciMethodData.hpp"
#include "gc/shared/barrierSet.hpp"
#include "utilities/macros.hpp"
#include "utilities/sizes.hpp"
class BarrierSetC1;
// The classes responsible for code emission and register allocation
@ -165,7 +169,6 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
Values _instruction_for_operand;
BitMap2D _vreg_flags; // flags which can be set on a per-vreg basis
LIR_List* _lir;
BarrierSet* _bs;
LIRGenerator* gen() {
return this;
@ -173,6 +176,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
void print_if_not_loaded(const NewInstance* new_instance) PRODUCT_RETURN;
public:
#ifdef ASSERT
LIR_List* lir(const char * file, int line) const {
_lir->set_file_and_line(file, line);
@ -183,6 +187,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
return _lir;
}
private:
// a simple cache of constants used within a block
GrowableArray<LIR_Const*> _constants;
LIR_OprList _reg_for_constants;
@ -190,6 +195,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
friend class PhiResolver;
public:
// unified bailout support
void bailout(const char* msg) const { compilation()->bailout(msg); }
bool bailed_out() const { return compilation()->bailed_out(); }
@ -233,14 +239,15 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
void move_to_phi(PhiResolver* resolver, Value cur_val, Value sux_val);
void move_to_phi(ValueStack* cur_state);
// code emission
void do_ArithmeticOp_Long (ArithmeticOp* x);
void do_ArithmeticOp_Int (ArithmeticOp* x);
void do_ArithmeticOp_FPU (ArithmeticOp* x);
// platform dependent
LIR_Opr getThreadPointer();
private:
// code emission
void do_ArithmeticOp_Long(ArithmeticOp* x);
void do_ArithmeticOp_Int (ArithmeticOp* x);
void do_ArithmeticOp_FPU (ArithmeticOp* x);
void do_RegisterFinalizer(Intrinsic* x);
void do_isInstance(Intrinsic* x);
void do_isPrimitive(Intrinsic* x);
@ -258,6 +265,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
void do_update_CRC32C(Intrinsic* x);
void do_vectorizedMismatch(Intrinsic* x);
public:
LIR_Opr call_runtime(BasicTypeArray* signature, LIRItemList* args, address entry, ValueType* result_type, CodeEmitInfo* info);
LIR_Opr call_runtime(BasicTypeArray* signature, LIR_OprList* args, address entry, ValueType* result_type, CodeEmitInfo* info);
@ -265,27 +273,37 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
LIR_Opr call_runtime(Value arg1, address entry, ValueType* result_type, CodeEmitInfo* info);
LIR_Opr call_runtime(Value arg1, Value arg2, address entry, ValueType* result_type, CodeEmitInfo* info);
// GC Barriers
// Access API
// generic interface
private:
BarrierSetC1 *_barrier_set;
void pre_barrier(LIR_Opr addr_opr, LIR_Opr pre_val, bool do_load, bool patch, CodeEmitInfo* info);
void post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val);
public:
void access_store_at(DecoratorSet decorators, BasicType type,
LIRItem& base, LIR_Opr offset, LIR_Opr value,
CodeEmitInfo* patch_info = NULL, CodeEmitInfo* store_emit_info = NULL);
void access_load_at(DecoratorSet decorators, BasicType type,
LIRItem& base, LIR_Opr offset, LIR_Opr result,
CodeEmitInfo* patch_info = NULL, CodeEmitInfo* load_emit_info = NULL);
LIR_Opr access_atomic_cmpxchg_at(DecoratorSet decorators, BasicType type,
LIRItem& base, LIRItem& offset, LIRItem& cmp_value, LIRItem& new_value);
LIR_Opr access_atomic_xchg_at(DecoratorSet decorators, BasicType type,
LIRItem& base, LIRItem& offset, LIRItem& value);
LIR_Opr access_atomic_add_at(DecoratorSet decorators, BasicType type,
LIRItem& base, LIRItem& offset, LIRItem& value);
// These need to guarantee JMM volatile semantics are preserved on each platform
// and requires one implementation per architecture.
LIR_Opr atomic_cmpxchg(BasicType type, LIR_Opr addr, LIRItem& cmp_value, LIRItem& new_value);
LIR_Opr atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& new_value);
LIR_Opr atomic_add(BasicType type, LIR_Opr addr, LIRItem& new_value);
// specific implementations
// pre barriers
void G1BarrierSet_pre_barrier(LIR_Opr addr_opr, LIR_Opr pre_val,
bool do_load, bool patch, CodeEmitInfo* info);
// post barriers
void G1BarrierSet_post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val);
void CardTableBarrierSet_post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val);
#ifdef CARDTABLEBARRIERSET_POST_BARRIER_HELPER
void CardTableBarrierSet_post_barrier_helper(LIR_OprDesc* addr, LIR_Const* card_table_base);
#endif
void array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, ciMethod* profiled_method, int profiled_bci);
static LIR_Opr result_register_for(ValueType* type, bool callee = false);
@ -354,7 +372,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
LIR_Address* generate_address(LIR_Opr base, int disp, BasicType type) {
return generate_address(base, LIR_OprFact::illegalOpr, 0, disp, type);
}
LIR_Address* emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr, BasicType type, bool needs_card_mark);
LIR_Address* emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr, BasicType type);
// the helper for generate_address
void add_large_constant(LIR_Opr src, int c, LIR_Opr dest);
@ -433,8 +451,6 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
void do_soft_float_compare(If *x);
#endif // __SOFTFP__
void init();
SwitchRangeArray* create_lookup_ranges(TableSwitch* x);
SwitchRangeArray* create_lookup_ranges(LookupSwitch* x);
void do_SwitchRanges(SwitchRangeArray* x, LIR_Opr value, BlockBegin* default_sux);
@ -452,6 +468,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
void profile_arguments(ProfileCall* x);
void profile_parameters(Base* x);
void profile_parameters_at_call(ProfileCall* x);
LIR_Opr mask_boolean(LIR_Opr array, LIR_Opr value, CodeEmitInfo*& null_check_info);
LIR_Opr maybe_mask_boolean(StoreIndexed* x, LIR_Opr array, LIR_Opr value, CodeEmitInfo*& null_check_info);
public:
@ -478,8 +495,8 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
: _compilation(compilation)
, _method(method)
, _virtual_register_number(LIR_OprDesc::vreg_base)
, _vreg_flags(num_vreg_flags) {
init();
, _vreg_flags(num_vreg_flags)
, _barrier_set(BarrierSet::barrier_set()->barrier_set_c1()) {
}
// for virtual registers, maps them back to Phi's or Local's

View File

@ -74,6 +74,9 @@ class StubAssembler: public C1_MacroAssembler {
void set_frame_size(int size);
void set_num_rt_args(int args);
void save_live_registers();
void restore_live_registers_without_return();
// accessors
const char* name() const { return _name; }
bool must_gc_arguments() const { return _must_gc_arguments; }
@ -86,6 +89,9 @@ class StubAssembler: public C1_MacroAssembler {
int call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1);
int call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2);
int call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2, Register arg3);
void prologue(const char* name, bool must_gc_arguments);
void epilogue();
};
#endif // SHARE_VM_C1_C1_MACROASSEMBLER_HPP

View File

@ -39,6 +39,7 @@
#include "code/vtableStubs.hpp"
#include "compiler/disassembler.hpp"
#include "gc/shared/barrierSet.hpp"
#include "gc/shared/c1/barrierSetC1.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "interpreter/bytecode.hpp"
#include "interpreter/interpreter.hpp"
@ -178,9 +179,17 @@ static void deopt_caller() {
}
}
class StubIDStubAssemblerCodeGenClosure: public StubAssemblerCodeGenClosure {
private:
Runtime1::StubID _id;
public:
StubIDStubAssemblerCodeGenClosure(Runtime1::StubID id) : _id(id) {}
virtual OopMapSet* generate_code(StubAssembler* sasm) {
return Runtime1::generate_code_for(_id, sasm);
}
};
void Runtime1::generate_blob_for(BufferBlob* buffer_blob, StubID id) {
assert(0 <= id && id < number_of_ids, "illegal stub id");
CodeBlob* Runtime1::generate_blob(BufferBlob* buffer_blob, int stub_id, const char* name, bool expect_oop_map, StubAssemblerCodeGenClosure* cl) {
ResourceMark rm;
// create code buffer for code storage
CodeBuffer code(buffer_blob);
@ -192,33 +201,12 @@ void Runtime1::generate_blob_for(BufferBlob* buffer_blob, StubID id) {
Compilation::setup_code_buffer(&code, 0);
// create assembler for code generation
StubAssembler* sasm = new StubAssembler(&code, name_for(id), id);
StubAssembler* sasm = new StubAssembler(&code, name, stub_id);
// generate code for runtime stub
oop_maps = generate_code_for(id, sasm);
oop_maps = cl->generate_code(sasm);
assert(oop_maps == NULL || sasm->frame_size() != no_frame_size,
"if stub has an oop map it must have a valid frame size");
#ifdef ASSERT
// Make sure that stubs that need oopmaps have them
switch (id) {
// These stubs don't need to have an oopmap
case dtrace_object_alloc_id:
case g1_pre_barrier_slow_id:
case g1_post_barrier_slow_id:
case slow_subtype_check_id:
case fpu2long_stub_id:
case unwind_exception_id:
case counter_overflow_id:
#if defined(SPARC) || defined(PPC32)
case handle_exception_nofpu_id: // Unused on sparc
#endif
break;
// All other stubs should have oopmaps
default:
assert(oop_maps != NULL, "must have an oopmap");
}
#endif
assert(!expect_oop_map || oop_maps != NULL, "must have an oopmap");
// align so printing shows nop's instead of random code at the end (SimpleStubs are aligned)
sasm->align(BytesPerWord);
@ -228,17 +216,42 @@ void Runtime1::generate_blob_for(BufferBlob* buffer_blob, StubID id) {
frame_size = sasm->frame_size();
must_gc_arguments = sasm->must_gc_arguments();
// create blob - distinguish a few special cases
CodeBlob* blob = RuntimeStub::new_runtime_stub(name_for(id),
CodeBlob* blob = RuntimeStub::new_runtime_stub(name,
&code,
CodeOffsets::frame_never_safe,
frame_size,
oop_maps,
must_gc_arguments);
// install blob
assert(blob != NULL, "blob must exist");
_blobs[id] = blob;
return blob;
}
void Runtime1::generate_blob_for(BufferBlob* buffer_blob, StubID id) {
assert(0 <= id && id < number_of_ids, "illegal stub id");
bool expect_oop_map = true;
#ifdef ASSERT
// Make sure that stubs that need oopmaps have them
switch (id) {
// These stubs don't need to have an oopmap
case dtrace_object_alloc_id:
case slow_subtype_check_id:
case fpu2long_stub_id:
case unwind_exception_id:
case counter_overflow_id:
#if defined(SPARC) || defined(PPC32)
case handle_exception_nofpu_id: // Unused on sparc
#endif
expect_oop_map = false;
break;
default:
break;
}
#endif
StubIDStubAssemblerCodeGenClosure cl(id);
CodeBlob* blob = generate_blob(buffer_blob, id, name_for(id), expect_oop_map, &cl);
// install blob
_blobs[id] = blob;
}
void Runtime1::initialize(BufferBlob* blob) {
// platform-dependent initialization
@ -257,9 +270,10 @@ void Runtime1::initialize(BufferBlob* blob) {
}
}
#endif
BarrierSetC1* bs = BarrierSet::barrier_set()->barrier_set_c1();
bs->generate_c1_runtime_stubs(blob);
}
CodeBlob* Runtime1::blob_for(StubID id) {
assert(0 <= id && id < number_of_ids, "illegal stub id");
return _blobs[id];

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -68,8 +68,6 @@ class StubAssembler;
stub(load_klass_patching) \
stub(load_mirror_patching) \
stub(load_appendix_patching) \
stub(g1_pre_barrier_slow) \
stub(g1_post_barrier_slow) \
stub(fpu2long_stub) \
stub(counter_overflow) \
stub(predicate_failed_trap) \
@ -80,6 +78,11 @@ class StubAssembler;
#define STUB_NAME(x) #x " Runtime1 stub",
#define LAST_STUB_NAME(x) #x " Runtime1 stub"
class StubAssemblerCodeGenClosure: public Closure {
public:
virtual OopMapSet* generate_code(StubAssembler* sasm) = 0;
};
class Runtime1: public AllStatic {
friend class VMStructs;
friend class ArrayCopyStub;
@ -121,8 +124,11 @@ class Runtime1: public AllStatic {
static const char* _blob_names[];
// stub generation
public:
static CodeBlob* generate_blob(BufferBlob* buffer_blob, int stub_id, const char* name, bool expect_oop_map, StubAssemblerCodeGenClosure *cl);
static void generate_blob_for(BufferBlob* blob, StubID id);
static OopMapSet* generate_code_for(StubID id, StubAssembler* sasm);
private:
static OopMapSet* generate_exception_throw(StubAssembler* sasm, address target, bool has_argument);
static OopMapSet* generate_handle_exception(StubID id, StubAssembler* sasm);
static void generate_unwind_exception(StubAssembler *sasm);

View File

@ -0,0 +1,230 @@
/*
* Copyright (c) 2018, 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 "precompiled.hpp"
#include "c1/c1_LIRGenerator.hpp"
#include "c1/c1_CodeStubs.hpp"
#include "gc/g1/c1/g1BarrierSetC1.hpp"
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1BarrierSetAssembler.hpp"
#include "gc/g1/g1ThreadLocalData.hpp"
#include "gc/g1/heapRegion.hpp"
#include "utilities/macros.hpp"
#ifdef ASSERT
#define __ gen->lir(__FILE__, __LINE__)->
#else
#define __ gen->lir()->
#endif
void G1PreBarrierStub::emit_code(LIR_Assembler* ce) {
G1BarrierSetAssembler* bs = (G1BarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler();
bs->gen_pre_barrier_stub(ce, this);
}
void G1PostBarrierStub::emit_code(LIR_Assembler* ce) {
G1BarrierSetAssembler* bs = (G1BarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler();
bs->gen_post_barrier_stub(ce, this);
}
void G1BarrierSetC1::pre_barrier(LIRAccess& access, LIR_Opr addr_opr,
LIR_Opr pre_val, CodeEmitInfo* info) {
LIRGenerator* gen = access.gen();
DecoratorSet decorators = access.decorators();
bool in_heap = (decorators & IN_HEAP) != 0;
bool in_conc_root = (decorators & IN_CONCURRENT_ROOT) != 0;
if (!in_heap && !in_conc_root) {
return;
}
// First we test whether marking is in progress.
BasicType flag_type;
bool patch = (decorators & C1_NEEDS_PATCHING) != 0;
bool do_load = pre_val == LIR_OprFact::illegalOpr;
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
flag_type = T_INT;
} else {
guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1,
"Assumption");
// Use unsigned type T_BOOLEAN here rather than signed T_BYTE since some platforms, eg. ARM,
// need to use unsigned instructions to use the large offset to load the satb_mark_queue.
flag_type = T_BOOLEAN;
}
LIR_Opr thrd = gen->getThreadPointer();
LIR_Address* mark_active_flag_addr =
new LIR_Address(thrd,
in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()),
flag_type);
// Read the marking-in-progress flag.
LIR_Opr flag_val = gen->new_register(T_INT);
__ load(mark_active_flag_addr, flag_val);
__ cmp(lir_cond_notEqual, flag_val, LIR_OprFact::intConst(0));
LIR_PatchCode pre_val_patch_code = lir_patch_none;
CodeStub* slow;
if (do_load) {
assert(pre_val == LIR_OprFact::illegalOpr, "sanity");
assert(addr_opr != LIR_OprFact::illegalOpr, "sanity");
if (patch)
pre_val_patch_code = lir_patch_normal;
pre_val = gen->new_register(T_OBJECT);
if (!addr_opr->is_address()) {
assert(addr_opr->is_register(), "must be");
addr_opr = LIR_OprFact::address(new LIR_Address(addr_opr, T_OBJECT));
}
slow = new G1PreBarrierStub(addr_opr, pre_val, pre_val_patch_code, info);
} else {
assert(addr_opr == LIR_OprFact::illegalOpr, "sanity");
assert(pre_val->is_register(), "must be");
assert(pre_val->type() == T_OBJECT, "must be an object");
assert(info == NULL, "sanity");
slow = new G1PreBarrierStub(pre_val);
}
__ branch(lir_cond_notEqual, T_INT, slow);
__ branch_destination(slow->continuation());
}
void G1BarrierSetC1::post_barrier(LIRAccess& access, LIR_OprDesc* addr, LIR_OprDesc* new_val) {
LIRGenerator* gen = access.gen();
DecoratorSet decorators = access.decorators();
bool in_heap = (decorators & IN_HEAP) != 0;
if (!in_heap) {
return;
}
// If the "new_val" is a constant NULL, no barrier is necessary.
if (new_val->is_constant() &&
new_val->as_constant_ptr()->as_jobject() == NULL) return;
if (!new_val->is_register()) {
LIR_Opr new_val_reg = gen->new_register(T_OBJECT);
if (new_val->is_constant()) {
__ move(new_val, new_val_reg);
} else {
__ leal(new_val, new_val_reg);
}
new_val = new_val_reg;
}
assert(new_val->is_register(), "must be a register at this point");
if (addr->is_address()) {
LIR_Address* address = addr->as_address_ptr();
LIR_Opr ptr = gen->new_pointer_register();
if (!address->index()->is_valid() && address->disp() == 0) {
__ move(address->base(), ptr);
} else {
assert(address->disp() != max_jint, "lea doesn't support patched addresses!");
__ leal(addr, ptr);
}
addr = ptr;
}
assert(addr->is_register(), "must be a register at this point");
LIR_Opr xor_res = gen->new_pointer_register();
LIR_Opr xor_shift_res = gen->new_pointer_register();
if (TwoOperandLIRForm) {
__ move(addr, xor_res);
__ logical_xor(xor_res, new_val, xor_res);
__ move(xor_res, xor_shift_res);
__ unsigned_shift_right(xor_shift_res,
LIR_OprFact::intConst(HeapRegion::LogOfHRGrainBytes),
xor_shift_res,
LIR_OprDesc::illegalOpr());
} else {
__ logical_xor(addr, new_val, xor_res);
__ unsigned_shift_right(xor_res,
LIR_OprFact::intConst(HeapRegion::LogOfHRGrainBytes),
xor_shift_res,
LIR_OprDesc::illegalOpr());
}
if (!new_val->is_register()) {
LIR_Opr new_val_reg = gen->new_register(T_OBJECT);
__ leal(new_val, new_val_reg);
new_val = new_val_reg;
}
assert(new_val->is_register(), "must be a register at this point");
__ cmp(lir_cond_notEqual, xor_shift_res, LIR_OprFact::intptrConst(NULL_WORD));
CodeStub* slow = new G1PostBarrierStub(addr, new_val);
__ branch(lir_cond_notEqual, LP64_ONLY(T_LONG) NOT_LP64(T_INT), slow);
__ branch_destination(slow->continuation());
}
void G1BarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) {
DecoratorSet decorators = access.decorators();
bool is_weak = (decorators & ON_WEAK_OOP_REF) != 0;
bool is_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0;
bool is_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0;
LIRGenerator *gen = access.gen();
BarrierSetC1::load_at_resolved(access, result);
if (access.is_oop() && (is_weak || is_phantom || is_anonymous)) {
// Register the value in the referent field with the pre-barrier
LabelObj *Lcont_anonymous;
if (is_anonymous) {
Lcont_anonymous = new LabelObj();
generate_referent_check(access, Lcont_anonymous);
}
pre_barrier(access, LIR_OprFact::illegalOpr /* addr_opr */,
result /* pre_val */, access.patch_emit_info() /* info */);
if (is_anonymous) {
__ branch_destination(Lcont_anonymous->label());
}
}
}
class C1G1PreBarrierCodeGenClosure : public StubAssemblerCodeGenClosure {
virtual OopMapSet* generate_code(StubAssembler* sasm) {
G1BarrierSetAssembler* bs = (G1BarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler();
bs->generate_c1_pre_barrier_runtime_stub(sasm);
return NULL;
}
};
class C1G1PostBarrierCodeGenClosure : public StubAssemblerCodeGenClosure {
virtual OopMapSet* generate_code(StubAssembler* sasm) {
G1BarrierSetAssembler* bs = (G1BarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler();
bs->generate_c1_post_barrier_runtime_stub(sasm);
return NULL;
}
};
void G1BarrierSetC1::generate_c1_runtime_stubs(BufferBlob* buffer_blob) {
C1G1PreBarrierCodeGenClosure pre_code_gen_cl;
C1G1PostBarrierCodeGenClosure post_code_gen_cl;
_pre_barrier_c1_runtime_code_blob = Runtime1::generate_blob(buffer_blob, -1, "g1_pre_barrier_slow",
false, &pre_code_gen_cl);
_post_barrier_c1_runtime_code_blob = Runtime1::generate_blob(buffer_blob, -1, "g1_post_barrier_slow",
false, &post_code_gen_cl);
}

View File

@ -0,0 +1,138 @@
/*
* Copyright (c) 2018, 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.
*
*/
#ifndef SHARE_GC_G1_C1_G1BARRIERSETC1_HPP
#define SHARE_GC_G1_C1_G1BARRIERSETC1_HPP
#include "c1/c1_CodeStubs.hpp"
#include "gc/shared/c1/modRefBarrierSetC1.hpp"
class G1PreBarrierStub: public CodeStub {
friend class G1BarrierSetC1;
private:
bool _do_load;
LIR_Opr _addr;
LIR_Opr _pre_val;
LIR_PatchCode _patch_code;
CodeEmitInfo* _info;
public:
// Version that _does_ generate a load of the previous value from addr.
// addr (the address of the field to be read) must be a LIR_Address
// pre_val (a temporary register) must be a register;
G1PreBarrierStub(LIR_Opr addr, LIR_Opr pre_val, LIR_PatchCode patch_code, CodeEmitInfo* info) :
_addr(addr), _pre_val(pre_val), _do_load(true),
_patch_code(patch_code), _info(info)
{
assert(_pre_val->is_register(), "should be temporary register");
assert(_addr->is_address(), "should be the address of the field");
}
// Version that _does not_ generate load of the previous value; the
// previous value is assumed to have already been loaded into pre_val.
G1PreBarrierStub(LIR_Opr pre_val) :
_addr(LIR_OprFact::illegalOpr), _pre_val(pre_val), _do_load(false),
_patch_code(lir_patch_none), _info(NULL)
{
assert(_pre_val->is_register(), "should be a register");
}
LIR_Opr addr() const { return _addr; }
LIR_Opr pre_val() const { return _pre_val; }
LIR_PatchCode patch_code() const { return _patch_code; }
CodeEmitInfo* info() const { return _info; }
bool do_load() const { return _do_load; }
virtual void emit_code(LIR_Assembler* e);
virtual void visit(LIR_OpVisitState* visitor) {
if (_do_load) {
// don't pass in the code emit info since it's processed in the fast
// path
if (_info != NULL)
visitor->do_slow_case(_info);
else
visitor->do_slow_case();
visitor->do_input(_addr);
visitor->do_temp(_pre_val);
} else {
visitor->do_slow_case();
visitor->do_input(_pre_val);
}
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("G1PreBarrierStub"); }
#endif // PRODUCT
};
class G1PostBarrierStub: public CodeStub {
friend class G1BarrierSetC1;
private:
LIR_Opr _addr;
LIR_Opr _new_val;
public:
// addr (the address of the object head) and new_val must be registers.
G1PostBarrierStub(LIR_Opr addr, LIR_Opr new_val): _addr(addr), _new_val(new_val) { }
LIR_Opr addr() const { return _addr; }
LIR_Opr new_val() const { return _new_val; }
virtual void emit_code(LIR_Assembler* e);
virtual void visit(LIR_OpVisitState* visitor) {
// don't pass in the code emit info since it's processed in the fast path
visitor->do_slow_case();
visitor->do_input(_addr);
visitor->do_input(_new_val);
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("G1PostBarrierStub"); }
#endif // PRODUCT
};
class CodeBlob;
class G1BarrierSetC1 : public ModRefBarrierSetC1 {
protected:
CodeBlob* _pre_barrier_c1_runtime_code_blob;
CodeBlob* _post_barrier_c1_runtime_code_blob;
virtual void pre_barrier(LIRAccess& access, LIR_Opr addr_opr,
LIR_Opr pre_val, CodeEmitInfo* info);
virtual void post_barrier(LIRAccess& access, LIR_OprDesc* addr, LIR_OprDesc* new_val);
virtual void load_at_resolved(LIRAccess& access, LIR_Opr result);
public:
G1BarrierSetC1()
: _pre_barrier_c1_runtime_code_blob(NULL),
_post_barrier_c1_runtime_code_blob(NULL) {}
CodeBlob* pre_barrier_c1_runtime_code_blob() { return _pre_barrier_c1_runtime_code_blob; }
CodeBlob* post_barrier_c1_runtime_code_blob() { return _post_barrier_c1_runtime_code_blob; }
virtual void generate_c1_runtime_stubs(BufferBlob* buffer_blob);
};
#endif // SHARE_GC_G1_C1_G1BARRIERSETC1_HPP

View File

@ -37,12 +37,18 @@
#include "runtime/mutexLocker.hpp"
#include "runtime/thread.inline.hpp"
#include "utilities/macros.hpp"
#ifdef COMPILER1
#include "gc/g1/c1/g1BarrierSetC1.hpp"
#endif
class G1BarrierSetC1;
SATBMarkQueueSet G1BarrierSet::_satb_mark_queue_set;
DirtyCardQueueSet G1BarrierSet::_dirty_card_queue_set;
G1BarrierSet::G1BarrierSet(G1CardTable* card_table) :
CardTableBarrierSet(make_barrier_set_assembler<G1BarrierSetAssembler>(),
make_barrier_set_c1<G1BarrierSetC1>(),
card_table,
BarrierSet::FakeRtti(BarrierSet::G1BarrierSet)) {}

View File

@ -33,8 +33,9 @@
#include "utilities/fakeRttiSupport.hpp"
#include "utilities/macros.hpp"
class JavaThread;
class BarrierSetAssembler;
class BarrierSetC1;
class JavaThread;
// This class provides the interface between a barrier implementation and
// the rest of the system.
@ -68,6 +69,7 @@ protected:
private:
FakeRtti _fake_rtti;
BarrierSetAssembler* _barrier_set_assembler;
BarrierSetC1* _barrier_set_c1;
public:
// Metafunction mapping a class derived from BarrierSet to the
@ -88,9 +90,12 @@ public:
// End of fake RTTI support.
protected:
BarrierSet(BarrierSetAssembler* barrier_set_assembler, const FakeRtti& fake_rtti) :
BarrierSet(BarrierSetAssembler* barrier_set_assembler,
BarrierSetC1* barrier_set_c1,
const FakeRtti& fake_rtti) :
_fake_rtti(fake_rtti),
_barrier_set_assembler(barrier_set_assembler) { }
_barrier_set_assembler(barrier_set_assembler),
_barrier_set_c1(barrier_set_c1) {}
~BarrierSet() { }
template <class BarrierSetAssemblerT>
@ -98,6 +103,11 @@ protected:
return NOT_ZERO(new BarrierSetAssemblerT()) ZERO_ONLY(NULL);
}
template <class BarrierSetC1T>
BarrierSetC1* make_barrier_set_c1() {
return COMPILER1_PRESENT(new BarrierSetC1T()) NOT_COMPILER1(NULL);
}
public:
// Support for optimizing compilers to call the barrier set on slow path allocations
// that did not enter a TLAB. Used for e.g. ReduceInitialCardMarks.
@ -123,6 +133,11 @@ public:
return _barrier_set_assembler;
}
BarrierSetC1* barrier_set_c1() {
assert(_barrier_set_c1 != NULL, "should be set");
return _barrier_set_c1;
}
// The AccessBarrier of a BarrierSet subclass is called by the Access API
// (cf. oops/access.hpp) to perform decorated accesses. GC implementations
// may override these default access operations by declaring an

View File

@ -0,0 +1,326 @@
/*
* Copyright (c) 2018, 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 "precompiled.hpp"
#include "c1/c1_Defs.hpp"
#include "c1/c1_LIRGenerator.hpp"
#include "gc/shared/c1/barrierSetC1.hpp"
#include "utilities/macros.hpp"
#ifndef PATCHED_ADDR
#define PATCHED_ADDR (max_jint)
#endif
#ifdef ASSERT
#define __ gen->lir(__FILE__, __LINE__)->
#else
#define __ gen->lir()->
#endif
LIR_Opr BarrierSetC1::resolve_address(LIRAccess& access, bool resolve_in_register) {
DecoratorSet decorators = access.decorators();
bool on_array = (decorators & IN_HEAP_ARRAY) != 0;
bool needs_patching = (decorators & C1_NEEDS_PATCHING) != 0;
LIRItem& base = access.base().item();
LIR_Opr offset = access.offset().opr();
LIRGenerator *gen = access.gen();
LIR_Opr addr_opr;
if (on_array) {
addr_opr = LIR_OprFact::address(gen->emit_array_address(base.result(), offset, access.type()));
} else if (needs_patching) {
// we need to patch the offset in the instruction so don't allow
// generate_address to try to be smart about emitting the -1.
// Otherwise the patching code won't know how to find the
// instruction to patch.
addr_opr = LIR_OprFact::address(new LIR_Address(base.result(), PATCHED_ADDR, access.type()));
} else {
addr_opr = LIR_OprFact::address(gen->generate_address(base.result(), offset, 0, 0, access.type()));
}
if (resolve_in_register) {
LIR_Opr resolved_addr = gen->new_pointer_register();
__ leal(addr_opr, resolved_addr);
resolved_addr = LIR_OprFact::address(new LIR_Address(resolved_addr, access.type()));
return resolved_addr;
} else {
return addr_opr;
}
}
void BarrierSetC1::store_at(LIRAccess& access, LIR_Opr value) {
DecoratorSet decorators = access.decorators();
bool in_heap = (decorators & IN_HEAP) != 0;
assert(in_heap, "not supported yet");
LIR_Opr resolved = resolve_address(access, false);
access.set_resolved_addr(resolved);
store_at_resolved(access, value);
}
void BarrierSetC1::load_at(LIRAccess& access, LIR_Opr result) {
DecoratorSet decorators = access.decorators();
bool in_heap = (decorators & IN_HEAP) != 0;
assert(in_heap, "not supported yet");
LIR_Opr resolved = resolve_address(access, false);
access.set_resolved_addr(resolved);
load_at_resolved(access, result);
}
LIR_Opr BarrierSetC1::atomic_cmpxchg_at(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value) {
DecoratorSet decorators = access.decorators();
bool in_heap = (decorators & IN_HEAP) != 0;
assert(in_heap, "not supported yet");
access.load_address();
LIR_Opr resolved = resolve_address(access, true);
access.set_resolved_addr(resolved);
return atomic_cmpxchg_at_resolved(access, cmp_value, new_value);
}
LIR_Opr BarrierSetC1::atomic_xchg_at(LIRAccess& access, LIRItem& value) {
DecoratorSet decorators = access.decorators();
bool in_heap = (decorators & IN_HEAP) != 0;
assert(in_heap, "not supported yet");
access.load_address();
LIR_Opr resolved = resolve_address(access, true);
access.set_resolved_addr(resolved);
return atomic_xchg_at_resolved(access, value);
}
LIR_Opr BarrierSetC1::atomic_add_at(LIRAccess& access, LIRItem& value) {
DecoratorSet decorators = access.decorators();
bool in_heap = (decorators & IN_HEAP) != 0;
assert(in_heap, "not supported yet");
access.load_address();
LIR_Opr resolved = resolve_address(access, true);
access.set_resolved_addr(resolved);
return atomic_add_at_resolved(access, value);
}
void BarrierSetC1::store_at_resolved(LIRAccess& access, LIR_Opr value) {
DecoratorSet decorators = access.decorators();
bool is_volatile = (((decorators & MO_SEQ_CST) != 0) || AlwaysAtomicAccesses) && os::is_MP();
bool needs_patching = (decorators & C1_NEEDS_PATCHING) != 0;
bool mask_boolean = (decorators & C1_MASK_BOOLEAN) != 0;
LIRGenerator* gen = access.gen();
if (mask_boolean) {
value = gen->mask_boolean(access.base().opr(), value, access.access_emit_info());
}
if (is_volatile && os::is_MP()) {
__ membar_release();
}
LIR_PatchCode patch_code = needs_patching ? lir_patch_normal : lir_patch_none;
if (is_volatile && !needs_patching) {
gen->volatile_field_store(value, access.resolved_addr()->as_address_ptr(), access.access_emit_info());
} else {
__ store(value, access.resolved_addr()->as_address_ptr(), access.access_emit_info(), patch_code);
}
if (is_volatile && !support_IRIW_for_not_multiple_copy_atomic_cpu) {
__ membar();
}
}
void BarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) {
LIRGenerator *gen = access.gen();
DecoratorSet decorators = access.decorators();
bool is_volatile = (((decorators & MO_SEQ_CST) != 0) || AlwaysAtomicAccesses) && os::is_MP();
bool needs_patching = (decorators & C1_NEEDS_PATCHING) != 0;
bool mask_boolean = (decorators & C1_MASK_BOOLEAN) != 0;
if (support_IRIW_for_not_multiple_copy_atomic_cpu && is_volatile) {
__ membar();
}
LIR_PatchCode patch_code = needs_patching ? lir_patch_normal : lir_patch_none;
if (is_volatile && !needs_patching) {
gen->volatile_field_load(access.resolved_addr()->as_address_ptr(), result, access.access_emit_info());
} else {
__ load(access.resolved_addr()->as_address_ptr(), result, access.access_emit_info(), patch_code);
}
if (is_volatile && os::is_MP()) {
__ membar_acquire();
}
/* Normalize boolean value returned by unsafe operation, i.e., value != 0 ? value = true : value false. */
if (mask_boolean) {
LabelObj* equalZeroLabel = new LabelObj();
__ cmp(lir_cond_equal, result, 0);
__ branch(lir_cond_equal, T_BOOLEAN, equalZeroLabel->label());
__ move(LIR_OprFact::intConst(1), result);
__ branch_destination(equalZeroLabel->label());
}
}
LIR_Opr BarrierSetC1::atomic_cmpxchg_at_resolved(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value) {
LIRGenerator *gen = access.gen();
return gen->atomic_cmpxchg(access.type(), access.resolved_addr(), cmp_value, new_value);
}
LIR_Opr BarrierSetC1::atomic_xchg_at_resolved(LIRAccess& access, LIRItem& value) {
LIRGenerator *gen = access.gen();
return gen->atomic_xchg(access.type(), access.resolved_addr(), value);
}
LIR_Opr BarrierSetC1::atomic_add_at_resolved(LIRAccess& access, LIRItem& value) {
LIRGenerator *gen = access.gen();
return gen->atomic_add(access.type(), access.resolved_addr(), value);
}
void BarrierSetC1::generate_referent_check(LIRAccess& access, LabelObj* cont) {
// We might be reading the value of the referent field of a
// Reference object in order to attach it back to the live
// object graph. If G1 is enabled then we need to record
// the value that is being returned in an SATB log buffer.
//
// We need to generate code similar to the following...
//
// if (offset == java_lang_ref_Reference::referent_offset) {
// if (src != NULL) {
// if (klass(src)->reference_type() != REF_NONE) {
// pre_barrier(..., value, ...);
// }
// }
// }
bool gen_pre_barrier = true; // Assume we need to generate pre_barrier.
bool gen_offset_check = true; // Assume we need to generate the offset guard.
bool gen_source_check = true; // Assume we need to check the src object for null.
bool gen_type_check = true; // Assume we need to check the reference_type.
LIRGenerator *gen = access.gen();
LIRItem& base = access.base().item();
LIR_Opr offset = access.offset().opr();
if (offset->is_constant()) {
LIR_Const* constant = offset->as_constant_ptr();
jlong off_con = (constant->type() == T_INT ?
(jlong)constant->as_jint() :
constant->as_jlong());
if (off_con != (jlong) java_lang_ref_Reference::referent_offset) {
// The constant offset is something other than referent_offset.
// We can skip generating/checking the remaining guards and
// skip generation of the code stub.
gen_pre_barrier = false;
} else {
// The constant offset is the same as referent_offset -
// we do not need to generate a runtime offset check.
gen_offset_check = false;
}
}
// We don't need to generate stub if the source object is an array
if (gen_pre_barrier && base.type()->is_array()) {
gen_pre_barrier = false;
}
if (gen_pre_barrier) {
// We still need to continue with the checks.
if (base.is_constant()) {
ciObject* src_con = base.get_jobject_constant();
guarantee(src_con != NULL, "no source constant");
if (src_con->is_null_object()) {
// The constant src object is null - We can skip
// generating the code stub.
gen_pre_barrier = false;
} else {
// Non-null constant source object. We still have to generate
// the slow stub - but we don't need to generate the runtime
// null object check.
gen_source_check = false;
}
}
}
if (gen_pre_barrier && !PatchALot) {
// Can the klass of object be statically determined to be
// a sub-class of Reference?
ciType* type = base.value()->declared_type();
if ((type != NULL) && type->is_loaded()) {
if (type->is_subtype_of(gen->compilation()->env()->Reference_klass())) {
gen_type_check = false;
} else if (type->is_klass() &&
!gen->compilation()->env()->Object_klass()->is_subtype_of(type->as_klass())) {
// Not Reference and not Object klass.
gen_pre_barrier = false;
}
}
}
if (gen_pre_barrier) {
// We can have generate one runtime check here. Let's start with
// the offset check.
if (gen_offset_check) {
// if (offset != referent_offset) -> continue
// If offset is an int then we can do the comparison with the
// referent_offset constant; otherwise we need to move
// referent_offset into a temporary register and generate
// a reg-reg compare.
LIR_Opr referent_off;
if (offset->type() == T_INT) {
referent_off = LIR_OprFact::intConst(java_lang_ref_Reference::referent_offset);
} else {
assert(offset->type() == T_LONG, "what else?");
referent_off = gen->new_register(T_LONG);
__ move(LIR_OprFact::longConst(java_lang_ref_Reference::referent_offset), referent_off);
}
__ cmp(lir_cond_notEqual, offset, referent_off);
__ branch(lir_cond_notEqual, offset->type(), cont->label());
}
if (gen_source_check) {
// offset is a const and equals referent offset
// if (source == null) -> continue
__ cmp(lir_cond_equal, base.result(), LIR_OprFact::oopConst(NULL));
__ branch(lir_cond_equal, T_OBJECT, cont->label());
}
LIR_Opr src_klass = gen->new_register(T_OBJECT);
if (gen_type_check) {
// We have determined that offset == referent_offset && src != null.
// if (src->_klass->_reference_type == REF_NONE) -> continue
__ move(new LIR_Address(base.result(), oopDesc::klass_offset_in_bytes(), T_ADDRESS), src_klass);
LIR_Address* reference_type_addr = new LIR_Address(src_klass, in_bytes(InstanceKlass::reference_type_offset()), T_BYTE);
LIR_Opr reference_type = gen->new_register(T_INT);
__ move(reference_type_addr, reference_type);
__ cmp(lir_cond_equal, reference_type, LIR_OprFact::intConst(REF_NONE));
__ branch(lir_cond_equal, T_INT, cont->label());
}
}
}

View File

@ -0,0 +1,139 @@
/*
* Copyright (c) 2018, 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.
*
*/
#ifndef SHARE_GC_SHARED_C1_BARRIERSETC1_HPP
#define SHARE_GC_SHARED_C1_BARRIERSETC1_HPP
#include "c1/c1_Decorators.hpp"
#include "c1/c1_LIRGenerator.hpp"
#include "c1/c1_Instruction.hpp"
#include "c1/c1_LIR.hpp"
#include "memory/allocation.hpp"
class LIRGenerator;
class LIRItem;
// The LIRAddressOpr comprises either a LIRItem or a LIR_Opr to describe elements
// of an access in the C1 Access API. Both of them allow asking for the opr() which
// will correspond to either _item.result() or _opr if there is no _item.
class LIRAddressOpr: public StackObj {
LIRItem* _item;
LIR_Opr _opr;
public:
LIRAddressOpr(LIRItem& item) : _item(&item), _opr(NULL) {}
LIRAddressOpr(LIR_Opr opr) : _item(NULL), _opr(opr) {}
LIRAddressOpr(const LIRAddressOpr& other) : _item(other._item), _opr(other._opr) {}
LIRItem& item() const {
assert(_item != NULL, "sanity");
return *_item;
}
LIR_Opr opr() const {
if (_item == NULL) {
return _opr;
} else {
return _item->result();
}
}
};
// The LIRAccess class wraps shared context parameters required for performing
// the right access in C1. This includes the address of the offset and the decorators.
class LIRAccess: public StackObj {
LIRGenerator* _gen;
DecoratorSet _decorators;
LIRAddressOpr _base;
LIRAddressOpr _offset;
BasicType _type;
LIR_Opr _resolved_addr;
CodeEmitInfo* _patch_emit_info;
CodeEmitInfo* _access_emit_info;
public:
LIRAccess(LIRGenerator* gen, DecoratorSet decorators,
LIRAddressOpr base, LIRAddressOpr offset, BasicType type,
CodeEmitInfo* patch_emit_info = NULL, CodeEmitInfo* access_emit_info = NULL) :
_gen(gen),
_decorators(AccessInternal::decorator_fixup(decorators)),
_base(base),
_offset(offset),
_type(type),
_resolved_addr(NULL),
_patch_emit_info(patch_emit_info),
_access_emit_info(access_emit_info) {}
void load_base() { _base.item().load_item(); }
void load_offset() { _offset.item().load_nonconstant(); }
void load_address() {
load_base();
load_offset();
}
LIRGenerator* gen() const { return _gen; }
CodeEmitInfo*& patch_emit_info() { return _patch_emit_info; }
CodeEmitInfo*& access_emit_info() { return _access_emit_info; }
LIRAddressOpr& base() { return _base; }
LIRAddressOpr& offset() { return _offset; }
BasicType type() const { return _type; }
LIR_Opr resolved_addr() const { return _resolved_addr; }
void set_resolved_addr(LIR_Opr addr) { _resolved_addr = addr; }
bool is_oop() const { return _type == T_ARRAY || _type == T_OBJECT; }
DecoratorSet decorators() const { return _decorators; }
bool is_raw() const { return (_decorators & AS_RAW) != 0; }
};
// The BarrierSetC1 class is the main entry point for the GC backend of the Access API in C1.
// It is called by the LIRGenerator::access_* functions, which is the main entry poing for
// access calls in C1.
class BarrierSetC1: public CHeapObj<mtGC> {
protected:
virtual LIR_Opr resolve_address(LIRAccess& access, bool resolve_in_register);
virtual void generate_referent_check(LIRAccess& access, LabelObj* cont);
// Accesses with resolved address
virtual void store_at_resolved(LIRAccess& access, LIR_Opr value);
virtual void load_at_resolved(LIRAccess& access, LIR_Opr result);
virtual LIR_Opr atomic_cmpxchg_at_resolved(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value);
virtual LIR_Opr atomic_xchg_at_resolved(LIRAccess& access, LIRItem& value);
virtual LIR_Opr atomic_add_at_resolved(LIRAccess& access, LIRItem& value);
public:
virtual void store_at(LIRAccess& access, LIR_Opr value);
virtual void load_at(LIRAccess& access, LIR_Opr result);
virtual LIR_Opr atomic_cmpxchg_at(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value);
virtual LIR_Opr atomic_xchg_at(LIRAccess& access, LIRItem& value);
virtual LIR_Opr atomic_add_at(LIRAccess& access, LIRItem& value);
virtual void generate_c1_runtime_stubs(BufferBlob* buffer_blob) {}
};
#endif // SHARE_GC_SHARED_C1_BARRIERSETC1_HPP

View File

@ -0,0 +1,102 @@
/*
* Copyright (c) 2018, 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 "precompiled.hpp"
#include "gc/shared/c1/cardTableBarrierSetC1.hpp"
#include "gc/shared/cardTableBarrierSet.hpp"
#include "utilities/macros.hpp"
#ifdef ASSERT
#define __ gen->lir(__FILE__, __LINE__)->
#else
#define __ gen->lir()->
#endif
void CardTableBarrierSetC1::post_barrier(LIRAccess& access, LIR_OprDesc* addr, LIR_OprDesc* new_val) {
DecoratorSet decorators = access.decorators();
LIRGenerator* gen = access.gen();
bool in_heap = (decorators & IN_HEAP) != 0;
if (!in_heap) {
return;
}
BarrierSet* bs = BarrierSet::barrier_set();
CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
CardTable* ct = ctbs->card_table();
assert(sizeof(*(ct->byte_map_base())) == sizeof(jbyte), "adjust this code");
LIR_Const* card_table_base = new LIR_Const(ct->byte_map_base());
if (addr->is_address()) {
LIR_Address* address = addr->as_address_ptr();
// ptr cannot be an object because we use this barrier for array card marks
// and addr can point in the middle of an array.
LIR_Opr ptr = gen->new_pointer_register();
if (!address->index()->is_valid() && address->disp() == 0) {
__ move(address->base(), ptr);
} else {
assert(address->disp() != max_jint, "lea doesn't support patched addresses!");
__ leal(addr, ptr);
}
addr = ptr;
}
assert(addr->is_register(), "must be a register at this point");
#ifdef CARDTABLEBARRIERSET_POST_BARRIER_HELPER
gen->CardTableBarrierSet_post_barrier_helper(addr, card_table_base);
#else
LIR_Opr tmp = gen->new_pointer_register();
if (TwoOperandLIRForm) {
__ move(addr, tmp);
__ unsigned_shift_right(tmp, CardTable::card_shift, tmp);
} else {
__ unsigned_shift_right(addr, CardTable::card_shift, tmp);
}
LIR_Address* card_addr;
if (gen->can_inline_as_constant(card_table_base)) {
card_addr = new LIR_Address(tmp, card_table_base->as_jint(), T_BYTE);
} else {
card_addr = new LIR_Address(tmp, gen->load_constant(card_table_base), T_BYTE);
}
LIR_Opr dirty = LIR_OprFact::intConst(CardTable::dirty_card_val());
if (UseCondCardMark) {
LIR_Opr cur_value = gen->new_register(T_INT);
if (ct->scanned_concurrently()) {
__ membar_storeload();
}
__ move(card_addr, cur_value);
LabelObj* L_already_dirty = new LabelObj();
__ cmp(lir_cond_equal, cur_value, dirty);
__ branch(lir_cond_equal, T_BYTE, L_already_dirty->label());
__ move(dirty, card_addr);
__ branch_destination(L_already_dirty->label());
} else {
if (ct->scanned_concurrently()) {
__ membar_storestore();
}
__ move(dirty, card_addr);
}
#endif
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2018, 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.
*
*/
#ifndef SHARE_GC_SHARED_C1_CARDTABLEBARRIERSETC1_HPP
#define SHARE_GC_SHARED_C1_CARDTABLEBARRIERSETC1_HPP
#include "gc/shared/c1/modRefBarrierSetC1.hpp"
class CardTableBarrierSetC1 : public ModRefBarrierSetC1 {
protected:
virtual void post_barrier(LIRAccess& access, LIR_OprDesc* addr, LIR_OprDesc* new_val);
};
#endif // SHARE_GC_SHARED_C1_CARDTABLEBARRIERSETC1_HPP

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2018, 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 "precompiled.hpp"
#include "gc/shared/c1/modRefBarrierSetC1.hpp"
#include "utilities/macros.hpp"
#ifdef ASSERT
#define __ gen->lir(__FILE__, __LINE__)->
#else
#define __ gen->lir()->
#endif
void ModRefBarrierSetC1::store_at_resolved(LIRAccess& access, LIR_Opr value) {
DecoratorSet decorators = access.decorators();
bool on_array = (decorators & IN_HEAP_ARRAY) != 0;
bool on_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0;
if (access.is_oop()) {
pre_barrier(access, access.resolved_addr(),
LIR_OprFact::illegalOpr /* pre_val */, access.patch_emit_info());
}
BarrierSetC1::store_at_resolved(access, value);
if (access.is_oop()) {
bool precise = on_array || on_anonymous;
LIR_Opr post_addr = precise ? access.resolved_addr() : access.base().opr();
post_barrier(access, post_addr, value);
}
}
LIR_Opr ModRefBarrierSetC1::atomic_cmpxchg_at_resolved(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value) {
if (access.is_oop()) {
pre_barrier(access, access.resolved_addr(),
LIR_OprFact::illegalOpr /* pre_val */, NULL);
}
LIR_Opr result = BarrierSetC1::atomic_cmpxchg_at_resolved(access, cmp_value, new_value);
if (access.is_oop()) {
post_barrier(access, access.resolved_addr(), new_value.result());
}
return result;
}
LIR_Opr ModRefBarrierSetC1::atomic_xchg_at_resolved(LIRAccess& access, LIRItem& value) {
if (access.is_oop()) {
pre_barrier(access, access.resolved_addr(),
LIR_OprFact::illegalOpr /* pre_val */, NULL);
}
LIR_Opr result = BarrierSetC1::atomic_xchg_at_resolved(access, value);
if (access.is_oop()) {
post_barrier(access, access.resolved_addr(), value.result());
}
return result;
}
// This overrides the default to resolve the address into a register,
// assuming it will be used by a write barrier anyway.
LIR_Opr ModRefBarrierSetC1::resolve_address(LIRAccess& access, bool resolve_in_register) {
DecoratorSet decorators = access.decorators();
bool needs_patching = (decorators & C1_NEEDS_PATCHING) != 0;
bool is_write = (decorators & C1_WRITE_ACCESS) != 0;
resolve_in_register |= !needs_patching && is_write && access.is_oop();
return BarrierSetC1::resolve_address(access, resolve_in_register);
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2018, 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.
*
*/
#ifndef SHARE_GC_SHARED_C1_MODREFBARRIERSETC1_HPP
#define SHARE_GC_SHARED_C1_MODREFBARRIERSETC1_HPP
#include "gc/shared/c1/barrierSetC1.hpp"
// The ModRefBarrierSetC1 filters away accesses on BasicTypes other
// than T_OBJECT/T_ARRAY (oops). The oop accesses call one of the protected
// accesses, which are overridden in the concrete BarrierSetAssembler.
class ModRefBarrierSetC1 : public BarrierSetC1 {
protected:
virtual void pre_barrier(LIRAccess& access, LIR_Opr addr_opr,
LIR_Opr pre_val, CodeEmitInfo* info) {}
virtual void post_barrier(LIRAccess& access, LIR_OprDesc* addr,
LIR_OprDesc* new_val) {}
virtual LIR_Opr resolve_address(LIRAccess& access, bool resolve_in_register);
virtual void store_at_resolved(LIRAccess& access, LIR_Opr value);
virtual LIR_Opr atomic_cmpxchg_at_resolved(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value);
virtual LIR_Opr atomic_xchg_at_resolved(LIRAccess& access, LIRItem& value);
};
#endif // SHARE_GC_SHARED_C1_MODREFBARRIERSETC1_HPP

View File

@ -34,15 +34,22 @@
#include "services/memTracker.hpp"
#include "utilities/align.hpp"
#include "utilities/macros.hpp"
#ifdef COMPILER1
#include "gc/shared/c1/cardTableBarrierSetC1.hpp"
#endif
class CardTableBarrierSetC1;
// This kind of "BarrierSet" allows a "CollectedHeap" to detect and
// enumerate ref fields that have been modified (since the last
// enumeration.)
CardTableBarrierSet::CardTableBarrierSet(BarrierSetAssembler* barrier_set_assembler,
BarrierSetC1* barrier_set_c1,
CardTable* card_table,
const BarrierSet::FakeRtti& fake_rtti) :
ModRefBarrierSet(barrier_set_assembler,
barrier_set_c1,
fake_rtti.add_tag(BarrierSet::CardTableBarrierSet)),
_defer_initial_card_mark(false),
_card_table(card_table)
@ -50,6 +57,7 @@ CardTableBarrierSet::CardTableBarrierSet(BarrierSetAssembler* barrier_set_assemb
CardTableBarrierSet::CardTableBarrierSet(CardTable* card_table) :
ModRefBarrierSet(make_barrier_set_assembler<CardTableBarrierSetAssembler>(),
make_barrier_set_c1<CardTableBarrierSetC1>(),
BarrierSet::FakeRtti(BarrierSet::CardTableBarrierSet)),
_defer_initial_card_mark(false),
_card_table(card_table)

View File

@ -53,6 +53,7 @@ class CardTableBarrierSet: public ModRefBarrierSet {
CardTable* _card_table;
CardTableBarrierSet(BarrierSetAssembler* barrier_set_assembler,
BarrierSetC1* barrier_set_c1,
CardTable* card_table,
const BarrierSet::FakeRtti& fake_rtti);

View File

@ -33,8 +33,10 @@ class Klass;
class ModRefBarrierSet: public BarrierSet {
protected:
ModRefBarrierSet(BarrierSetAssembler* barrier_set_assembler,
BarrierSetC1* barrier_set_c1,
const BarrierSet::FakeRtti& fake_rtti)
: BarrierSet(barrier_set_assembler,
barrier_set_c1,
fake_rtti.add_tag(BarrierSet::ModRef)) { }
~ModRefBarrierSet() { }

View File

@ -980,31 +980,6 @@ namespace AccessInternal {
}
};
// This class adds implied decorators that follow according to decorator rules.
// For example adding default reference strength and default memory ordering
// semantics.
template <DecoratorSet input_decorators>
struct DecoratorFixup: AllStatic {
// If no reference strength has been picked, then strong will be picked
static const DecoratorSet ref_strength_default = input_decorators |
(((ON_DECORATOR_MASK & input_decorators) == 0 && (INTERNAL_VALUE_IS_OOP & input_decorators) != 0) ?
ON_STRONG_OOP_REF : INTERNAL_EMPTY);
// If no memory ordering has been picked, unordered will be picked
static const DecoratorSet memory_ordering_default = ref_strength_default |
((MO_DECORATOR_MASK & ref_strength_default) == 0 ? MO_UNORDERED : INTERNAL_EMPTY);
// If no barrier strength has been picked, normal will be used
static const DecoratorSet barrier_strength_default = memory_ordering_default |
((AS_DECORATOR_MASK & memory_ordering_default) == 0 ? AS_NORMAL : INTERNAL_EMPTY);
// Heap array accesses imply it is a heap access
static const DecoratorSet heap_array_is_in_heap = barrier_strength_default |
((IN_HEAP_ARRAY & barrier_strength_default) != 0 ? IN_HEAP : INTERNAL_EMPTY);
static const DecoratorSet conc_root_is_root = heap_array_is_in_heap |
((IN_CONCURRENT_ROOT & heap_array_is_in_heap) != 0 ? IN_ROOT : INTERNAL_EMPTY);
static const DecoratorSet archive_root_is_root = conc_root_is_root |
((IN_ARCHIVE_ROOT & conc_root_is_root) != 0 ? IN_ROOT : INTERNAL_EMPTY);
static const DecoratorSet value = archive_root_is_root | BT_BUILDTIME_DECORATORS;
};
// Step 2: Reduce types.
// Enforce that for non-oop types, T and P have to be strictly the same.
// P is the type of the address and T is the type of the values.

View File

@ -25,6 +25,11 @@
#ifndef SHARE_OOPS_ACCESSDECORATORS_HPP
#define SHARE_OOPS_ACCESSDECORATORS_HPP
#include "gc/shared/barrierSetConfig.hpp"
#include "memory/allocation.hpp"
#include "metaprogramming/integralConstant.hpp"
#include "utilities/globalDefinitions.hpp"
// A decorator is an attribute or property that affects the way a memory access is performed in some way.
// There are different groups of decorators. Some have to do with memory ordering, others to do with,
// e.g. strength of references, strength of GC barriers, or whether compression should be applied or not.
@ -216,4 +221,58 @@ const DecoratorSet ARRAYCOPY_DECORATOR_MASK = ARRAYCOPY_CHECKCAST | ARRAYC
ARRAYCOPY_DISJOINT | ARRAYCOPY_ARRAYOF |
ARRAYCOPY_ATOMIC | ARRAYCOPY_ALIGNED;
// Keep track of the last decorator.
const DecoratorSet DECORATOR_LAST = UCONST64(1) << 30;
namespace AccessInternal {
// This class adds implied decorators that follow according to decorator rules.
// For example adding default reference strength and default memory ordering
// semantics.
template <DecoratorSet input_decorators>
struct DecoratorFixup: AllStatic {
// If no reference strength has been picked, then strong will be picked
static const DecoratorSet ref_strength_default = input_decorators |
(((ON_DECORATOR_MASK & input_decorators) == 0 && (INTERNAL_VALUE_IS_OOP & input_decorators) != 0) ?
ON_STRONG_OOP_REF : INTERNAL_EMPTY);
// If no memory ordering has been picked, unordered will be picked
static const DecoratorSet memory_ordering_default = ref_strength_default |
((MO_DECORATOR_MASK & ref_strength_default) == 0 ? MO_UNORDERED : INTERNAL_EMPTY);
// If no barrier strength has been picked, normal will be used
static const DecoratorSet barrier_strength_default = memory_ordering_default |
((AS_DECORATOR_MASK & memory_ordering_default) == 0 ? AS_NORMAL : INTERNAL_EMPTY);
// Heap array accesses imply it is a heap access
static const DecoratorSet heap_array_is_in_heap = barrier_strength_default |
((IN_HEAP_ARRAY & barrier_strength_default) != 0 ? IN_HEAP : INTERNAL_EMPTY);
static const DecoratorSet conc_root_is_root = heap_array_is_in_heap |
((IN_CONCURRENT_ROOT & heap_array_is_in_heap) != 0 ? IN_ROOT : INTERNAL_EMPTY);
static const DecoratorSet archive_root_is_root = conc_root_is_root |
((IN_ARCHIVE_ROOT & conc_root_is_root) != 0 ? IN_ROOT : INTERNAL_EMPTY);
static const DecoratorSet value = archive_root_is_root | BT_BUILDTIME_DECORATORS;
};
// This function implements the above DecoratorFixup rules, but without meta
// programming for code generation that does not use templates.
inline DecoratorSet decorator_fixup(DecoratorSet input_decorators) {
// If no reference strength has been picked, then strong will be picked
DecoratorSet ref_strength_default = input_decorators |
(((ON_DECORATOR_MASK & input_decorators) == 0 && (INTERNAL_VALUE_IS_OOP & input_decorators) != 0) ?
ON_STRONG_OOP_REF : INTERNAL_EMPTY);
// If no memory ordering has been picked, unordered will be picked
DecoratorSet memory_ordering_default = ref_strength_default |
((MO_DECORATOR_MASK & ref_strength_default) == 0 ? MO_UNORDERED : INTERNAL_EMPTY);
// If no barrier strength has been picked, normal will be used
DecoratorSet barrier_strength_default = memory_ordering_default |
((AS_DECORATOR_MASK & memory_ordering_default) == 0 ? AS_NORMAL : INTERNAL_EMPTY);
// Heap array accesses imply it is a heap access
DecoratorSet heap_array_is_in_heap = barrier_strength_default |
((IN_HEAP_ARRAY & barrier_strength_default) != 0 ? IN_HEAP : INTERNAL_EMPTY);
DecoratorSet conc_root_is_root = heap_array_is_in_heap |
((IN_CONCURRENT_ROOT & heap_array_is_in_heap) != 0 ? IN_ROOT : INTERNAL_EMPTY);
DecoratorSet archive_root_is_root = conc_root_is_root |
((IN_ARCHIVE_ROOT & conc_root_is_root) != 0 ? IN_ROOT : INTERNAL_EMPTY);
DecoratorSet value = archive_root_is_root | BT_BUILDTIME_DECORATORS;
return value;
}
}
#endif // SHARE_OOPS_ACCESSDECORATORS_HPP

View File

@ -206,8 +206,10 @@
#define TIERED
#endif
#define COMPILER1_PRESENT(code) code
#define NOT_COMPILER1(code)
#else // COMPILER1
#define COMPILER1_PRESENT(code)
#define NOT_COMPILER1(code) code
#endif // COMPILER1
// COMPILER2 variant