Path: blob/master/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp
41153 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 "gc/shenandoah/shenandoahBarrierSet.hpp"26#include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"27#include "gc/shenandoah/shenandoahForwarding.hpp"28#include "gc/shenandoah/shenandoahHeap.inline.hpp"29#include "gc/shenandoah/shenandoahHeapRegion.hpp"30#include "gc/shenandoah/shenandoahRuntime.hpp"31#include "gc/shenandoah/shenandoahThreadLocalData.hpp"32#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"33#include "interpreter/interpreter.hpp"34#include "interpreter/interp_masm.hpp"35#include "runtime/sharedRuntime.hpp"36#include "runtime/thread.hpp"37#ifdef COMPILER138#include "c1/c1_LIRAssembler.hpp"39#include "c1/c1_MacroAssembler.hpp"40#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"41#endif4243#define __ masm->4445void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,46Register src, Register dst, Register count, RegSet saved_regs) {47if (is_oop) {48bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0;49if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahIUBarrier || ShenandoahLoadRefBarrier) {5051Label done;5253// Avoid calling runtime if count == 054__ cbz(count, done);5556// Is GC active?57Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));58__ ldrb(rscratch1, gc_state);59if (ShenandoahSATBBarrier && dest_uninitialized) {60__ tbz(rscratch1, ShenandoahHeap::HAS_FORWARDED_BITPOS, done);61} else {62__ mov(rscratch2, ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::MARKING);63__ tst(rscratch1, rscratch2);64__ br(Assembler::EQ, done);65}6667__ push(saved_regs, sp);68if (UseCompressedOops) {69__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry), src, dst, count);70} else {71__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop_entry), src, dst, count);72}73__ pop(saved_regs, sp);74__ bind(done);75}76}77}7879void ShenandoahBarrierSetAssembler::shenandoah_write_barrier_pre(MacroAssembler* masm,80Register obj,81Register pre_val,82Register thread,83Register tmp,84bool tosca_live,85bool expand_call) {86if (ShenandoahSATBBarrier) {87satb_write_barrier_pre(masm, obj, pre_val, thread, tmp, tosca_live, expand_call);88}89}9091void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm,92Register obj,93Register pre_val,94Register thread,95Register tmp,96bool tosca_live,97bool expand_call) {98// If expand_call is true then we expand the call_VM_leaf macro99// directly to skip generating the check by100// InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp.101102assert(thread == rthread, "must be");103104Label done;105Label runtime;106107assert_different_registers(obj, pre_val, tmp, rscratch1);108assert(pre_val != noreg && tmp != noreg, "expecting a register");109110Address in_progress(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset()));111Address index(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()));112Address buffer(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()));113114// Is marking active?115if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {116__ ldrw(tmp, in_progress);117} else {118assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");119__ ldrb(tmp, in_progress);120}121__ cbzw(tmp, done);122123// Do we need to load the previous value?124if (obj != noreg) {125__ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW);126}127128// Is the previous value null?129__ cbz(pre_val, done);130131// Can we store original value in the thread's buffer?132// Is index == 0?133// (The index field is typed as size_t.)134135__ ldr(tmp, index); // tmp := *index_adr136__ cbz(tmp, runtime); // tmp == 0?137// If yes, goto runtime138139__ sub(tmp, tmp, wordSize); // tmp := tmp - wordSize140__ str(tmp, index); // *index_adr := tmp141__ ldr(rscratch1, buffer);142__ add(tmp, tmp, rscratch1); // tmp := tmp + *buffer_adr143144// Record the previous value145__ str(pre_val, Address(tmp, 0));146__ b(done);147148__ bind(runtime);149// save the live input values150RegSet saved = RegSet::of(pre_val);151if (tosca_live) saved += RegSet::of(r0);152if (obj != noreg) saved += RegSet::of(obj);153154__ push(saved, sp);155156// Calling the runtime using the regular call_VM_leaf mechanism generates157// code (generated by InterpreterMacroAssember::call_VM_leaf_base)158// that checks that the *(rfp+frame::interpreter_frame_last_sp) == NULL.159//160// If we care generating the pre-barrier without a frame (e.g. in the161// intrinsified Reference.get() routine) then ebp might be pointing to162// the caller frame and so this check will most likely fail at runtime.163//164// Expanding the call directly bypasses the generation of the check.165// So when we do not have have a full interpreter frame on the stack166// expand_call should be passed true.167168if (expand_call) {169assert(pre_val != c_rarg1, "smashed arg");170__ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread);171} else {172__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread);173}174175__ pop(saved, sp);176177__ bind(done);178}179180void ShenandoahBarrierSetAssembler::resolve_forward_pointer(MacroAssembler* masm, Register dst, Register tmp) {181assert(ShenandoahLoadRefBarrier || ShenandoahCASBarrier, "Should be enabled");182Label is_null;183__ cbz(dst, is_null);184resolve_forward_pointer_not_null(masm, dst, tmp);185__ bind(is_null);186}187188// IMPORTANT: This must preserve all registers, even rscratch1 and rscratch2, except those explicitely189// passed in.190void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp) {191assert(ShenandoahLoadRefBarrier || ShenandoahCASBarrier, "Should be enabled");192// The below loads the mark word, checks if the lowest two bits are193// set, and if so, clear the lowest two bits and copy the result194// to dst. Otherwise it leaves dst alone.195// Implementing this is surprisingly awkward. I do it here by:196// - Inverting the mark word197// - Test lowest two bits == 0198// - If so, set the lowest two bits199// - Invert the result back, and copy to dst200201bool borrow_reg = (tmp == noreg);202if (borrow_reg) {203// No free registers available. Make one useful.204tmp = rscratch1;205if (tmp == dst) {206tmp = rscratch2;207}208__ push(RegSet::of(tmp), sp);209}210211assert_different_registers(tmp, dst);212213Label done;214__ ldr(tmp, Address(dst, oopDesc::mark_offset_in_bytes()));215__ eon(tmp, tmp, zr);216__ ands(zr, tmp, markWord::lock_mask_in_place);217__ br(Assembler::NE, done);218__ orr(tmp, tmp, markWord::marked_value);219__ eon(dst, tmp, zr);220__ bind(done);221222if (borrow_reg) {223__ pop(RegSet::of(tmp), sp);224}225}226227void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, Register dst, Address load_addr, DecoratorSet decorators) {228assert(ShenandoahLoadRefBarrier, "Should be enabled");229assert(dst != rscratch2, "need rscratch2");230assert_different_registers(load_addr.base(), load_addr.index(), rscratch1, rscratch2);231232bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators);233bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators);234bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators);235bool is_native = ShenandoahBarrierSet::is_native_access(decorators);236bool is_narrow = UseCompressedOops && !is_native;237238Label heap_stable, not_cset;239__ enter();240Address gc_state(rthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));241__ ldrb(rscratch2, gc_state);242243// Check for heap stability244if (is_strong) {245__ tbz(rscratch2, ShenandoahHeap::HAS_FORWARDED_BITPOS, heap_stable);246} else {247Label lrb;248__ tbnz(rscratch2, ShenandoahHeap::WEAK_ROOTS_BITPOS, lrb);249__ tbz(rscratch2, ShenandoahHeap::HAS_FORWARDED_BITPOS, heap_stable);250__ bind(lrb);251}252253// use r1 for load address254Register result_dst = dst;255if (dst == r1) {256__ mov(rscratch1, dst);257dst = rscratch1;258}259260// Save r0 and r1, unless it is an output register261RegSet to_save = RegSet::of(r0, r1) - result_dst;262__ push(to_save, sp);263__ lea(r1, load_addr);264__ mov(r0, dst);265266// Test for in-cset267if (is_strong) {268__ mov(rscratch2, ShenandoahHeap::in_cset_fast_test_addr());269__ lsr(rscratch1, r0, ShenandoahHeapRegion::region_size_bytes_shift_jint());270__ ldrb(rscratch2, Address(rscratch2, rscratch1));271__ tbz(rscratch2, 0, not_cset);272}273274__ push_call_clobbered_registers();275if (is_strong) {276if (is_narrow) {277__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow));278} else {279__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong));280}281} else if (is_weak) {282if (is_narrow) {283__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow));284} else {285__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak));286}287} else {288assert(is_phantom, "only remaining strength");289assert(!is_narrow, "phantom access cannot be narrow");290__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom));291}292__ blr(lr);293__ mov(rscratch1, r0);294__ pop_call_clobbered_registers();295__ mov(r0, rscratch1);296297__ bind(not_cset);298299__ mov(result_dst, r0);300__ pop(to_save, sp);301302__ bind(heap_stable);303__ leave();304}305306void ShenandoahBarrierSetAssembler::iu_barrier(MacroAssembler* masm, Register dst, Register tmp) {307if (ShenandoahIUBarrier) {308__ push_call_clobbered_registers();309satb_write_barrier_pre(masm, noreg, dst, rthread, tmp, true, false);310__ pop_call_clobbered_registers();311}312}313314//315// Arguments:316//317// Inputs:318// src: oop location to load from, might be clobbered319//320// Output:321// dst: oop loaded from src location322//323// Kill:324// rscratch1 (scratch reg)325//326// Alias:327// dst: rscratch1 (might use rscratch1 as temporary output register to avoid clobbering src)328//329void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,330Register dst, Address src, Register tmp1, Register tmp_thread) {331// 1: non-reference load, no additional barrier is needed332if (!is_reference_type(type)) {333BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread);334return;335}336337// 2: load a reference from src location and apply LRB if needed338if (ShenandoahBarrierSet::need_load_reference_barrier(decorators, type)) {339Register result_dst = dst;340341// Preserve src location for LRB342if (dst == src.base() || dst == src.index()) {343dst = rscratch1;344}345assert_different_registers(dst, src.base(), src.index());346347BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread);348349load_reference_barrier(masm, dst, src, decorators);350351if (dst != result_dst) {352__ mov(result_dst, dst);353dst = result_dst;354}355} else {356BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread);357}358359// 3: apply keep-alive barrier if needed360if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) {361__ enter();362__ push_call_clobbered_registers();363satb_write_barrier_pre(masm /* masm */,364noreg /* obj */,365dst /* pre_val */,366rthread /* thread */,367tmp1 /* tmp */,368true /* tosca_live */,369true /* expand_call */);370__ pop_call_clobbered_registers();371__ leave();372}373}374375void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,376Address dst, Register val, Register tmp1, Register tmp2) {377bool on_oop = is_reference_type(type);378if (!on_oop) {379BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2);380return;381}382383// flatten object address if needed384if (dst.index() == noreg && dst.offset() == 0) {385if (dst.base() != r3) {386__ mov(r3, dst.base());387}388} else {389__ lea(r3, dst);390}391392shenandoah_write_barrier_pre(masm,393r3 /* obj */,394tmp2 /* pre_val */,395rthread /* thread */,396tmp1 /* tmp */,397val != noreg /* tosca_live */,398false /* expand_call */);399400if (val == noreg) {401BarrierSetAssembler::store_at(masm, decorators, type, Address(r3, 0), noreg, noreg, noreg);402} else {403iu_barrier(masm, val, tmp1);404// G1 barrier needs uncompressed oop for region cross check.405Register new_val = val;406if (UseCompressedOops) {407new_val = rscratch2;408__ mov(new_val, val);409}410BarrierSetAssembler::store_at(masm, decorators, type, Address(r3, 0), val, noreg, noreg);411}412413}414415void ShenandoahBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env,416Register obj, Register tmp, Label& slowpath) {417Label done;418// Resolve jobject419BarrierSetAssembler::try_resolve_jobject_in_native(masm, jni_env, obj, tmp, slowpath);420421// Check for null.422__ cbz(obj, done);423424assert(obj != rscratch2, "need rscratch2");425Address gc_state(jni_env, ShenandoahThreadLocalData::gc_state_offset() - JavaThread::jni_environment_offset());426__ lea(rscratch2, gc_state);427__ ldrb(rscratch2, Address(rscratch2));428429// Check for heap in evacuation phase430__ tbnz(rscratch2, ShenandoahHeap::EVACUATION_BITPOS, slowpath);431432__ bind(done);433}434435// Special Shenandoah CAS implementation that handles false negatives due436// to concurrent evacuation. The service is more complex than a437// traditional CAS operation because the CAS operation is intended to438// succeed if the reference at addr exactly matches expected or if the439// reference at addr holds a pointer to a from-space object that has440// been relocated to the location named by expected. There are two441// races that must be addressed:442// a) A parallel thread may mutate the contents of addr so that it points443// to a different object. In this case, the CAS operation should fail.444// b) A parallel thread may heal the contents of addr, replacing a445// from-space pointer held in addr with the to-space pointer446// representing the new location of the object.447// Upon entry to cmpxchg_oop, it is assured that new_val equals NULL448// or it refers to an object that is not being evacuated out of449// from-space, or it refers to the to-space version of an object that450// is being evacuated out of from-space.451//452// By default the value held in the result register following execution453// of the generated code sequence is 0 to indicate failure of CAS,454// non-zero to indicate success. If is_cae, the result is the value most455// recently fetched from addr rather than a boolean success indicator.456//457// Clobbers rscratch1, rscratch2458void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm,459Register addr,460Register expected,461Register new_val,462bool acquire, bool release,463bool is_cae,464Register result) {465Register tmp1 = rscratch1;466Register tmp2 = rscratch2;467bool is_narrow = UseCompressedOops;468Assembler::operand_size size = is_narrow ? Assembler::word : Assembler::xword;469470assert_different_registers(addr, expected, tmp1, tmp2);471assert_different_registers(addr, new_val, tmp1, tmp2);472473Label step4, done;474475// There are two ways to reach this label. Initial entry into the476// cmpxchg_oop code expansion starts at step1 (which is equivalent477// to label step4). Additionally, in the rare case that four steps478// are required to perform the requested operation, the fourth step479// is the same as the first. On a second pass through step 1,480// control may flow through step 2 on its way to failure. It will481// not flow from step 2 to step 3 since we are assured that the482// memory at addr no longer holds a from-space pointer.483//484// The comments that immediately follow the step4 label apply only485// to the case in which control reaches this label by branch from486// step 3.487488__ bind (step4);489490// Step 4. CAS has failed because the value most recently fetched491// from addr is no longer the from-space pointer held in tmp2. If a492// different thread replaced the in-memory value with its equivalent493// to-space pointer, then CAS may still be able to succeed. The494// value held in the expected register has not changed.495//496// It is extremely rare we reach this point. For this reason, the497// implementation opts for smaller rather than potentially faster498// code. Ultimately, smaller code for this rare case most likely499// delivers higher overall throughput by enabling improved icache500// performance.501502// Step 1. Fast-path.503//504// Try to CAS with given arguments. If successful, then we are done.505//506// No label required for step 1.507508__ cmpxchg(addr, expected, new_val, size, acquire, release, false, tmp2);509// EQ flag set iff success. tmp2 holds value fetched.510511// If expected equals null but tmp2 does not equal null, the512// following branches to done to report failure of CAS. If both513// expected and tmp2 equal null, the following branches to done to514// report success of CAS. There's no need for a special test of515// expected equal to null.516517__ br(Assembler::EQ, done);518// if CAS failed, fall through to step 2519520// Step 2. CAS has failed because the value held at addr does not521// match expected. This may be a false negative because the value fetched522// from addr (now held in tmp2) may be a from-space pointer to the523// original copy of same object referenced by to-space pointer expected.524//525// To resolve this, it suffices to find the forward pointer associated526// with fetched value. If this matches expected, retry CAS with new527// parameters. If this mismatches, then we have a legitimate528// failure, and we're done.529//530// No need for step2 label.531532// overwrite tmp1 with from-space pointer fetched from memory533__ mov(tmp1, tmp2);534535if (is_narrow) {536// Decode tmp1 in order to resolve its forward pointer537__ decode_heap_oop(tmp1, tmp1);538}539resolve_forward_pointer(masm, tmp1);540// Encode tmp1 to compare against expected.541__ encode_heap_oop(tmp1, tmp1);542543// Does forwarded value of fetched from-space pointer match original544// value of expected? If tmp1 holds null, this comparison will fail545// because we know from step1 that expected is not null. There is546// no need for a separate test for tmp1 (the value originally held547// in memory) equal to null.548__ cmp(tmp1, expected);549550// If not, then the failure was legitimate and we're done.551// Branching to done with NE condition denotes failure.552__ br(Assembler::NE, done);553554// Fall through to step 3. No need for step3 label.555556// Step 3. We've confirmed that the value originally held in memory557// (now held in tmp2) pointed to from-space version of original558// expected value. Try the CAS again with the from-space expected559// value. If it now succeeds, we're good.560//561// Note: tmp2 holds encoded from-space pointer that matches to-space562// object residing at expected. tmp2 is the new "expected".563564// Note that macro implementation of __cmpxchg cannot use same register565// tmp2 for result and expected since it overwrites result before it566// compares result with expected.567__ cmpxchg(addr, tmp2, new_val, size, acquire, release, false, noreg);568// EQ flag set iff success. tmp2 holds value fetched, tmp1 (rscratch1) clobbered.569570// If fetched value did not equal the new expected, this could571// still be a false negative because some other thread may have572// newly overwritten the memory value with its to-space equivalent.573__ br(Assembler::NE, step4);574575if (is_cae) {576// We're falling through to done to indicate success. Success577// with is_cae is denoted by returning the value of expected as578// result.579__ mov(tmp2, expected);580}581582__ bind(done);583// At entry to done, the Z (EQ) flag is on iff if the CAS584// operation was successful. Additionally, if is_cae, tmp2 holds585// the value most recently fetched from addr. In this case, success586// is denoted by tmp2 matching expected.587588if (is_cae) {589__ mov(result, tmp2);590} else {591__ cset(result, Assembler::EQ);592}593}594595#undef __596597#ifdef COMPILER1598599#define __ ce->masm()->600601void ShenandoahBarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub) {602ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();603// At this point we know that marking is in progress.604// If do_load() is true then we have to emit the605// load of the previous value; otherwise it has already606// been loaded into _pre_val.607608__ bind(*stub->entry());609610assert(stub->pre_val()->is_register(), "Precondition.");611612Register pre_val_reg = stub->pre_val()->as_register();613614if (stub->do_load()) {615ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/, false /*unaligned*/);616}617__ cbz(pre_val_reg, *stub->continuation());618ce->store_parameter(stub->pre_val()->as_register(), 0);619__ far_call(RuntimeAddress(bs->pre_barrier_c1_runtime_code_blob()->code_begin()));620__ b(*stub->continuation());621}622623void ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub(LIR_Assembler* ce, ShenandoahLoadReferenceBarrierStub* stub) {624ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1();625__ bind(*stub->entry());626627DecoratorSet decorators = stub->decorators();628bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators);629bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators);630bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators);631bool is_native = ShenandoahBarrierSet::is_native_access(decorators);632633Register obj = stub->obj()->as_register();634Register res = stub->result()->as_register();635Register addr = stub->addr()->as_pointer_register();636Register tmp1 = stub->tmp1()->as_register();637Register tmp2 = stub->tmp2()->as_register();638639assert(res == r0, "result must arrive in r0");640641if (res != obj) {642__ mov(res, obj);643}644645if (is_strong) {646// Check for object in cset.647__ mov(tmp2, ShenandoahHeap::in_cset_fast_test_addr());648__ lsr(tmp1, res, ShenandoahHeapRegion::region_size_bytes_shift_jint());649__ ldrb(tmp2, Address(tmp2, tmp1));650__ cbz(tmp2, *stub->continuation());651}652653ce->store_parameter(res, 0);654ce->store_parameter(addr, 1);655if (is_strong) {656if (is_native) {657__ far_call(RuntimeAddress(bs->load_reference_barrier_strong_native_rt_code_blob()->code_begin()));658} else {659__ far_call(RuntimeAddress(bs->load_reference_barrier_strong_rt_code_blob()->code_begin()));660}661} else if (is_weak) {662__ far_call(RuntimeAddress(bs->load_reference_barrier_weak_rt_code_blob()->code_begin()));663} else {664assert(is_phantom, "only remaining strength");665__ far_call(RuntimeAddress(bs->load_reference_barrier_phantom_rt_code_blob()->code_begin()));666}667668__ b(*stub->continuation());669}670671#undef __672673#define __ sasm->674675void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) {676__ prologue("shenandoah_pre_barrier", false);677678// arg0 : previous value of memory679680BarrierSet* bs = BarrierSet::barrier_set();681682const Register pre_val = r0;683const Register thread = rthread;684const Register tmp = rscratch1;685686Address queue_index(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()));687Address buffer(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()));688689Label done;690Label runtime;691692// Is marking still active?693Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));694__ ldrb(tmp, gc_state);695__ tbz(tmp, ShenandoahHeap::MARKING_BITPOS, done);696697// Can we store original value in the thread's buffer?698__ ldr(tmp, queue_index);699__ cbz(tmp, runtime);700701__ sub(tmp, tmp, wordSize);702__ str(tmp, queue_index);703__ ldr(rscratch2, buffer);704__ add(tmp, tmp, rscratch2);705__ load_parameter(0, rscratch2);706__ str(rscratch2, Address(tmp, 0));707__ b(done);708709__ bind(runtime);710__ push_call_clobbered_registers();711__ load_parameter(0, pre_val);712__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread);713__ pop_call_clobbered_registers();714__ bind(done);715716__ epilogue();717}718719void ShenandoahBarrierSetAssembler::generate_c1_load_reference_barrier_runtime_stub(StubAssembler* sasm, DecoratorSet decorators) {720__ prologue("shenandoah_load_reference_barrier", false);721// arg0 : object to be resolved722723__ push_call_clobbered_registers();724__ load_parameter(0, r0);725__ load_parameter(1, r1);726727bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators);728bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators);729bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators);730bool is_native = ShenandoahBarrierSet::is_native_access(decorators);731if (is_strong) {732if (is_native) {733__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong));734} else {735if (UseCompressedOops) {736__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow));737} else {738__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong));739}740}741} else if (is_weak) {742assert(!is_native, "weak must not be called off-heap");743if (UseCompressedOops) {744__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow));745} else {746__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak));747}748} else {749assert(is_phantom, "only remaining strength");750assert(is_native, "phantom must only be called off-heap");751__ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom));752}753__ blr(lr);754__ mov(rscratch1, r0);755__ pop_call_clobbered_registers();756__ mov(r0, rscratch1);757758__ epilogue();759}760761#undef __762763#endif // COMPILER1764765766