8201786: Modularize interpreter GC barriers: leftovers for ARM32

Reviewed-by: enevill, eosterlund
This commit is contained in:
Aleksey Shipilev 2018-05-02 19:26:42 +02:00
parent 62d87665eb
commit 078b80e63c
15 changed files with 580 additions and 475 deletions

View file

@ -28,6 +28,7 @@
#include "gc/g1/g1BarrierSetAssembler.hpp" #include "gc/g1/g1BarrierSetAssembler.hpp"
#include "gc/g1/g1ThreadLocalData.hpp" #include "gc/g1/g1ThreadLocalData.hpp"
#include "gc/g1/g1CardTable.hpp" #include "gc/g1/g1CardTable.hpp"
#include "gc/g1/g1ThreadLocalData.hpp"
#include "gc/g1/heapRegion.hpp" #include "gc/g1/heapRegion.hpp"
#include "interpreter/interp_masm.hpp" #include "interpreter/interp_masm.hpp"
#include "runtime/sharedRuntime.hpp" #include "runtime/sharedRuntime.hpp"
@ -127,6 +128,239 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas
#endif // !AARCH64 #endif // !AARCH64
} }
// G1 pre-barrier.
// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
// If store_addr != noreg, then previous value is loaded from [store_addr];
// in such case store_addr and new_val registers are preserved;
// otherwise pre_val register is preserved.
void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
Register store_addr,
Register new_val,
Register pre_val,
Register tmp1,
Register tmp2) {
Label done;
Label runtime;
if (store_addr != noreg) {
assert_different_registers(store_addr, new_val, pre_val, tmp1, tmp2, noreg);
} else {
assert (new_val == noreg, "should be");
assert_different_registers(pre_val, tmp1, tmp2, noreg);
}
Address in_progress(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
Address index(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
Address buffer(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
// Is marking active?
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "adjust this code");
__ ldrb(tmp1, in_progress);
__ cbz(tmp1, done);
// Do we need to load the previous value?
if (store_addr != noreg) {
__ load_heap_oop(pre_val, Address(store_addr, 0));
}
// Is the previous value null?
__ cbz(pre_val, done);
// Can we store original value in the thread's buffer?
// Is index == 0?
// (The index field is typed as size_t.)
__ ldr(tmp1, index); // tmp1 := *index_adr
__ ldr(tmp2, buffer);
__ subs(tmp1, tmp1, wordSize); // tmp1 := tmp1 - wordSize
__ b(runtime, lt); // If negative, goto runtime
__ str(tmp1, index); // *index_adr := tmp1
// Record the previous value
__ str(pre_val, Address(tmp2, tmp1));
__ b(done);
__ bind(runtime);
// save the live input values
#ifdef AARCH64
if (store_addr != noreg) {
__ raw_push(store_addr, new_val);
} else {
__ raw_push(pre_val, ZR);
}
#else
if (store_addr != noreg) {
// avoid raw_push to support any ordering of store_addr and new_val
__ push(RegisterSet(store_addr) | RegisterSet(new_val));
} else {
__ push(pre_val);
}
#endif // AARCH64
if (pre_val != R0) {
__ mov(R0, pre_val);
}
__ mov(R1, Rthread);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), R0, R1);
#ifdef AARCH64
if (store_addr != noreg) {
__ raw_pop(store_addr, new_val);
} else {
__ raw_pop(pre_val, ZR);
}
#else
if (store_addr != noreg) {
__ pop(RegisterSet(store_addr) | RegisterSet(new_val));
} else {
__ pop(pre_val);
}
#endif // AARCH64
__ bind(done);
}
// G1 post-barrier.
// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
Register store_addr,
Register new_val,
Register tmp1,
Register tmp2,
Register tmp3) {
Address queue_index(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
Address buffer(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
BarrierSet* bs = BarrierSet::barrier_set();
CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
CardTable* ct = ctbs->card_table();
Label done;
Label runtime;
// Does store cross heap regions?
__ eor(tmp1, store_addr, new_val);
#ifdef AARCH64
__ logical_shift_right(tmp1, tmp1, HeapRegion::LogOfHRGrainBytes);
__ cbz(tmp1, done);
#else
__ movs(tmp1, AsmOperand(tmp1, lsr, HeapRegion::LogOfHRGrainBytes));
__ b(done, eq);
#endif
// crosses regions, storing NULL?
__ cbz(new_val, done);
// storing region crossing non-NULL, is card already dirty?
const Register card_addr = tmp1;
assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
__ mov_address(tmp2, (address)ct->byte_map_base(), symbolic_Relocation::card_table_reference);
__ add(card_addr, tmp2, AsmOperand(store_addr, lsr, CardTable::card_shift));
__ ldrb(tmp2, Address(card_addr));
__ cmp(tmp2, (int)G1CardTable::g1_young_card_val());
__ b(done, eq);
__ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp2);
assert(CardTable::dirty_card_val() == 0, "adjust this code");
__ ldrb(tmp2, Address(card_addr));
__ cbz(tmp2, done);
// storing a region crossing, non-NULL oop, card is clean.
// dirty card and log.
__ strb(__ zero_register(tmp2), Address(card_addr));
__ ldr(tmp2, queue_index);
__ ldr(tmp3, buffer);
__ subs(tmp2, tmp2, wordSize);
__ b(runtime, lt); // go to runtime if now negative
__ str(tmp2, queue_index);
__ str(card_addr, Address(tmp3, tmp2));
__ b(done);
__ bind(runtime);
if (card_addr != R0) {
__ mov(R0, card_addr);
}
__ mov(R1, Rthread);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), R0, R1);
__ bind(done);
}
void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register dst, Address src, Register tmp1, Register tmp2, Register tmp3) {
bool on_oop = type == T_OBJECT || type == T_ARRAY;
bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0;
bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0;
bool on_reference = on_weak || on_phantom;
ModRefBarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp2, tmp3);
if (on_oop && on_reference) {
// Generate the G1 pre-barrier code to log the value of
// the referent field in an SATB buffer.
g1_write_barrier_pre(masm, noreg, noreg, dst, tmp1, tmp2);
}
}
void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, bool is_null) {
bool in_heap = (decorators & IN_HEAP) != 0;
bool in_concurrent_root = (decorators & IN_CONCURRENT_ROOT) != 0;
bool needs_pre_barrier = in_heap || in_concurrent_root;
bool needs_post_barrier = (new_val != noreg) && in_heap;
// flatten object address if needed
assert (obj.mode() == basic_offset, "pre- or post-indexing is not supported here");
const Register store_addr = obj.base();
if (obj.index() != noreg) {
assert (obj.disp() == 0, "index or displacement, not both");
#ifdef AARCH64
__ add(store_addr, obj.base(), obj.index(), obj.extend(), obj.shift_imm());
#else
assert(obj.offset_op() == add_offset, "addition is expected");
__ add(store_addr, obj.base(), AsmOperand(obj.index(), obj.shift(), obj.shift_imm()));
#endif // AARCH64
} else if (obj.disp() != 0) {
__ add(store_addr, obj.base(), obj.disp());
}
if (needs_pre_barrier) {
g1_write_barrier_pre(masm, store_addr, new_val, tmp1, tmp2, tmp3);
}
if (is_null) {
BarrierSetAssembler::store_at(masm, decorators, type, Address(store_addr), new_val, tmp1, tmp2, tmp3, true);
} else {
// G1 barrier needs uncompressed oop for region cross check.
Register val_to_store = new_val;
if (UseCompressedOops) {
val_to_store = tmp1;
__ mov(val_to_store, new_val);
}
BarrierSetAssembler::store_at(masm, decorators, type, Address(store_addr), val_to_store, tmp1, tmp2, tmp3, false);
if (needs_post_barrier) {
g1_write_barrier_post(masm, store_addr, new_val, tmp1, tmp2, tmp3);
}
}
};
#ifdef COMPILER1 #ifdef COMPILER1
#undef __ #undef __

