Path: blob/master/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp
41153 views
/*1* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "asm/macroAssembler.inline.hpp"26#include "gc/g1/g1BarrierSet.hpp"27#include "gc/g1/g1BarrierSetAssembler.hpp"28#include "gc/g1/g1BarrierSetRuntime.hpp"29#include "gc/g1/g1CardTable.hpp"30#include "gc/g1/g1ThreadLocalData.hpp"31#include "gc/g1/heapRegion.hpp"32#include "gc/shared/collectedHeap.hpp"33#include "runtime/sharedRuntime.hpp"34#include "runtime/thread.hpp"35#include "interpreter/interp_masm.hpp"36#include "runtime/sharedRuntime.hpp"37#ifdef COMPILER138#include "c1/c1_LIRAssembler.hpp"39#include "c1/c1_MacroAssembler.hpp"40#include "gc/g1/c1/g1BarrierSetC1.hpp"41#endif4243#define __ masm->4445void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators,46Register addr, Register count, RegSet saved_regs) {47bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;48if (!dest_uninitialized) {49Label done;50Address in_progress(rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));5152// Is marking active?53if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {54__ ldrw(rscratch1, in_progress);55} else {56assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");57__ ldrb(rscratch1, in_progress);58}59__ cbzw(rscratch1, done);6061__ push(saved_regs, sp);62if (count == c_rarg0) {63if (addr == c_rarg1) {64// exactly backwards!!65__ mov(rscratch1, c_rarg0);66__ mov(c_rarg0, c_rarg1);67__ mov(c_rarg1, rscratch1);68} else {69__ mov(c_rarg1, count);70__ mov(c_rarg0, addr);71}72} else {73__ mov(c_rarg0, addr);74__ mov(c_rarg1, count);75}76if (UseCompressedOops) {77__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_narrow_oop_entry), 2);78} else {79__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_oop_entry), 2);80}81__ pop(saved_regs, sp);8283__ bind(done);84}85}8687void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,88Register start, Register count, Register scratch, RegSet saved_regs) {89__ push(saved_regs, sp);90assert_different_registers(start, count, scratch);91assert_different_registers(c_rarg0, count);92__ mov(c_rarg0, start);93__ mov(c_rarg1, count);94__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry), 2);95__ pop(saved_regs, sp);96}9798void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,99Register obj,100Register pre_val,101Register thread,102Register tmp,103bool tosca_live,104bool expand_call) {105// If expand_call is true then we expand the call_VM_leaf macro106// directly to skip generating the check by107// InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp.108109assert(thread == rthread, "must be");110111Label done;112Label runtime;113114assert_different_registers(obj, pre_val, tmp, rscratch1);115assert(pre_val != noreg && tmp != noreg, "expecting a register");116117Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));118Address index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));119Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));120121// Is marking active?122if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {123__ ldrw(tmp, in_progress);124} else {125assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");126__ ldrb(tmp, in_progress);127}128__ cbzw(tmp, done);129130// Do we need to load the previous value?131if (obj != noreg) {132__ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW);133}134135// Is the previous value null?136__ cbz(pre_val, done);137138// Can we store original value in the thread's buffer?139// Is index == 0?140// (The index field is typed as size_t.)141142__ ldr(tmp, index); // tmp := *index_adr143__ cbz(tmp, runtime); // tmp == 0?144// If yes, goto runtime145146__ sub(tmp, tmp, wordSize); // tmp := tmp - wordSize147__ str(tmp, index); // *index_adr := tmp148__ ldr(rscratch1, buffer);149__ add(tmp, tmp, rscratch1); // tmp := tmp + *buffer_adr150151// Record the previous value152__ str(pre_val, Address(tmp, 0));153__ b(done);154155__ bind(runtime);156// save the live input values157RegSet saved = RegSet::of(pre_val);158if (tosca_live) saved += RegSet::of(r0);159if (obj != noreg) saved += RegSet::of(obj);160161__ push(saved, sp);162163// Calling the runtime using the regular call_VM_leaf mechanism generates164// code (generated by InterpreterMacroAssember::call_VM_leaf_base)165// that checks that the *(rfp+frame::interpreter_frame_last_sp) == NULL.166//167// If we care generating the pre-barrier without a frame (e.g. in the168// intrinsified Reference.get() routine) then ebp might be pointing to169// the caller frame and so this check will most likely fail at runtime.170//171// Expanding the call directly bypasses the generation of the check.172// So when we do not have have a full interpreter frame on the stack173// expand_call should be passed true.174175if (expand_call) {176assert(pre_val != c_rarg1, "smashed arg");177__ super_call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread);178} else {179__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread);180}181182__ pop(saved, sp);183184__ bind(done);185186}187188void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,189Register store_addr,190Register new_val,191Register thread,192Register tmp,193Register tmp2) {194assert(thread == rthread, "must be");195assert_different_registers(store_addr, new_val, thread, tmp, tmp2,196rscratch1);197assert(store_addr != noreg && new_val != noreg && tmp != noreg198&& tmp2 != noreg, "expecting a register");199200Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));201Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));202203BarrierSet* bs = BarrierSet::barrier_set();204CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);205CardTable* ct = ctbs->card_table();206207Label done;208Label runtime;209210// Does store cross heap regions?211212__ eor(tmp, store_addr, new_val);213__ lsr(tmp, tmp, HeapRegion::LogOfHRGrainBytes);214__ cbz(tmp, done);215216// crosses regions, storing NULL?217218__ cbz(new_val, done);219220// storing region crossing non-NULL, is card already dirty?221222const Register card_addr = tmp;223224__ lsr(card_addr, store_addr, CardTable::card_shift);225226// get the address of the card227__ load_byte_map_base(tmp2);228__ add(card_addr, card_addr, tmp2);229__ ldrb(tmp2, Address(card_addr));230__ cmpw(tmp2, (int)G1CardTable::g1_young_card_val());231__ br(Assembler::EQ, done);232233assert((int)CardTable::dirty_card_val() == 0, "must be 0");234235__ membar(Assembler::StoreLoad);236237__ ldrb(tmp2, Address(card_addr));238__ cbzw(tmp2, done);239240// storing a region crossing, non-NULL oop, card is clean.241// dirty card and log.242243__ strb(zr, Address(card_addr));244245__ ldr(rscratch1, queue_index);246__ cbz(rscratch1, runtime);247__ sub(rscratch1, rscratch1, wordSize);248__ str(rscratch1, queue_index);249250__ ldr(tmp2, buffer);251__ str(card_addr, Address(tmp2, rscratch1));252__ b(done);253254__ bind(runtime);255// save the live input values256RegSet saved = RegSet::of(store_addr);257__ push(saved, sp);258__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread);259__ pop(saved, sp);260261__ bind(done);262}263264void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,265Register dst, Address src, Register tmp1, Register tmp_thread) {266bool on_oop = is_reference_type(type);267bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0;268bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0;269bool on_reference = on_weak || on_phantom;270ModRefBarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread);271if (on_oop && on_reference) {272// LR is live. It must be saved around calls.273__ enter(); // barrier may call runtime274// Generate the G1 pre-barrier code to log the value of275// the referent field in an SATB buffer.276g1_write_barrier_pre(masm /* masm */,277noreg /* obj */,278dst /* pre_val */,279rthread /* thread */,280tmp1 /* tmp */,281true /* tosca_live */,282true /* expand_call */);283__ leave();284}285}286287void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,288Address dst, Register val, Register tmp1, Register tmp2) {289// flatten object address if needed290if (dst.index() == noreg && dst.offset() == 0) {291if (dst.base() != r3) {292__ mov(r3, dst.base());293}294} else {295__ lea(r3, dst);296}297298g1_write_barrier_pre(masm,299r3 /* obj */,300tmp2 /* pre_val */,301rthread /* thread */,302tmp1 /* tmp */,303val != noreg /* tosca_live */,304false /* expand_call */);305306if (val == noreg) {307BarrierSetAssembler::store_at(masm, decorators, type, Address(r3, 0), noreg, noreg, noreg);308} else {309// G1 barrier needs uncompressed oop for region cross check.310Register new_val = val;311if (UseCompressedOops) {312new_val = rscratch2;313__ mov(new_val, val);314}315BarrierSetAssembler::store_at(masm, decorators, type, Address(r3, 0), val, noreg, noreg);316g1_write_barrier_post(masm,317r3 /* store_adr */,318new_val /* new_val */,319rthread /* thread */,320tmp1 /* tmp */,321tmp2 /* tmp2 */);322}323324}325326#ifdef COMPILER1327328#undef __329#define __ ce->masm()->330331void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) {332G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();333// At this point we know that marking is in progress.334// If do_load() is true then we have to emit the335// load of the previous value; otherwise it has already336// been loaded into _pre_val.337338__ bind(*stub->entry());339340assert(stub->pre_val()->is_register(), "Precondition.");341342Register pre_val_reg = stub->pre_val()->as_register();343344if (stub->do_load()) {345ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/, false /*unaligned*/);346}347__ cbz(pre_val_reg, *stub->continuation());348ce->store_parameter(stub->pre_val()->as_register(), 0);349__ far_call(RuntimeAddress(bs->pre_barrier_c1_runtime_code_blob()->code_begin()));350__ b(*stub->continuation());351}352353void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) {354G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();355__ bind(*stub->entry());356assert(stub->addr()->is_register(), "Precondition.");357assert(stub->new_val()->is_register(), "Precondition.");358Register new_val_reg = stub->new_val()->as_register();359__ cbz(new_val_reg, *stub->continuation());360ce->store_parameter(stub->addr()->as_pointer_register(), 0);361__ far_call(RuntimeAddress(bs->post_barrier_c1_runtime_code_blob()->code_begin()));362__ b(*stub->continuation());363}364365#undef __366367#define __ sasm->368369void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) {370__ prologue("g1_pre_barrier", false);371372// arg0 : previous value of memory373374BarrierSet* bs = BarrierSet::barrier_set();375376const Register pre_val = r0;377const Register thread = rthread;378const Register tmp = rscratch1;379380Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));381Address queue_index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));382Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));383384Label done;385Label runtime;386387// Is marking still active?388if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {389__ ldrw(tmp, in_progress);390} else {391assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");392__ ldrb(tmp, in_progress);393}394__ cbzw(tmp, done);395396// Can we store original value in the thread's buffer?397__ ldr(tmp, queue_index);398__ cbz(tmp, runtime);399400__ sub(tmp, tmp, wordSize);401__ str(tmp, queue_index);402__ ldr(rscratch2, buffer);403__ add(tmp, tmp, rscratch2);404__ load_parameter(0, rscratch2);405__ str(rscratch2, Address(tmp, 0));406__ b(done);407408__ bind(runtime);409__ push_call_clobbered_registers();410__ load_parameter(0, pre_val);411__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread);412__ pop_call_clobbered_registers();413__ bind(done);414415__ epilogue();416}417418void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) {419__ prologue("g1_post_barrier", false);420421// arg0: store_address422Address store_addr(rfp, 2*BytesPerWord);423424BarrierSet* bs = BarrierSet::barrier_set();425CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);426CardTable* ct = ctbs->card_table();427428Label done;429Label runtime;430431// At this point we know new_value is non-NULL and the new_value crosses regions.432// Must check to see if card is already dirty433434const Register thread = rthread;435436Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));437Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));438439const Register card_offset = rscratch2;440// LR is free here, so we can use it to hold the byte_map_base.441const Register byte_map_base = lr;442443assert_different_registers(card_offset, byte_map_base, rscratch1);444445__ load_parameter(0, card_offset);446__ lsr(card_offset, card_offset, CardTable::card_shift);447__ load_byte_map_base(byte_map_base);448__ ldrb(rscratch1, Address(byte_map_base, card_offset));449__ cmpw(rscratch1, (int)G1CardTable::g1_young_card_val());450__ br(Assembler::EQ, done);451452assert((int)CardTable::dirty_card_val() == 0, "must be 0");453454__ membar(Assembler::StoreLoad);455__ ldrb(rscratch1, Address(byte_map_base, card_offset));456__ cbzw(rscratch1, done);457458// storing region crossing non-NULL, card is clean.459// dirty card and log.460__ strb(zr, Address(byte_map_base, card_offset));461462// Convert card offset into an address in card_addr463Register card_addr = card_offset;464__ add(card_addr, byte_map_base, card_addr);465466__ ldr(rscratch1, queue_index);467__ cbz(rscratch1, runtime);468__ sub(rscratch1, rscratch1, wordSize);469__ str(rscratch1, queue_index);470471// Reuse LR to hold buffer_addr472const Register buffer_addr = lr;473474__ ldr(buffer_addr, buffer);475__ str(card_addr, Address(buffer_addr, rscratch1));476__ b(done);477478__ bind(runtime);479__ push_call_clobbered_registers();480__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread);481__ pop_call_clobbered_registers();482__ bind(done);483__ epilogue();484}485486#undef __487488#endif // COMPILER1489490491