Path: blob/master/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp
40975 views
/*1* Copyright (c) 2018, 2021, Red Hat, Inc. 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 "c1/c1_IR.hpp"26#include "gc/shared/satbMarkQueue.hpp"27#include "gc/shenandoah/shenandoahBarrierSet.hpp"28#include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"29#include "gc/shenandoah/shenandoahHeap.inline.hpp"30#include "gc/shenandoah/shenandoahHeapRegion.hpp"31#include "gc/shenandoah/shenandoahRuntime.hpp"32#include "gc/shenandoah/shenandoahThreadLocalData.hpp"33#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"3435#ifdef ASSERT36#define __ gen->lir(__FILE__, __LINE__)->37#else38#define __ gen->lir()->39#endif4041void ShenandoahPreBarrierStub::emit_code(LIR_Assembler* ce) {42ShenandoahBarrierSetAssembler* bs = (ShenandoahBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler();43bs->gen_pre_barrier_stub(ce, this);44}4546void ShenandoahLoadReferenceBarrierStub::emit_code(LIR_Assembler* ce) {47ShenandoahBarrierSetAssembler* bs = (ShenandoahBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler();48bs->gen_load_reference_barrier_stub(ce, this);49}5051ShenandoahBarrierSetC1::ShenandoahBarrierSetC1() :52_pre_barrier_c1_runtime_code_blob(NULL),53_load_reference_barrier_strong_rt_code_blob(NULL),54_load_reference_barrier_strong_native_rt_code_blob(NULL),55_load_reference_barrier_weak_rt_code_blob(NULL),56_load_reference_barrier_phantom_rt_code_blob(NULL) {}5758void ShenandoahBarrierSetC1::pre_barrier(LIRGenerator* gen, CodeEmitInfo* info, DecoratorSet decorators, LIR_Opr addr_opr, LIR_Opr pre_val) {59// First we test whether marking is in progress.60BasicType flag_type;61bool patch = (decorators & C1_NEEDS_PATCHING) != 0;62bool do_load = pre_val == LIR_OprFact::illegalOpr;63if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {64flag_type = T_INT;65} else {66guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1,67"Assumption");68// Use unsigned type T_BOOLEAN here rather than signed T_BYTE since some platforms, eg. ARM,69// need to use unsigned instructions to use the large offset to load the satb_mark_queue.70flag_type = T_BOOLEAN;71}72LIR_Opr thrd = gen->getThreadPointer();73LIR_Address* mark_active_flag_addr =74new LIR_Address(thrd,75in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset()),76flag_type);77// Read the marking-in-progress flag.78LIR_Opr flag_val = gen->new_register(T_INT);79__ load(mark_active_flag_addr, flag_val);80__ cmp(lir_cond_notEqual, flag_val, LIR_OprFact::intConst(0));8182LIR_PatchCode pre_val_patch_code = lir_patch_none;8384CodeStub* slow;8586if (do_load) {87assert(pre_val == LIR_OprFact::illegalOpr, "sanity");88assert(addr_opr != LIR_OprFact::illegalOpr, "sanity");8990if (patch)91pre_val_patch_code = lir_patch_normal;9293pre_val = gen->new_register(T_OBJECT);9495if (!addr_opr->is_address()) {96assert(addr_opr->is_register(), "must be");97addr_opr = LIR_OprFact::address(new LIR_Address(addr_opr, T_OBJECT));98}99slow = new ShenandoahPreBarrierStub(addr_opr, pre_val, pre_val_patch_code, info ? new CodeEmitInfo(info) : NULL);100} else {101assert(addr_opr == LIR_OprFact::illegalOpr, "sanity");102assert(pre_val->is_register(), "must be");103assert(pre_val->type() == T_OBJECT, "must be an object");104105slow = new ShenandoahPreBarrierStub(pre_val);106}107108__ branch(lir_cond_notEqual, slow);109__ branch_destination(slow->continuation());110}111112LIR_Opr ShenandoahBarrierSetC1::load_reference_barrier(LIRGenerator* gen, LIR_Opr obj, LIR_Opr addr, DecoratorSet decorators) {113if (ShenandoahLoadRefBarrier) {114return load_reference_barrier_impl(gen, obj, addr, decorators);115} else {116return obj;117}118}119120LIR_Opr ShenandoahBarrierSetC1::load_reference_barrier_impl(LIRGenerator* gen, LIR_Opr obj, LIR_Opr addr, DecoratorSet decorators) {121assert(ShenandoahLoadRefBarrier, "Should be enabled");122123obj = ensure_in_register(gen, obj, T_OBJECT);124assert(obj->is_register(), "must be a register at this point");125addr = ensure_in_register(gen, addr, T_ADDRESS);126assert(addr->is_register(), "must be a register at this point");127LIR_Opr result = gen->result_register_for(obj->value_type());128__ move(obj, result);129LIR_Opr tmp1 = gen->new_register(T_ADDRESS);130LIR_Opr tmp2 = gen->new_register(T_ADDRESS);131132LIR_Opr thrd = gen->getThreadPointer();133LIR_Address* active_flag_addr =134new LIR_Address(thrd,135in_bytes(ShenandoahThreadLocalData::gc_state_offset()),136T_BYTE);137// Read and check the gc-state-flag.138LIR_Opr flag_val = gen->new_register(T_INT);139__ load(active_flag_addr, flag_val);140int flags = ShenandoahHeap::HAS_FORWARDED;141if (!ShenandoahBarrierSet::is_strong_access(decorators)) {142flags |= ShenandoahHeap::WEAK_ROOTS;143}144LIR_Opr mask = LIR_OprFact::intConst(flags);145LIR_Opr mask_reg = gen->new_register(T_INT);146__ move(mask, mask_reg);147148if (TwoOperandLIRForm) {149__ logical_and(flag_val, mask_reg, flag_val);150} else {151LIR_Opr masked_flag = gen->new_register(T_INT);152__ logical_and(flag_val, mask_reg, masked_flag);153flag_val = masked_flag;154}155__ cmp(lir_cond_notEqual, flag_val, LIR_OprFact::intConst(0));156157CodeStub* slow = new ShenandoahLoadReferenceBarrierStub(obj, addr, result, tmp1, tmp2, decorators);158__ branch(lir_cond_notEqual, slow);159__ branch_destination(slow->continuation());160161return result;162}163164LIR_Opr ShenandoahBarrierSetC1::ensure_in_register(LIRGenerator* gen, LIR_Opr obj, BasicType type) {165if (!obj->is_register()) {166LIR_Opr obj_reg;167if (obj->is_constant()) {168obj_reg = gen->new_register(type);169__ move(obj, obj_reg);170} else {171obj_reg = gen->new_pointer_register();172__ leal(obj, obj_reg);173}174obj = obj_reg;175}176return obj;177}178179LIR_Opr ShenandoahBarrierSetC1::iu_barrier(LIRGenerator* gen, LIR_Opr obj, CodeEmitInfo* info, DecoratorSet decorators) {180if (ShenandoahIUBarrier) {181obj = ensure_in_register(gen, obj, T_OBJECT);182pre_barrier(gen, info, decorators, LIR_OprFact::illegalOpr, obj);183}184return obj;185}186187void ShenandoahBarrierSetC1::store_at_resolved(LIRAccess& access, LIR_Opr value) {188if (access.is_oop()) {189if (ShenandoahSATBBarrier) {190pre_barrier(access.gen(), access.access_emit_info(), access.decorators(), access.resolved_addr(), LIR_OprFact::illegalOpr /* pre_val */);191}192value = iu_barrier(access.gen(), value, access.access_emit_info(), access.decorators());193}194BarrierSetC1::store_at_resolved(access, value);195}196197LIR_Opr ShenandoahBarrierSetC1::resolve_address(LIRAccess& access, bool resolve_in_register) {198// We must resolve in register when patching. This is to avoid199// having a patch area in the load barrier stub, since the call200// into the runtime to patch will not have the proper oop map.201const bool patch_before_barrier = access.is_oop() && (access.decorators() & C1_NEEDS_PATCHING) != 0;202return BarrierSetC1::resolve_address(access, resolve_in_register || patch_before_barrier);203}204205void ShenandoahBarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) {206// 1: non-reference load, no additional barrier is needed207if (!access.is_oop()) {208BarrierSetC1::load_at_resolved(access, result);209return;210}211212LIRGenerator* gen = access.gen();213DecoratorSet decorators = access.decorators();214BasicType type = access.type();215216// 2: load a reference from src location and apply LRB if ShenandoahLoadRefBarrier is set217if (ShenandoahBarrierSet::need_load_reference_barrier(decorators, type)) {218LIR_Opr tmp = gen->new_register(T_OBJECT);219BarrierSetC1::load_at_resolved(access, tmp);220tmp = load_reference_barrier(gen, tmp, access.resolved_addr(), decorators);221__ move(tmp, result);222} else {223BarrierSetC1::load_at_resolved(access, result);224}225226// 3: apply keep-alive barrier for java.lang.ref.Reference if needed227if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) {228bool is_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0;229230// Register the value in the referent field with the pre-barrier231LabelObj *Lcont_anonymous;232if (is_anonymous) {233Lcont_anonymous = new LabelObj();234generate_referent_check(access, Lcont_anonymous);235}236pre_barrier(gen, access.access_emit_info(), decorators, LIR_OprFact::illegalOpr /* addr_opr */,237result /* pre_val */);238if (is_anonymous) {239__ branch_destination(Lcont_anonymous->label());240}241}242}243244class C1ShenandoahPreBarrierCodeGenClosure : public StubAssemblerCodeGenClosure {245virtual OopMapSet* generate_code(StubAssembler* sasm) {246ShenandoahBarrierSetAssembler* bs = (ShenandoahBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler();247bs->generate_c1_pre_barrier_runtime_stub(sasm);248return NULL;249}250};251252class C1ShenandoahLoadReferenceBarrierCodeGenClosure : public StubAssemblerCodeGenClosure {253private:254const DecoratorSet _decorators;255256public:257C1ShenandoahLoadReferenceBarrierCodeGenClosure(DecoratorSet decorators) : _decorators(decorators) {}258259virtual OopMapSet* generate_code(StubAssembler* sasm) {260ShenandoahBarrierSetAssembler* bs = (ShenandoahBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler();261bs->generate_c1_load_reference_barrier_runtime_stub(sasm, _decorators);262return NULL;263}264};265266void ShenandoahBarrierSetC1::generate_c1_runtime_stubs(BufferBlob* buffer_blob) {267C1ShenandoahPreBarrierCodeGenClosure pre_code_gen_cl;268_pre_barrier_c1_runtime_code_blob = Runtime1::generate_blob(buffer_blob, -1,269"shenandoah_pre_barrier_slow",270false, &pre_code_gen_cl);271if (ShenandoahLoadRefBarrier) {272C1ShenandoahLoadReferenceBarrierCodeGenClosure lrb_strong_code_gen_cl(ON_STRONG_OOP_REF);273_load_reference_barrier_strong_rt_code_blob = Runtime1::generate_blob(buffer_blob, -1,274"shenandoah_load_reference_barrier_strong_slow",275false, &lrb_strong_code_gen_cl);276277C1ShenandoahLoadReferenceBarrierCodeGenClosure lrb_strong_native_code_gen_cl(ON_STRONG_OOP_REF | IN_NATIVE);278_load_reference_barrier_strong_native_rt_code_blob = Runtime1::generate_blob(buffer_blob, -1,279"shenandoah_load_reference_barrier_strong_native_slow",280false, &lrb_strong_native_code_gen_cl);281282C1ShenandoahLoadReferenceBarrierCodeGenClosure lrb_weak_code_gen_cl(ON_WEAK_OOP_REF);283_load_reference_barrier_weak_rt_code_blob = Runtime1::generate_blob(buffer_blob, -1,284"shenandoah_load_reference_barrier_weak_slow",285false, &lrb_weak_code_gen_cl);286287C1ShenandoahLoadReferenceBarrierCodeGenClosure lrb_phantom_code_gen_cl(ON_PHANTOM_OOP_REF | IN_NATIVE);288_load_reference_barrier_phantom_rt_code_blob = Runtime1::generate_blob(buffer_blob, -1,289"shenandoah_load_reference_barrier_phantom_slow",290false, &lrb_phantom_code_gen_cl);291}292}293294295