View file

@ -41,6 +41,27 @@ protected:
void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register addr, Register count, Register tmp); Register addr, Register count, Register tmp);
void g1_write_barrier_pre(MacroAssembler* masm,
Register store_addr,
Register new_val,
Register pre_val,
Register tmp1,
Register tmp2);
void g1_write_barrier_post(MacroAssembler* masm,
Register store_addr,
Register new_val,
Register tmp1,
Register tmp2,
Register tmp3);
virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, bool is_null);
public:
virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register dst, Address src, Register tmp1, Register tmp2, Register tmp3);
#ifdef COMPILER1 #ifdef COMPILER1
public: public:
void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub); void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);

View file

@ -0,0 +1,87 @@
/*
* 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/barrierSetAssembler.hpp"
#define __ masm->
void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register dst, Address src, Register tmp1, Register tmp2, Register tmp3) {
bool on_heap = (decorators & IN_HEAP) != 0;
bool on_root = (decorators & IN_ROOT) != 0;
switch (type) {
case T_OBJECT:
case T_ARRAY: {
if (on_heap) {
#ifdef AARCH64
if (UseCompressedOops) {
__ ldr_w(dst, src);
__ decode_heap_oop(dst);
} else
#endif // AARCH64
{
__ ldr(dst, src);
}
} else {
assert(on_root, "why else?");
__ ldr(dst, src);
}
break;
}
default: Unimplemented();
}
}
void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Address obj, Register val, Register tmp1, Register tmp2, Register tmp3, bool is_null) {
bool on_heap = (decorators & IN_HEAP) != 0;
bool on_root = (decorators & IN_ROOT) != 0;
switch (type) {
case T_OBJECT:
case T_ARRAY: {
if (on_heap) {
#ifdef AARCH64
if (UseCompressedOops) {
assert(!dst.uses(src), "not enough registers");
if (!is_null) {
__ encode_heap_oop(src);
}
__ str_w(val, obj);
} else
#endif // AARCH64
{
__ str(val, obj);
}
} else {
assert(on_root, "why else?");
__ str(val, obj);
}
break;
}
default: Unimplemented();
}
}

View file

@ -36,6 +36,11 @@ public:
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
Register addr, Register count, Register tmp) {} Register addr, Register count, Register tmp) {}
virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register dst, Address src, Register tmp1, Register tmp2, Register tmp3);
virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, bool is_null);
virtual void barrier_stubs_init() {} virtual void barrier_stubs_init() {}
}; };

View file

@ -72,3 +72,107 @@ void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembl
__ b(L_cardtable_loop, ge); __ b(L_cardtable_loop, ge);
__ BIND(L_done); __ BIND(L_done);
} }
void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, bool is_null) {
bool on_array = (decorators & IN_HEAP_ARRAY) != 0;
bool on_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0;
bool precise = on_array || on_anonymous;
if (is_null) {
BarrierSetAssembler::store_at(masm, decorators, type, obj, new_val, tmp1, tmp2, tmp3, true);
} else {
assert (!precise || (obj.index() == noreg && obj.disp() == 0),
"store check address should be calculated beforehand");
store_check_part1(masm, tmp1);
BarrierSetAssembler::store_at(masm, decorators, type, obj, new_val, tmp1, tmp2, tmp3, false);
new_val = noreg;
store_check_part2(masm, obj.base(), tmp1, tmp2);
}
}
// The 1st part of the store check.
// Sets card_table_base register.
void CardTableBarrierSetAssembler::store_check_part1(MacroAssembler* masm, Register card_table_base) {
// Check barrier set type (should be card table) and element size
BarrierSet* bs = BarrierSet::barrier_set();
assert(bs->kind() == BarrierSet::CardTableBarrierSet,
"Wrong barrier set kind");
CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
CardTable* ct = ctbs->card_table();
assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "Adjust store check code");
// Load card table base address.
/* Performance note.
There is an alternative way of loading card table base address
from thread descriptor, which may look more efficient:
ldr(card_table_base, Address(Rthread, JavaThread::card_table_base_offset()));
However, performance measurements of micro benchmarks and specJVM98
showed that loading of card table base from thread descriptor is
7-18% slower compared to loading of literal embedded into the code.
Possible cause is a cache miss (card table base address resides in a
rarely accessed area of thread descriptor).
*/
// TODO-AARCH64 Investigate if mov_slow is faster than ldr from Rthread on AArch64
__ mov_address(card_table_base, (address)ct->byte_map_base(), symbolic_Relocation::card_table_reference);
}
// The 2nd part of the store check.
void CardTableBarrierSetAssembler::store_check_part2(MacroAssembler* masm, Register obj, Register card_table_base, Register tmp) {
assert_different_registers(obj, card_table_base, tmp);
assert(CardTable::dirty_card_val() == 0, "Dirty card value must be 0 due to optimizations.");
#ifdef AARCH64
add(card_table_base, card_table_base, AsmOperand(obj, lsr, CardTable::card_shift));
Address card_table_addr(card_table_base);
#else
Address card_table_addr(card_table_base, obj, lsr, CardTable::card_shift);
#endif
if (UseCondCardMark) {
#if INCLUDE_ALL_GCS
if (UseConcMarkSweepGC) {
__ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), noreg);
}
#endif
Label already_dirty;
__ ldrb(tmp, card_table_addr);
__ cbz(tmp, already_dirty);
set_card(masm, card_table_base, card_table_addr, tmp);
__ bind(already_dirty);
} else {
#if INCLUDE_ALL_GCS
if (UseConcMarkSweepGC && CMSPrecleaningEnabled) {
__ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore), noreg);
}
#endif
set_card(masm, card_table_base, card_table_addr, tmp);
}
}
void CardTableBarrierSetAssembler::set_card(MacroAssembler* masm, Register card_table_base, Address card_table_addr, Register tmp) {
#ifdef AARCH64
strb(ZR, card_table_addr);
#else
CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
CardTable* ct = ctbs->card_table();
if ((((uintptr_t)ct->byte_map_base() & 0xff) == 0)) {
// Card table is aligned so the lowest byte of the table address base is zero.
// This works only if the code is not saved for later use, possibly
// in a context where the base would no longer be aligned.
__ strb(card_table_base, card_table_addr);
} else {
__ mov(tmp, 0);
__ strb(tmp, card_table_addr);
}
#endif // AARCH64
}

