Path: blob/master/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp
41153 views
/*1* Copyright (c) 2018, 2019, 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 "interpreter/interp_masm.hpp"33#include "runtime/sharedRuntime.hpp"34#include "utilities/debug.hpp"35#include "utilities/macros.hpp"36#ifdef COMPILER137#include "c1/c1_LIRAssembler.hpp"38#include "c1/c1_MacroAssembler.hpp"39#include "gc/g1/c1/g1BarrierSetC1.hpp"40#endif4142#define __ masm->4344void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators,45Register addr, Register count) {46bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;4748if (!dest_uninitialized) {49Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread);50#ifndef _LP6451__ push(thread);52__ get_thread(thread);53#endif5455Label filtered;56Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));57// Is marking active?58if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {59__ cmpl(in_progress, 0);60} else {61assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");62__ cmpb(in_progress, 0);63}6465NOT_LP64(__ pop(thread);)6667__ jcc(Assembler::equal, filtered);6869__ pusha(); // push registers70#ifdef _LP6471if (count == c_rarg0) {72if (addr == c_rarg1) {73// exactly backwards!!74__ xchgptr(c_rarg1, c_rarg0);75} else {76__ movptr(c_rarg1, count);77__ movptr(c_rarg0, addr);78}79} else {80__ movptr(c_rarg0, addr);81__ movptr(c_rarg1, count);82}83if (UseCompressedOops) {84__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_narrow_oop_entry), 2);85} else {86__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_oop_entry), 2);87}88#else89__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_oop_entry),90addr, count);91#endif92__ popa();9394__ bind(filtered);95}96}9798void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,99Register addr, Register count, Register tmp) {100__ pusha(); // push registers (overkill)101#ifdef _LP64102if (c_rarg0 == count) { // On win64 c_rarg0 == rcx103assert_different_registers(c_rarg1, addr);104__ mov(c_rarg1, count);105__ mov(c_rarg0, addr);106} else {107assert_different_registers(c_rarg0, count);108__ mov(c_rarg0, addr);109__ mov(c_rarg1, count);110}111__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry), 2);112#else113__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry),114addr, count);115#endif116__ popa();117}118119void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,120Register dst, Address src, Register tmp1, Register tmp_thread) {121bool on_oop = is_reference_type(type);122bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0;123bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0;124bool on_reference = on_weak || on_phantom;125ModRefBarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread);126if (on_oop && on_reference) {127const Register thread = NOT_LP64(tmp_thread) LP64_ONLY(r15_thread);128NOT_LP64(__ get_thread(thread));129130// Generate the G1 pre-barrier code to log the value of131// the referent field in an SATB buffer.132g1_write_barrier_pre(masm /* masm */,133noreg /* obj */,134dst /* pre_val */,135thread /* thread */,136tmp1 /* tmp */,137true /* tosca_live */,138true /* expand_call */);139}140}141142void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,143Register obj,144Register pre_val,145Register thread,146Register tmp,147bool tosca_live,148bool expand_call) {149// If expand_call is true then we expand the call_VM_leaf macro150// directly to skip generating the check by151// InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp.152153#ifdef _LP64154assert(thread == r15_thread, "must be");155#endif // _LP64156157Label done;158Label runtime;159160assert(pre_val != noreg, "check this code");161162if (obj != noreg) {163assert_different_registers(obj, pre_val, tmp);164assert(pre_val != rax, "check this code");165}166167Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));168Address index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));169Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));170171// Is marking active?172if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {173__ cmpl(in_progress, 0);174} else {175assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");176__ cmpb(in_progress, 0);177}178__ jcc(Assembler::equal, done);179180// Do we need to load the previous value?181if (obj != noreg) {182__ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW);183}184185// Is the previous value null?186__ cmpptr(pre_val, (int32_t) NULL_WORD);187__ jcc(Assembler::equal, done);188189// Can we store original value in the thread's buffer?190// Is index == 0?191// (The index field is typed as size_t.)192193__ movptr(tmp, index); // tmp := *index_adr194__ cmpptr(tmp, 0); // tmp == 0?195__ jcc(Assembler::equal, runtime); // If yes, goto runtime196197__ subptr(tmp, wordSize); // tmp := tmp - wordSize198__ movptr(index, tmp); // *index_adr := tmp199__ addptr(tmp, buffer); // tmp := tmp + *buffer_adr200201// Record the previous value202__ movptr(Address(tmp, 0), pre_val);203__ jmp(done);204205__ bind(runtime);206// save the live input values207if(tosca_live) __ push(rax);208209if (obj != noreg && obj != rax)210__ push(obj);211212if (pre_val != rax)213__ push(pre_val);214215// Calling the runtime using the regular call_VM_leaf mechanism generates216// code (generated by InterpreterMacroAssember::call_VM_leaf_base)217// that checks that the *(ebp+frame::interpreter_frame_last_sp) == NULL.218//219// If we care generating the pre-barrier without a frame (e.g. in the220// intrinsified Reference.get() routine) then ebp might be pointing to221// the caller frame and so this check will most likely fail at runtime.222//223// Expanding the call directly bypasses the generation of the check.224// So when we do not have have a full interpreter frame on the stack225// expand_call should be passed true.226227NOT_LP64( __ push(thread); )228229if (expand_call) {230LP64_ONLY( assert(pre_val != c_rarg1, "smashed arg"); )231#ifdef _LP64232if (c_rarg1 != thread) {233__ mov(c_rarg1, thread);234}235if (c_rarg0 != pre_val) {236__ mov(c_rarg0, pre_val);237}238#else239__ push(thread);240__ push(pre_val);241#endif242__ MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), 2);243} else {244__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread);245}246247NOT_LP64( __ pop(thread); )248249// save the live input values250if (pre_val != rax)251__ pop(pre_val);252253if (obj != noreg && obj != rax)254__ pop(obj);255256if(tosca_live) __ pop(rax);257258__ bind(done);259}260261void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,262Register store_addr,263Register new_val,264Register thread,265Register tmp,266Register tmp2) {267// Generated code assumes that buffer index is pointer sized.268STATIC_ASSERT(in_bytes(SATBMarkQueue::byte_width_of_index()) == sizeof(intptr_t));269#ifdef _LP64270assert(thread == r15_thread, "must be");271#endif // _LP64272273Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));274Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));275276CardTableBarrierSet* ct =277barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());278279Label done;280Label runtime;281282// Does store cross heap regions?283284__ movptr(tmp, store_addr);285__ xorptr(tmp, new_val);286__ shrptr(tmp, HeapRegion::LogOfHRGrainBytes);287__ jcc(Assembler::equal, done);288289// crosses regions, storing NULL?290291__ cmpptr(new_val, (int32_t) NULL_WORD);292__ jcc(Assembler::equal, done);293294// storing region crossing non-NULL, is card already dirty?295296const Register card_addr = tmp;297const Register cardtable = tmp2;298299__ movptr(card_addr, store_addr);300__ shrptr(card_addr, CardTable::card_shift);301// Do not use ExternalAddress to load 'byte_map_base', since 'byte_map_base' is NOT302// a valid address and therefore is not properly handled by the relocation code.303__ movptr(cardtable, (intptr_t)ct->card_table()->byte_map_base());304__ addptr(card_addr, cardtable);305306__ cmpb(Address(card_addr, 0), (int)G1CardTable::g1_young_card_val());307__ jcc(Assembler::equal, done);308309__ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad));310__ cmpb(Address(card_addr, 0), (int)G1CardTable::dirty_card_val());311__ jcc(Assembler::equal, done);312313314// storing a region crossing, non-NULL oop, card is clean.315// dirty card and log.316317__ movb(Address(card_addr, 0), (int)G1CardTable::dirty_card_val());318319__ movptr(tmp2, queue_index);320__ testptr(tmp2, tmp2);321__ jcc(Assembler::zero, runtime);322__ subptr(tmp2, wordSize);323__ movptr(queue_index, tmp2);324__ addptr(tmp2, buffer);325__ movptr(Address(tmp2, 0), card_addr);326__ jmp(done);327328__ bind(runtime);329// save the live input values330__ push(store_addr);331#ifdef _LP64332__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, r15_thread);333#else334__ push(thread);335__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread);336__ pop(thread);337#endif338__ pop(store_addr);339340__ bind(done);341}342343void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,344Address dst, Register val, Register tmp1, Register tmp2) {345bool in_heap = (decorators & IN_HEAP) != 0;346bool as_normal = (decorators & AS_NORMAL) != 0;347assert((decorators & IS_DEST_UNINITIALIZED) == 0, "unsupported");348349bool needs_pre_barrier = as_normal;350bool needs_post_barrier = val != noreg && in_heap;351352Register tmp3 = LP64_ONLY(r8) NOT_LP64(rsi);353Register rthread = LP64_ONLY(r15_thread) NOT_LP64(rcx);354// flatten object address if needed355// We do it regardless of precise because we need the registers356if (dst.index() == noreg && dst.disp() == 0) {357if (dst.base() != tmp1) {358__ movptr(tmp1, dst.base());359}360} else {361__ lea(tmp1, dst);362}363364#ifndef _LP64365InterpreterMacroAssembler *imasm = static_cast<InterpreterMacroAssembler*>(masm);366#endif367368NOT_LP64(__ get_thread(rcx));369NOT_LP64(imasm->save_bcp());370371if (needs_pre_barrier) {372g1_write_barrier_pre(masm /*masm*/,373tmp1 /* obj */,374tmp2 /* pre_val */,375rthread /* thread */,376tmp3 /* tmp */,377val != noreg /* tosca_live */,378false /* expand_call */);379}380if (val == noreg) {381BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg);382} else {383Register new_val = val;384if (needs_post_barrier) {385// G1 barrier needs uncompressed oop for region cross check.386if (UseCompressedOops) {387new_val = tmp2;388__ movptr(new_val, val);389}390}391BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg);392if (needs_post_barrier) {393g1_write_barrier_post(masm /*masm*/,394tmp1 /* store_adr */,395new_val /* new_val */,396rthread /* thread */,397tmp3 /* tmp */,398tmp2 /* tmp2 */);399}400}401NOT_LP64(imasm->restore_bcp());402}403404#ifdef COMPILER1405406#undef __407#define __ ce->masm()->408409void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) {410G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();411// At this point we know that marking is in progress.412// If do_load() is true then we have to emit the413// load of the previous value; otherwise it has already414// been loaded into _pre_val.415416__ bind(*stub->entry());417assert(stub->pre_val()->is_register(), "Precondition.");418419Register pre_val_reg = stub->pre_val()->as_register();420421if (stub->do_load()) {422ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/, false /*unaligned*/);423}424425__ cmpptr(pre_val_reg, (int32_t)NULL_WORD);426__ jcc(Assembler::equal, *stub->continuation());427ce->store_parameter(stub->pre_val()->as_register(), 0);428__ call(RuntimeAddress(bs->pre_barrier_c1_runtime_code_blob()->code_begin()));429__ jmp(*stub->continuation());430431}432433void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) {434G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();435__ bind(*stub->entry());436assert(stub->addr()->is_register(), "Precondition.");437assert(stub->new_val()->is_register(), "Precondition.");438Register new_val_reg = stub->new_val()->as_register();439__ cmpptr(new_val_reg, (int32_t) NULL_WORD);440__ jcc(Assembler::equal, *stub->continuation());441ce->store_parameter(stub->addr()->as_pointer_register(), 0);442__ call(RuntimeAddress(bs->post_barrier_c1_runtime_code_blob()->code_begin()));443__ jmp(*stub->continuation());444}445446#undef __447448#define __ sasm->449450void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) {451// Generated code assumes that buffer index is pointer sized.452STATIC_ASSERT(in_bytes(SATBMarkQueue::byte_width_of_index()) == sizeof(intptr_t));453454__ prologue("g1_pre_barrier", false);455// arg0 : previous value of memory456457__ push(rax);458__ push(rdx);459460const Register pre_val = rax;461const Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread);462const Register tmp = rdx;463464NOT_LP64(__ get_thread(thread);)465466Address queue_active(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));467Address queue_index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));468Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));469470Label done;471Label runtime;472473// Is marking still active?474if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {475__ cmpl(queue_active, 0);476} else {477assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");478__ cmpb(queue_active, 0);479}480__ jcc(Assembler::equal, done);481482// Can we store original value in the thread's buffer?483484__ movptr(tmp, queue_index);485__ testptr(tmp, tmp);486__ jcc(Assembler::zero, runtime);487__ subptr(tmp, wordSize);488__ movptr(queue_index, tmp);489__ addptr(tmp, buffer);490491// prev_val (rax)492__ load_parameter(0, pre_val);493__ movptr(Address(tmp, 0), pre_val);494__ jmp(done);495496__ bind(runtime);497498__ save_live_registers_no_oop_map(true);499500// load the pre-value501__ load_parameter(0, rcx);502__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), rcx, thread);503504__ restore_live_registers(true);505506__ bind(done);507508__ pop(rdx);509__ pop(rax);510511__ epilogue();512}513514void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) {515__ prologue("g1_post_barrier", false);516517// arg0: store_address518Address store_addr(rbp, 2*BytesPerWord);519520CardTableBarrierSet* ct =521barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());522523Label done;524Label enqueued;525Label runtime;526527// At this point we know new_value is non-NULL and the new_value crosses regions.528// Must check to see if card is already dirty529530const Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread);531532Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));533Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));534535__ push(rax);536__ push(rcx);537538const Register cardtable = rax;539const Register card_addr = rcx;540541__ load_parameter(0, card_addr);542__ shrptr(card_addr, CardTable::card_shift);543// Do not use ExternalAddress to load 'byte_map_base', since 'byte_map_base' is NOT544// a valid address and therefore is not properly handled by the relocation code.545__ movptr(cardtable, (intptr_t)ct->card_table()->byte_map_base());546__ addptr(card_addr, cardtable);547548NOT_LP64(__ get_thread(thread);)549550__ cmpb(Address(card_addr, 0), (int)G1CardTable::g1_young_card_val());551__ jcc(Assembler::equal, done);552553__ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad));554__ cmpb(Address(card_addr, 0), (int)CardTable::dirty_card_val());555__ jcc(Assembler::equal, done);556557// storing region crossing non-NULL, card is clean.558// dirty card and log.559560__ movb(Address(card_addr, 0), (int)CardTable::dirty_card_val());561562const Register tmp = rdx;563__ push(rdx);564565__ movptr(tmp, queue_index);566__ testptr(tmp, tmp);567__ jcc(Assembler::zero, runtime);568__ subptr(tmp, wordSize);569__ movptr(queue_index, tmp);570__ addptr(tmp, buffer);571__ movptr(Address(tmp, 0), card_addr);572__ jmp(enqueued);573574__ bind(runtime);575576__ save_live_registers_no_oop_map(true);577578__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread);579580__ restore_live_registers(true);581582__ bind(enqueued);583__ pop(rdx);584585__ bind(done);586__ pop(rcx);587__ pop(rax);588589__ epilogue();590}591592#undef __593594#endif // COMPILER1595596597