View file

@ -29,9 +29,18 @@
#include "gc/shared/modRefBarrierSetAssembler.hpp" #include "gc/shared/modRefBarrierSetAssembler.hpp"
class CardTableBarrierSetAssembler: public ModRefBarrierSetAssembler { class CardTableBarrierSetAssembler: public ModRefBarrierSetAssembler {
private:
void store_check(MacroAssembler* masm, Register obj, Address dst);
void store_check_part1(MacroAssembler* masm, Register card_table_base);
void store_check_part2(MacroAssembler* masm, Register obj, Register card_table_base, Register tmp);
void set_card(MacroAssembler* masm, Register card_table_base, Address card_table_addr, Register tmp);
protected: protected:
virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register addr, Register count, Register tmp); Register addr, Register count, Register tmp);
virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, bool is_null);
}; };
#endif // #ifndef CPU_ARM_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_ARM_HPP #endif // #ifndef CPU_ARM_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_ARM_HPP

View file

@ -42,3 +42,12 @@ void ModRefBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, Decorat
gen_write_ref_array_post_barrier(masm, decorators, addr, count, tmp); gen_write_ref_array_post_barrier(masm, decorators, addr, count, tmp);
} }
} }
void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, bool is_null) {
if (type == T_OBJECT || type == T_ARRAY) {
oop_store_at(masm, decorators, type, obj, new_val, tmp1, tmp2, tmp3, is_null);
} else {
BarrierSetAssembler::store_at(masm, decorators, type, obj, new_val, tmp1, tmp2, tmp3, is_null);
}
}

View file

@ -28,6 +28,10 @@
#include "asm/macroAssembler.hpp" #include "asm/macroAssembler.hpp"
#include "gc/shared/barrierSetAssembler.hpp" #include "gc/shared/barrierSetAssembler.hpp"
// The ModRefBarrierSetAssembler 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 ModRefBarrierSetAssembler: public BarrierSetAssembler { class ModRefBarrierSetAssembler: public BarrierSetAssembler {
protected: protected:
virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators,
@ -35,11 +39,16 @@ protected:
virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register addr, Register count, Register tmp) {} Register addr, Register count, Register tmp) {}
virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Address obj, Register val, Register tmp1, Register tmp2, Register tmp3, bool is_null) = 0;
public: public:
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
Register addr, Register count, int callee_saved_regs); Register addr, Register count, int callee_saved_regs);
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
Register addr, Register count, Register tmp); Register addr, Register count, Register tmp);
virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Address obj, Register val, Register tmp1, Register tmp2, Register tmp3, bool is_null);
}; };
#endif // CPU_ARM_GC_SHARED_MODREFBARRIERSETASSEMBLER_ARM_HPP #endif // CPU_ARM_GC_SHARED_MODREFBARRIERSETASSEMBLER_ARM_HPP

View file

@ -406,91 +406,6 @@ void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass,
} }
// The 1st part of the store check.
// Sets card_table_base register.
void InterpreterMacroAssembler::store_check_part1(Register card_table_base) {
// Check barrier set type (should be card table) and element size
BarrierSet* bs = BarrierSet::barrier_set();
assert(bs->kind() == BarrierSet::CardTableBarrierSet,
"Wrong barrier set kind");
CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
CardTable* ct = ctbs->card_table();
assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "Adjust store check code");
// Load card table base address.
/* Performance note.
There is an alternative way of loading card table base address
from thread descriptor, which may look more efficient:
ldr(card_table_base, Address(Rthread, JavaThread::card_table_base_offset()));
However, performance measurements of micro benchmarks and specJVM98
showed that loading of card table base from thread descriptor is
7-18% slower compared to loading of literal embedded into the code.
Possible cause is a cache miss (card table base address resides in a
rarely accessed area of thread descriptor).
*/
// TODO-AARCH64 Investigate if mov_slow is faster than ldr from Rthread on AArch64
mov_address(card_table_base, (address)ct->byte_map_base(), symbolic_Relocation::card_table_reference);
}
// The 2nd part of the store check.
void InterpreterMacroAssembler::store_check_part2(Register obj, Register card_table_base, Register tmp) {
assert_different_registers(obj, card_table_base, tmp);
assert(CardTable::dirty_card_val() == 0, "Dirty card value must be 0 due to optimizations.");
#ifdef AARCH64
add(card_table_base, card_table_base, AsmOperand(obj, lsr, CardTable::card_shift));
Address card_table_addr(card_table_base);
#else
Address card_table_addr(card_table_base, obj, lsr, CardTable::card_shift);
#endif
if (UseCondCardMark) {
#if INCLUDE_ALL_GCS
if (UseConcMarkSweepGC) {
membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), noreg);
}
#endif
Label already_dirty;
ldrb(tmp, card_table_addr);
cbz(tmp, already_dirty);
set_card(card_table_base, card_table_addr, tmp);
bind(already_dirty);
} else {
#if INCLUDE_ALL_GCS
if (UseConcMarkSweepGC && CMSPrecleaningEnabled) {
membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore), noreg);
}
#endif
set_card(card_table_base, card_table_addr, tmp);
}
}
void InterpreterMacroAssembler::set_card(Register card_table_base, Address card_table_addr, Register tmp) {
#ifdef AARCH64
strb(ZR, card_table_addr);
#else
CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
CardTable* ct = ctbs->card_table();
if ((((uintptr_t)ct->byte_map_base() & 0xff) == 0)) {
// Card table is aligned so the lowest byte of the table address base is zero.
// This works only if the code is not saved for later use, possibly
// in a context where the base would no longer be aligned.
strb(card_table_base, card_table_addr);
} else {
mov(tmp, 0);
strb(tmp, card_table_addr);
}
#endif // AARCH64
}
////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////

View file

@ -144,11 +144,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
// load cpool->resolved_klass_at(index); Rtemp is corrupted upon return // load cpool->resolved_klass_at(index); Rtemp is corrupted upon return
void load_resolved_klass_at_offset(Register Rcpool, Register Rindex, Register Rklass); void load_resolved_klass_at_offset(Register Rcpool, Register Rindex, Register Rklass);
void store_check_part1(Register card_table_base); // Sets card_table_base register.
void store_check_part2(Register obj, Register card_table_base, Register tmp);
void set_card(Register card_table_base, Address card_table_addr, Register tmp);
void pop_ptr(Register r); void pop_ptr(Register r);
void pop_i(Register r = R0_tos); void pop_i(Register r = R0_tos);
#ifdef AARCH64 #ifdef AARCH64

View file

@ -31,6 +31,7 @@
#include "compiler/disassembler.hpp" #include "compiler/disassembler.hpp"
#include "gc/shared/barrierSet.hpp" #include "gc/shared/barrierSet.hpp"
#include "gc/shared/cardTable.hpp" #include "gc/shared/cardTable.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
#include "gc/shared/cardTableBarrierSet.hpp" #include "gc/shared/cardTableBarrierSet.hpp"
#include "gc/shared/collectedHeap.inline.hpp" #include "gc/shared/collectedHeap.inline.hpp"
#include "interpreter/interpreter.hpp" #include "interpreter/interpreter.hpp"
@ -44,12 +45,6 @@
#include "runtime/sharedRuntime.hpp" #include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp" #include "runtime/stubRoutines.hpp"
#include "utilities/macros.hpp" #include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CardTable.hpp"
#include "gc/g1/g1ThreadLocalData.hpp"
#include "gc/g1/heapRegion.hpp"
#endif
// Implementation of AddressLiteral // Implementation of AddressLiteral
@ -2131,204 +2126,20 @@ void MacroAssembler::resolve_jobject(Register value,
cbz(value, done); // Use NULL as-is. cbz(value, done); // Use NULL as-is.
STATIC_ASSERT(JNIHandles::weak_tag_mask == 1u); STATIC_ASSERT(JNIHandles::weak_tag_mask == 1u);
tbz(value, 0, not_weak); // Test for jweak tag. tbz(value, 0, not_weak); // Test for jweak tag.
// Resolve jweak. // Resolve jweak.
ldr(value, Address(value, -JNIHandles::weak_tag_value)); access_load_at(T_OBJECT, IN_ROOT | ON_PHANTOM_OOP_REF,
verify_oop(value); Address(value, -JNIHandles::weak_tag_value), value, tmp1, tmp2, noreg);
#if INCLUDE_ALL_GCS
if (UseG1GC) {
g1_write_barrier_pre(noreg, // store_addr
noreg, // new_val
value, // pre_val
tmp1, // tmp1
tmp2); // tmp2
}
#endif // INCLUDE_ALL_GCS
b(done); b(done);
bind(not_weak); bind(not_weak);
// Resolve (untagged) jobject. // Resolve (untagged) jobject.
ldr(value, Address(value)); access_load_at(T_OBJECT, IN_ROOT | IN_CONCURRENT_ROOT,
Address(value, 0), value, tmp1, tmp2, noreg);
verify_oop(value); verify_oop(value);
bind(done); bind(done);
} }
//////////////////////////////////////////////////////////////////////////////////
#if INCLUDE_ALL_GCS
// G1 pre-barrier.
// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
// If store_addr != noreg, then previous value is loaded from [store_addr];
// in such case store_addr and new_val registers are preserved;
// otherwise pre_val register is preserved.
void MacroAssembler::g1_write_barrier_pre(Register store_addr,
Register new_val,
Register pre_val,
Register tmp1,
Register tmp2) {
Label done;
Label runtime;
if (store_addr != noreg) {
assert_different_registers(store_addr, new_val, pre_val, tmp1, tmp2, noreg);
} else {
assert (new_val == noreg, "should be");
assert_different_registers(pre_val, tmp1, tmp2, noreg);
}
Address in_progress(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
Address index(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
Address buffer(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
// Is marking active?
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "adjust this code");
ldrb(tmp1, in_progress);
cbz(tmp1, done);
// Do we need to load the previous value?
if (store_addr != noreg) {
load_heap_oop(pre_val, Address(store_addr, 0));
}
// Is the previous value null?
cbz(pre_val, done);
// Can we store original value in the thread's buffer?
// Is index == 0?
// (The index field is typed as size_t.)
ldr(tmp1, index); // tmp1 := *index_adr
ldr(tmp2, buffer);
subs(tmp1, tmp1, wordSize); // tmp1 := tmp1 - wordSize
b(runtime, lt); // If negative, goto runtime
str(tmp1, index); // *index_adr := tmp1
// Record the previous value
str(pre_val, Address(tmp2, tmp1));
b(done);
bind(runtime);
// save the live input values
#ifdef AARCH64
if (store_addr != noreg) {
raw_push(store_addr, new_val);
} else {
raw_push(pre_val, ZR);
}
#else
if (store_addr != noreg) {
// avoid raw_push to support any ordering of store_addr and new_val
push(RegisterSet(store_addr) | RegisterSet(new_val));
} else {
push(pre_val);
}
#endif // AARCH64
if (pre_val != R0) {
mov(R0, pre_val);
}
mov(R1, Rthread);
call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), R0, R1);
#ifdef AARCH64
if (store_addr != noreg) {
raw_pop(store_addr, new_val);
} else {
raw_pop(pre_val, ZR);
}
#else
if (store_addr != noreg) {
pop(RegisterSet(store_addr) | RegisterSet(new_val));
} else {
pop(pre_val);
}
#endif // AARCH64
bind(done);
}
// G1 post-barrier.
// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
void MacroAssembler::g1_write_barrier_post(Register store_addr,
Register new_val,
Register tmp1,
Register tmp2,
Register tmp3) {
Address queue_index(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
Address buffer(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
BarrierSet* bs = BarrierSet::barrier_set();
CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
CardTable* ct = ctbs->card_table();
Label done;
Label runtime;
// Does store cross heap regions?
eor(tmp1, store_addr, new_val);
#ifdef AARCH64
logical_shift_right(tmp1, tmp1, HeapRegion::LogOfHRGrainBytes);
cbz(tmp1, done);
#else
movs(tmp1, AsmOperand(tmp1, lsr, HeapRegion::LogOfHRGrainBytes));
b(done, eq);
#endif
// crosses regions, storing NULL?
cbz(new_val, done);
// storing region crossing non-NULL, is card already dirty?
const Register card_addr = tmp1;
assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
mov_address(tmp2, (address)ct->byte_map_base(), symbolic_Relocation::card_table_reference);
add(card_addr, tmp2, AsmOperand(store_addr, lsr, CardTable::card_shift));
ldrb(tmp2, Address(card_addr));
cmp(tmp2, (int)G1CardTable::g1_young_card_val());
b(done, eq);
membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp2);
assert(CardTable::dirty_card_val() == 0, "adjust this code");
ldrb(tmp2, Address(card_addr));
cbz(tmp2, done);
// storing a region crossing, non-NULL oop, card is clean.
// dirty card and log.
strb(zero_register(tmp2), Address(card_addr));
ldr(tmp2, queue_index);
ldr(tmp3, buffer);
subs(tmp2, tmp2, wordSize);
b(runtime, lt); // go to runtime if now negative
str(tmp2, queue_index);
str(card_addr, Address(tmp3, tmp2));
b(done);
bind(runtime);
if (card_addr != R0) {
mov(R0, card_addr);
}
mov(R1, Rthread);
call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), R0, R1);
bind(done);
}
#endif // INCLUDE_ALL_GCS
////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////
#ifdef AARCH64 #ifdef AARCH64
@ -2873,38 +2684,39 @@ void MacroAssembler::store_klass_gap(Register dst) {
#endif // AARCH64 #endif // AARCH64
void MacroAssembler::load_heap_oop(Register dst, Address src) { void MacroAssembler::load_heap_oop(Register dst, Address src, Register tmp1, Register tmp2, Register tmp3, DecoratorSet decorators) {
#ifdef AARCH64 access_load_at(T_OBJECT, IN_HEAP | decorators, src, dst, tmp1, tmp2, tmp3);
if (UseCompressedOops) {
ldr_w(dst, src);
decode_heap_oop(dst);
return;
}
#endif // AARCH64
ldr(dst, src);
} }
// Blows src and flags. // Blows src and flags.
void MacroAssembler::store_heap_oop(Register src, Address dst) { void MacroAssembler::store_heap_oop(Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, DecoratorSet decorators) {
#ifdef AARCH64 access_store_at(T_OBJECT, IN_HEAP | decorators, obj, new_val, tmp1, tmp2, tmp3, false);
if (UseCompressedOops) {
assert(!dst.uses(src), "not enough registers");
encode_heap_oop(src);
str_w(src, dst);
return;
}
#endif // AARCH64
str(src, dst);
} }
void MacroAssembler::store_heap_oop_null(Register src, Address dst) { void MacroAssembler::store_heap_oop_null(Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, DecoratorSet decorators) {
#ifdef AARCH64 access_store_at(T_OBJECT, IN_HEAP, obj, new_val, tmp1, tmp2, tmp3, true);
if (UseCompressedOops) { }
str_w(src, dst);
return; void MacroAssembler::access_load_at(BasicType type, DecoratorSet decorators,
Address src, Register dst, Register tmp1, Register tmp2, Register tmp3) {
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
bool as_raw = (decorators & AS_RAW) != 0;
if (as_raw) {
bs->BarrierSetAssembler::load_at(this, decorators, type, dst, src, tmp1, tmp2, tmp3);
} else {
bs->load_at(this, decorators, type, dst, src, tmp1, tmp2, tmp3);
}
}
void MacroAssembler::access_store_at(BasicType type, DecoratorSet decorators,
Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, bool is_null) {
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
bool as_raw = (decorators & AS_RAW) != 0;
if (as_raw) {
bs->BarrierSetAssembler::store_at(this, decorators, type, obj, new_val, tmp1, tmp2, tmp3, is_null);
} else {
bs->store_at(this, decorators, type, obj, new_val, tmp1, tmp2, tmp3, is_null);
} }
#endif // AARCH64
str(src, dst);
} }

View file

@ -401,27 +401,6 @@ public:
void resolve_jobject(Register value, Register tmp1, Register tmp2); void resolve_jobject(Register value, Register tmp1, Register tmp2);
#if INCLUDE_ALL_GCS
// G1 pre-barrier.
// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
// If store_addr != noreg, then previous value is loaded from [store_addr];
// in such case store_addr and new_val registers are preserved;
// otherwise pre_val register is preserved.
void g1_write_barrier_pre(Register store_addr,
Register new_val,
Register pre_val,
Register tmp1,
Register tmp2);
// G1 post-barrier.
// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
void g1_write_barrier_post(Register store_addr,
Register new_val,
Register tmp1,
Register tmp2,
Register tmp3);
#endif // INCLUDE_ALL_GCS
#ifndef AARCH64 #ifndef AARCH64
void nop() { void nop() {
mov(R0, R0); mov(R0, R0);
@ -1072,12 +1051,12 @@ public:
// oop manipulations // oop manipulations
void load_heap_oop(Register dst, Address src); void load_heap_oop(Register dst, Address src, Register tmp1 = noreg, Register tmp2 = noreg, Register tmp3 = noreg, DecoratorSet decorators = 0);
void store_heap_oop(Register src, Address dst); void store_heap_oop(Address obj, Register new_val, Register tmp1 = noreg, Register tmp2 = noreg, Register tmp3 = noreg, DecoratorSet decorators = 0);
void store_heap_oop(Address dst, Register src) { void store_heap_oop_null(Address obj, Register new_val, Register tmp1 = noreg, Register tmp2 = noreg, Register tmp3 = noreg, DecoratorSet decorators = 0);
store_heap_oop(src, dst);
} void access_load_at(BasicType type, DecoratorSet decorators, Address src, Register dst, Register tmp1, Register tmp2, Register tmp3);
void store_heap_oop_null(Register src, Address dst); void access_store_at(BasicType type, DecoratorSet decorators, Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, bool is_null);
#ifdef AARCH64 #ifdef AARCH64
void encode_heap_oop(Register dst, Register src); void encode_heap_oop(Register dst, Register src);

View file

@ -3260,7 +3260,7 @@ class StubGenerator: public StubCodeGenerator {
__ align(OptoLoopAlignment); __ align(OptoLoopAlignment);
__ BIND(store_element); __ BIND(store_element);
if (UseCompressedOops) { if (UseCompressedOops) {
__ store_heap_oop(R5, Address(to, BytesPerHeapOop, post_indexed)); // store the oop, changes flags __ store_heap_oop(Address(to, BytesPerHeapOop, post_indexed), R5); // store the oop, changes flags
__ subs_32(count,count,1); __ subs_32(count,count,1);
} else { } else {
__ subs_32(count,count,1); __ subs_32(count,count,1);

View file

@ -852,80 +852,53 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
// //
address TemplateInterpreterGenerator::generate_Reference_get_entry(void) { address TemplateInterpreterGenerator::generate_Reference_get_entry(void) {
#if INCLUDE_ALL_GCS // Code: _aload_0, _getfield, _areturn
if (UseG1GC) { // parameter size = 1
// Code: _aload_0, _getfield, _areturn //
// parameter size = 1 // The code that gets generated by this routine is split into 2 parts:
// // 1. The "intrinsified" code performing an ON_WEAK_OOP_REF load,
// The code that gets generated by this routine is split into 2 parts: // 2. The slow path - which is an expansion of the regular method entry.
// 1. The "intrinsified" code for G1 (or any SATB based GC), //
// 2. The slow path - which is an expansion of the regular method entry. // Notes:-
// // * An intrinsic is always executed, where an ON_WEAK_OOP_REF load is performed.
// Notes:- // * We may jump to the slow path iff the receiver is null. If the
// * In the G1 code we do not check whether we need to block for // Reference object is null then we no longer perform an ON_WEAK_OOP_REF load
// a safepoint. If G1 is enabled then we must execute the specialized // Thus we can use the regular method entry code to generate the NPE.
// code for Reference.get (except when the Reference object is null) //
// so that we can log the value in the referent field with an SATB // Rmethod: Method*
// update buffer. // Rthread: thread
// If the code for the getfield template is modified so that the // Rsender_sp: sender sp, must be preserved for slow path, set SP to it on fast path
// G1 pre-barrier code is executed when the current method is // Rparams: parameters
// Reference.get() then going through the normal method entry
// will be fine.
// * The G1 code can, however, check the receiver object (the instance
// of java.lang.Reference) and jump to the slow path if null. If the
// Reference object is null then we obviously cannot fetch the referent
// and so we don't need to call the G1 pre-barrier. Thus we can use the
// regular method entry code to generate the NPE.
//
// This code is based on generate_accessor_enty.
//
// Rmethod: Method*
// Rthread: thread
// Rsender_sp: sender sp, must be preserved for slow path, set SP to it on fast path
// Rparams: parameters
address entry = __ pc(); address entry = __ pc();
Label slow_path; Label slow_path;
const Register Rthis = R0; const Register Rthis = R0;
const Register Rret_addr = Rtmp_save1; const Register Rret_addr = Rtmp_save1;
assert_different_registers(Rthis, Rret_addr, Rsender_sp); assert_different_registers(Rthis, Rret_addr, Rsender_sp);
const int referent_offset = java_lang_ref_Reference::referent_offset; const int referent_offset = java_lang_ref_Reference::referent_offset;
guarantee(referent_offset > 0, "referent offset not initialized"); guarantee(referent_offset > 0, "referent offset not initialized");
// Check if local 0 != NULL // Check if local 0 != NULL
// If the receiver is null then it is OK to jump to the slow path. // If the receiver is null then it is OK to jump to the slow path.
__ ldr(Rthis, Address(Rparams)); __ ldr(Rthis, Address(Rparams));
__ cbz(Rthis, slow_path); __ cbz(Rthis, slow_path);
// Generate the G1 pre-barrier code to log the value of // Preserve LR
// the referent field in an SATB buffer. __ mov(Rret_addr, LR);
// Load the value of the referent field. // Load the value of the referent field.
__ load_heap_oop(R0, Address(Rthis, referent_offset)); const Address field_address(Rthis, referent_offset);
__ load_heap_oop(R0, field_address, Rtemp, R1_tmp, R2_tmp, ON_WEAK_OOP_REF);
// Preserve LR // _areturn
__ mov(Rret_addr, LR); __ mov(SP, Rsender_sp);
__ ret(Rret_addr);
__ g1_write_barrier_pre(noreg, // store_addr // generate a vanilla interpreter entry as the slow path
noreg, // new_val __ bind(slow_path);
R0, // pre_val __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals));
Rtemp, // tmp1 return entry;
R1_tmp); // tmp2
// _areturn
__ mov(SP, Rsender_sp);
__ ret(Rret_addr);
// generate a vanilla interpreter entry as the slow path
__ bind(slow_path);
__ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals));
return entry;
}
#endif // INCLUDE_ALL_GCS
// If G1 is not enabled then attempt to go through the normal entry point
return NULL;
} }
// Not supported // Not supported

View file

@ -24,6 +24,7 @@
#include "precompiled.hpp" #include "precompiled.hpp"
#include "asm/macroAssembler.hpp" #include "asm/macroAssembler.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
#include "interpreter/interp_masm.hpp" #include "interpreter/interp_masm.hpp"
#include "interpreter/interpreter.hpp" #include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp" #include "interpreter/interpreterRuntime.hpp"
@ -187,72 +188,24 @@ static void do_oop_store(InterpreterMacroAssembler* _masm,
Register tmp1, Register tmp1,
Register tmp2, Register tmp2,
Register tmp3, Register tmp3,
BarrierSet::Name barrier, bool is_null,
bool precise, DecoratorSet decorators = 0) {
bool is_null) {
assert_different_registers(obj.base(), new_val, tmp1, tmp2, tmp3, noreg); assert_different_registers(obj.base(), new_val, tmp1, tmp2, tmp3, noreg);
switch (barrier) { if (is_null) {
#if INCLUDE_ALL_GCS __ store_heap_oop_null(obj, new_val, tmp1, tmp2, tmp3, decorators);
case BarrierSet::G1BarrierSet: } else {
{ __ store_heap_oop(obj, new_val, tmp1, tmp2, tmp3, decorators);
// flatten object address if needed
assert (obj.mode() == basic_offset, "pre- or post-indexing is not supported here");
const Register store_addr = obj.base();
if (obj.index() != noreg) {
assert (obj.disp() == 0, "index or displacement, not both");
#ifdef AARCH64
__ add(store_addr, obj.base(), obj.index(), obj.extend(), obj.shift_imm());
#else
assert(obj.offset_op() == add_offset, "addition is expected");
__ add(store_addr, obj.base(), AsmOperand(obj.index(), obj.shift(), obj.shift_imm()));
#endif // AARCH64
} else if (obj.disp() != 0) {
__ add(store_addr, obj.base(), obj.disp());
}
__ g1_write_barrier_pre(store_addr, new_val, tmp1, tmp2, tmp3);
if (is_null) {
__ store_heap_oop_null(new_val, Address(store_addr));
} else {
// G1 barrier needs uncompressed oop for region cross check.
Register val_to_store = new_val;
if (UseCompressedOops) {
val_to_store = tmp1;
__ mov(val_to_store, new_val);
}
__ store_heap_oop(val_to_store, Address(store_addr)); // blows val_to_store:
val_to_store = noreg;
__ g1_write_barrier_post(store_addr, new_val, tmp1, tmp2, tmp3);
}
}
break;
#endif // INCLUDE_ALL_GCS
case BarrierSet::CardTableBarrierSet:
{
if (is_null) {
__ store_heap_oop_null(new_val, obj);
} else {
assert (!precise || (obj.index() == noreg && obj.disp() == 0),
"store check address should be calculated beforehand");
__ store_check_part1(tmp1);
__ store_heap_oop(new_val, obj); // blows new_val:
new_val = noreg;
__ store_check_part2(obj.base(), tmp1, tmp2);
}
}
break;
case BarrierSet::ModRef:
ShouldNotReachHere();
break;
default:
ShouldNotReachHere();
break;
} }
} }
static void do_oop_load(InterpreterMacroAssembler* _masm,
Register dst,
Address obj,
DecoratorSet decorators = 0) {
__ load_heap_oop(dst, obj, noreg, noreg, noreg, decorators);
}
Address TemplateTable::at_bcp(int offset) { Address TemplateTable::at_bcp(int offset) {
assert(_desc->uses_bcp(), "inconsistent uses_bcp information"); assert(_desc->uses_bcp(), "inconsistent uses_bcp information");
return Address(Rbcp, offset); return Address(Rbcp, offset);
@ -863,7 +816,7 @@ void TemplateTable::aaload() {
const Register Rindex = R0_tos; const Register Rindex = R0_tos;
index_check(Rarray, Rindex); index_check(Rarray, Rindex);
__ load_heap_oop(R0_tos, get_array_elem_addr(T_OBJECT, Rarray, Rindex, Rtemp)); do_oop_load(_masm, R0_tos, get_array_elem_addr(T_OBJECT, Rarray, Rindex, Rtemp), IN_HEAP_ARRAY);
} }
@ -1248,7 +1201,7 @@ void TemplateTable::aastore() {
__ add(Raddr_1, Raddr_1, AsmOperand(Rindex_4, lsl, LogBytesPerHeapOop)); __ add(Raddr_1, Raddr_1, AsmOperand(Rindex_4, lsl, LogBytesPerHeapOop));
// Now store using the appropriate barrier // Now store using the appropriate barrier
do_oop_store(_masm, Raddr_1, Rvalue_2, Rtemp, R0_tmp, R3_tmp, _bs->kind(), true, false); do_oop_store(_masm, Raddr_1, Rvalue_2, Rtemp, R0_tmp, R3_tmp, false, IN_HEAP_ARRAY);
__ b(done); __ b(done);
__ bind(throw_array_store); __ bind(throw_array_store);
@ -1264,7 +1217,7 @@ void TemplateTable::aastore() {
__ profile_null_seen(R0_tmp); __ profile_null_seen(R0_tmp);
// Store a NULL // Store a NULL
do_oop_store(_masm, Address::indexed_oop(Raddr_1, Rindex_4), Rvalue_2, Rtemp, R0_tmp, R3_tmp, _bs->kind(), true, true); do_oop_store(_masm, Address::indexed_oop(Raddr_1, Rindex_4), Rvalue_2, Rtemp, R0_tmp, R3_tmp, true, IN_HEAP_ARRAY);
// Pop stack arguments // Pop stack arguments
__ bind(done); __ bind(done);
@ -3286,7 +3239,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr
// atos case for AArch64 and slow version on 32-bit ARM // atos case for AArch64 and slow version on 32-bit ARM
if(!atos_merged_with_itos) { if(!atos_merged_with_itos) {
__ bind(Latos); __ bind(Latos);
__ load_heap_oop(R0_tos, Address(Robj, Roffset)); do_oop_load(_masm, R0_tos, Address(Robj, Roffset));
__ push(atos); __ push(atos);
// Rewrite bytecode to be faster // Rewrite bytecode to be faster
if (!is_static && rc == may_rewrite) { if (!is_static && rc == may_rewrite) {
@ -3638,7 +3591,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr
__ pop(atos); __ pop(atos);
if (!is_static) pop_and_check_object(Robj); if (!is_static) pop_and_check_object(Robj);
// Store into the field // Store into the field
do_oop_store(_masm, Address(Robj, Roffset), R0_tos, Rtemp, R1_tmp, R5_tmp, _bs->kind(), false, false); do_oop_store(_masm, Address(Robj, Roffset), R0_tos, Rtemp, R1_tmp, R5_tmp, false);
if (!is_static && rc == may_rewrite) { if (!is_static && rc == may_rewrite) {
patch_bytecode(Bytecodes::_fast_aputfield, R0_tmp, Rtemp, true, byte_no); patch_bytecode(Bytecodes::_fast_aputfield, R0_tmp, Rtemp, true, byte_no);
} }
@ -3816,7 +3769,7 @@ void TemplateTable::fast_storefield(TosState state) {
#endif // AARCH64 #endif // AARCH64
case Bytecodes::_fast_aputfield: case Bytecodes::_fast_aputfield:
do_oop_store(_masm, Address(Robj, Roffset), R0_tos, Rtemp, R1_tmp, R2_tmp, _bs->kind(), false, false); do_oop_store(_masm, Address(Robj, Roffset), R0_tos, Rtemp, R1_tmp, R2_tmp, false);
break; break;
default: default:
@ -3912,7 +3865,7 @@ void TemplateTable::fast_accessfield(TosState state) {
case Bytecodes::_fast_dgetfield: __ add(Roffset, Robj, Roffset); __ fldd(D0_tos, Address(Roffset)); break; case Bytecodes::_fast_dgetfield: __ add(Roffset, Robj, Roffset); __ fldd(D0_tos, Address(Roffset)); break;
#endif // __SOFTFP__ #endif // __SOFTFP__
#endif // AARCH64 #endif // AARCH64
case Bytecodes::_fast_agetfield: __ load_heap_oop(R0_tos, Address(Robj, Roffset)); __ verify_oop(R0_tos); break; case Bytecodes::_fast_agetfield: do_oop_load(_masm, R0_tos, Address(Robj, Roffset)); __ verify_oop(R0_tos); break;
default: default:
ShouldNotReachHere(); ShouldNotReachHere();
} }
@ -3992,7 +3945,7 @@ void TemplateTable::fast_xaccess(TosState state) {
if (state == itos) { if (state == itos) {
__ ldr_s32(R0_tos, Address(Robj, Roffset)); __ ldr_s32(R0_tos, Address(Robj, Roffset));
} else if (state == atos) { } else if (state == atos) {
__ load_heap_oop(R0_tos, Address(Robj, Roffset)); do_oop_load(_masm, R0_tos, Address(Robj, Roffset));
__ verify_oop(R0_tos); __ verify_oop(R0_tos);
} else if (state == ftos) { } else if (state == ftos) {
#ifdef AARCH64 #ifdef AARCH64