Path: blob/master/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp
41153 views
/*1* Copyright (c) 2018, 2021, 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*/2223#include "precompiled.hpp"24#include "asm/macroAssembler.inline.hpp"25#include "code/codeBlob.hpp"26#include "code/vmreg.inline.hpp"27#include "gc/z/zBarrier.inline.hpp"28#include "gc/z/zBarrierSet.hpp"29#include "gc/z/zBarrierSetAssembler.hpp"30#include "gc/z/zBarrierSetRuntime.hpp"31#include "memory/resourceArea.hpp"32#include "runtime/sharedRuntime.hpp"33#include "utilities/macros.hpp"34#ifdef COMPILER135#include "c1/c1_LIRAssembler.hpp"36#include "c1/c1_MacroAssembler.hpp"37#include "gc/z/c1/zBarrierSetC1.hpp"38#endif // COMPILER139#ifdef COMPILER240#include "gc/z/c2/zBarrierSetC2.hpp"41#endif // COMPILER24243#ifdef PRODUCT44#define BLOCK_COMMENT(str) /* nothing */45#else46#define BLOCK_COMMENT(str) __ block_comment(str)47#endif4849#undef __50#define __ masm->5152static void call_vm(MacroAssembler* masm,53address entry_point,54Register arg0,55Register arg1) {56// Setup arguments57if (arg1 == c_rarg0) {58if (arg0 == c_rarg1) {59__ xchgptr(c_rarg1, c_rarg0);60} else {61__ movptr(c_rarg1, arg1);62__ movptr(c_rarg0, arg0);63}64} else {65if (arg0 != c_rarg0) {66__ movptr(c_rarg0, arg0);67}68if (arg1 != c_rarg1) {69__ movptr(c_rarg1, arg1);70}71}7273// Call VM74__ MacroAssembler::call_VM_leaf_base(entry_point, 2);75}7677void ZBarrierSetAssembler::load_at(MacroAssembler* masm,78DecoratorSet decorators,79BasicType type,80Register dst,81Address src,82Register tmp1,83Register tmp_thread) {84if (!ZBarrierSet::barrier_needed(decorators, type)) {85// Barrier not needed86BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread);87return;88}8990BLOCK_COMMENT("ZBarrierSetAssembler::load_at {");9192// Allocate scratch register93Register scratch = tmp1;94if (tmp1 == noreg) {95scratch = r12;96__ push(scratch);97}9899assert_different_registers(dst, scratch);100101Label done;102103//104// Fast Path105//106107// Load address108__ lea(scratch, src);109110// Load oop at address111__ movptr(dst, Address(scratch, 0));112113// Test address bad mask114__ testptr(dst, address_bad_mask_from_thread(r15_thread));115__ jcc(Assembler::zero, done);116117//118// Slow path119//120121// Save registers122__ push(rax);123__ push(rcx);124__ push(rdx);125__ push(rdi);126__ push(rsi);127__ push(r8);128__ push(r9);129__ push(r10);130__ push(r11);131132// We may end up here from generate_native_wrapper, then the method may have133// floats as arguments, and we must spill them before calling the VM runtime134// leaf. From the interpreter all floats are passed on the stack.135assert(Argument::n_float_register_parameters_j == 8, "Assumption");136const int xmm_size = wordSize * 2;137const int xmm_spill_size = xmm_size * Argument::n_float_register_parameters_j;138__ subptr(rsp, xmm_spill_size);139__ movdqu(Address(rsp, xmm_size * 7), xmm7);140__ movdqu(Address(rsp, xmm_size * 6), xmm6);141__ movdqu(Address(rsp, xmm_size * 5), xmm5);142__ movdqu(Address(rsp, xmm_size * 4), xmm4);143__ movdqu(Address(rsp, xmm_size * 3), xmm3);144__ movdqu(Address(rsp, xmm_size * 2), xmm2);145__ movdqu(Address(rsp, xmm_size * 1), xmm1);146__ movdqu(Address(rsp, xmm_size * 0), xmm0);147148// Call VM149call_vm(masm, ZBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr(decorators), dst, scratch);150151__ movdqu(xmm0, Address(rsp, xmm_size * 0));152__ movdqu(xmm1, Address(rsp, xmm_size * 1));153__ movdqu(xmm2, Address(rsp, xmm_size * 2));154__ movdqu(xmm3, Address(rsp, xmm_size * 3));155__ movdqu(xmm4, Address(rsp, xmm_size * 4));156__ movdqu(xmm5, Address(rsp, xmm_size * 5));157__ movdqu(xmm6, Address(rsp, xmm_size * 6));158__ movdqu(xmm7, Address(rsp, xmm_size * 7));159__ addptr(rsp, xmm_spill_size);160161__ pop(r11);162__ pop(r10);163__ pop(r9);164__ pop(r8);165__ pop(rsi);166__ pop(rdi);167__ pop(rdx);168__ pop(rcx);169170if (dst == rax) {171__ addptr(rsp, wordSize);172} else {173__ movptr(dst, rax);174__ pop(rax);175}176177__ bind(done);178179// Restore scratch register180if (tmp1 == noreg) {181__ pop(scratch);182}183184BLOCK_COMMENT("} ZBarrierSetAssembler::load_at");185}186187#ifdef ASSERT188189void ZBarrierSetAssembler::store_at(MacroAssembler* masm,190DecoratorSet decorators,191BasicType type,192Address dst,193Register src,194Register tmp1,195Register tmp2) {196BLOCK_COMMENT("ZBarrierSetAssembler::store_at {");197198// Verify oop store199if (is_reference_type(type)) {200// Note that src could be noreg, which means we201// are storing null and can skip verification.202if (src != noreg) {203Label done;204__ testptr(src, address_bad_mask_from_thread(r15_thread));205__ jcc(Assembler::zero, done);206__ stop("Verify oop store failed");207__ should_not_reach_here();208__ bind(done);209}210}211212// Store value213BarrierSetAssembler::store_at(masm, decorators, type, dst, src, tmp1, tmp2);214215BLOCK_COMMENT("} ZBarrierSetAssembler::store_at");216}217218#endif // ASSERT219220void ZBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm,221DecoratorSet decorators,222BasicType type,223Register src,224Register dst,225Register count) {226if (!ZBarrierSet::barrier_needed(decorators, type)) {227// Barrier not needed228return;229}230231BLOCK_COMMENT("ZBarrierSetAssembler::arraycopy_prologue {");232233// Save registers234__ pusha();235236// Call VM237call_vm(masm, ZBarrierSetRuntime::load_barrier_on_oop_array_addr(), src, count);238239// Restore registers240__ popa();241242BLOCK_COMMENT("} ZBarrierSetAssembler::arraycopy_prologue");243}244245void ZBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm,246Register jni_env,247Register obj,248Register tmp,249Label& slowpath) {250BLOCK_COMMENT("ZBarrierSetAssembler::try_resolve_jobject_in_native {");251252// Resolve jobject253BarrierSetAssembler::try_resolve_jobject_in_native(masm, jni_env, obj, tmp, slowpath);254255// Test address bad mask256__ testptr(obj, address_bad_mask_from_jni_env(jni_env));257__ jcc(Assembler::notZero, slowpath);258259BLOCK_COMMENT("} ZBarrierSetAssembler::try_resolve_jobject_in_native");260}261262#ifdef COMPILER1263264#undef __265#define __ ce->masm()->266267void ZBarrierSetAssembler::generate_c1_load_barrier_test(LIR_Assembler* ce,268LIR_Opr ref) const {269__ testptr(ref->as_register(), address_bad_mask_from_thread(r15_thread));270}271272void ZBarrierSetAssembler::generate_c1_load_barrier_stub(LIR_Assembler* ce,273ZLoadBarrierStubC1* stub) const {274// Stub entry275__ bind(*stub->entry());276277Register ref = stub->ref()->as_register();278Register ref_addr = noreg;279Register tmp = noreg;280281if (stub->tmp()->is_valid()) {282// Load address into tmp register283ce->leal(stub->ref_addr(), stub->tmp());284ref_addr = tmp = stub->tmp()->as_pointer_register();285} else {286// Address already in register287ref_addr = stub->ref_addr()->as_address_ptr()->base()->as_pointer_register();288}289290assert_different_registers(ref, ref_addr, noreg);291292// Save rax unless it is the result or tmp register293if (ref != rax && tmp != rax) {294__ push(rax);295}296297// Setup arguments and call runtime stub298__ subptr(rsp, 2 * BytesPerWord);299ce->store_parameter(ref_addr, 1);300ce->store_parameter(ref, 0);301__ call(RuntimeAddress(stub->runtime_stub()));302__ addptr(rsp, 2 * BytesPerWord);303304// Verify result305__ verify_oop(rax);306307// Move result into place308if (ref != rax) {309__ movptr(ref, rax);310}311312// Restore rax unless it is the result or tmp register313if (ref != rax && tmp != rax) {314__ pop(rax);315}316317// Stub exit318__ jmp(*stub->continuation());319}320321#undef __322#define __ sasm->323324void ZBarrierSetAssembler::generate_c1_load_barrier_runtime_stub(StubAssembler* sasm,325DecoratorSet decorators) const {326// Enter and save registers327__ enter();328__ save_live_registers_no_oop_map(true /* save_fpu_registers */);329330// Setup arguments331__ load_parameter(1, c_rarg1);332__ load_parameter(0, c_rarg0);333334// Call VM335__ call_VM_leaf(ZBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr(decorators), c_rarg0, c_rarg1);336337// Restore registers and return338__ restore_live_registers_except_rax(true /* restore_fpu_registers */);339__ leave();340__ ret(0);341}342343#endif // COMPILER1344345#ifdef COMPILER2346347OptoReg::Name ZBarrierSetAssembler::refine_register(const Node* node, OptoReg::Name opto_reg) {348if (!OptoReg::is_reg(opto_reg)) {349return OptoReg::Bad;350}351352const VMReg vm_reg = OptoReg::as_VMReg(opto_reg);353if (vm_reg->is_XMMRegister()) {354opto_reg &= ~15;355switch (node->ideal_reg()) {356case Op_VecX:357opto_reg |= 2;358break;359case Op_VecY:360opto_reg |= 4;361break;362case Op_VecZ:363opto_reg |= 8;364break;365default:366opto_reg |= 1;367break;368}369}370371return opto_reg;372}373374// We use the vec_spill_helper from the x86.ad file to avoid reinventing this wheel375extern void vec_spill_helper(CodeBuffer *cbuf, bool is_load,376int stack_offset, int reg, uint ireg, outputStream* st);377378#undef __379#define __ _masm->380381class ZSaveLiveRegisters {382private:383struct XMMRegisterData {384XMMRegister _reg;385int _size;386387// Used by GrowableArray::find()388bool operator == (const XMMRegisterData& other) {389return _reg == other._reg;390}391};392393MacroAssembler* const _masm;394GrowableArray<Register> _gp_registers;395GrowableArray<KRegister> _opmask_registers;396GrowableArray<XMMRegisterData> _xmm_registers;397int _spill_size;398int _spill_offset;399400static int xmm_compare_register_size(XMMRegisterData* left, XMMRegisterData* right) {401if (left->_size == right->_size) {402return 0;403}404405return (left->_size < right->_size) ? -1 : 1;406}407408static int xmm_slot_size(OptoReg::Name opto_reg) {409// The low order 4 bytes denote what size of the XMM register is live410return (opto_reg & 15) << 3;411}412413static uint xmm_ideal_reg_for_size(int reg_size) {414switch (reg_size) {415case 8:416return Op_VecD;417case 16:418return Op_VecX;419case 32:420return Op_VecY;421case 64:422return Op_VecZ;423default:424fatal("Invalid register size %d", reg_size);425return 0;426}427}428429bool xmm_needs_vzeroupper() const {430return _xmm_registers.is_nonempty() && _xmm_registers.at(0)._size > 16;431}432433void xmm_register_save(const XMMRegisterData& reg_data) {434const OptoReg::Name opto_reg = OptoReg::as_OptoReg(reg_data._reg->as_VMReg());435const uint ideal_reg = xmm_ideal_reg_for_size(reg_data._size);436_spill_offset -= reg_data._size;437vec_spill_helper(__ code(), false /* is_load */, _spill_offset, opto_reg, ideal_reg, tty);438}439440void xmm_register_restore(const XMMRegisterData& reg_data) {441const OptoReg::Name opto_reg = OptoReg::as_OptoReg(reg_data._reg->as_VMReg());442const uint ideal_reg = xmm_ideal_reg_for_size(reg_data._size);443vec_spill_helper(__ code(), true /* is_load */, _spill_offset, opto_reg, ideal_reg, tty);444_spill_offset += reg_data._size;445}446447void gp_register_save(Register reg) {448_spill_offset -= 8;449__ movq(Address(rsp, _spill_offset), reg);450}451452void opmask_register_save(KRegister reg) {453_spill_offset -= 8;454__ kmovql(Address(rsp, _spill_offset), reg);455}456457void gp_register_restore(Register reg) {458__ movq(reg, Address(rsp, _spill_offset));459_spill_offset += 8;460}461462void opmask_register_restore(KRegister reg) {463__ kmovql(reg, Address(rsp, _spill_offset));464_spill_offset += 8;465}466467void initialize(ZLoadBarrierStubC2* stub) {468// Create mask of caller saved registers that need to469// be saved/restored if live470RegMask caller_saved;471caller_saved.Insert(OptoReg::as_OptoReg(rax->as_VMReg()));472caller_saved.Insert(OptoReg::as_OptoReg(rcx->as_VMReg()));473caller_saved.Insert(OptoReg::as_OptoReg(rdx->as_VMReg()));474caller_saved.Insert(OptoReg::as_OptoReg(rsi->as_VMReg()));475caller_saved.Insert(OptoReg::as_OptoReg(rdi->as_VMReg()));476caller_saved.Insert(OptoReg::as_OptoReg(r8->as_VMReg()));477caller_saved.Insert(OptoReg::as_OptoReg(r9->as_VMReg()));478caller_saved.Insert(OptoReg::as_OptoReg(r10->as_VMReg()));479caller_saved.Insert(OptoReg::as_OptoReg(r11->as_VMReg()));480caller_saved.Remove(OptoReg::as_OptoReg(stub->ref()->as_VMReg()));481482// Create mask of live registers483RegMask live = stub->live();484if (stub->tmp() != noreg) {485live.Insert(OptoReg::as_OptoReg(stub->tmp()->as_VMReg()));486}487488int gp_spill_size = 0;489int opmask_spill_size = 0;490int xmm_spill_size = 0;491492// Record registers that needs to be saved/restored493RegMaskIterator rmi(live);494while (rmi.has_next()) {495const OptoReg::Name opto_reg = rmi.next();496const VMReg vm_reg = OptoReg::as_VMReg(opto_reg);497498if (vm_reg->is_Register()) {499if (caller_saved.Member(opto_reg)) {500_gp_registers.append(vm_reg->as_Register());501gp_spill_size += 8;502}503} else if (vm_reg->is_KRegister()) {504// All opmask registers are caller saved, thus spill the ones505// which are live.506if (_opmask_registers.find(vm_reg->as_KRegister()) == -1) {507_opmask_registers.append(vm_reg->as_KRegister());508opmask_spill_size += 8;509}510} else if (vm_reg->is_XMMRegister()) {511// We encode in the low order 4 bits of the opto_reg, how large part of the register is live512const VMReg vm_reg_base = OptoReg::as_VMReg(opto_reg & ~15);513const int reg_size = xmm_slot_size(opto_reg);514const XMMRegisterData reg_data = { vm_reg_base->as_XMMRegister(), reg_size };515const int reg_index = _xmm_registers.find(reg_data);516if (reg_index == -1) {517// Not previously appended518_xmm_registers.append(reg_data);519xmm_spill_size += reg_size;520} else {521// Previously appended, update size522const int reg_size_prev = _xmm_registers.at(reg_index)._size;523if (reg_size > reg_size_prev) {524_xmm_registers.at_put(reg_index, reg_data);525xmm_spill_size += reg_size - reg_size_prev;526}527}528} else {529fatal("Unexpected register type");530}531}532533// Sort by size, largest first534_xmm_registers.sort(xmm_compare_register_size);535536// On Windows, the caller reserves stack space for spilling register arguments537const int arg_spill_size = frame::arg_reg_save_area_bytes;538539// Stack pointer must be 16 bytes aligned for the call540_spill_offset = _spill_size = align_up(xmm_spill_size + gp_spill_size + opmask_spill_size + arg_spill_size, 16);541}542543public:544ZSaveLiveRegisters(MacroAssembler* masm, ZLoadBarrierStubC2* stub) :545_masm(masm),546_gp_registers(),547_opmask_registers(),548_xmm_registers(),549_spill_size(0),550_spill_offset(0) {551552//553// Stack layout after registers have been spilled:554//555// | ... | original rsp, 16 bytes aligned556// ------------------557// | zmm0 high |558// | ... |559// | zmm0 low | 16 bytes aligned560// | ... |561// | ymm1 high |562// | ... |563// | ymm1 low | 16 bytes aligned564// | ... |565// | xmmN high |566// | ... |567// | xmmN low | 8 bytes aligned568// | reg0 | 8 bytes aligned569// | reg1 |570// | ... |571// | regN | new rsp, if 16 bytes aligned572// | <padding> | else new rsp, 16 bytes aligned573// ------------------574//575576// Figure out what registers to save/restore577initialize(stub);578579// Allocate stack space580if (_spill_size > 0) {581__ subptr(rsp, _spill_size);582}583584// Save XMM/YMM/ZMM registers585for (int i = 0; i < _xmm_registers.length(); i++) {586xmm_register_save(_xmm_registers.at(i));587}588589if (xmm_needs_vzeroupper()) {590__ vzeroupper();591}592593// Save general purpose registers594for (int i = 0; i < _gp_registers.length(); i++) {595gp_register_save(_gp_registers.at(i));596}597598// Save opmask registers599for (int i = 0; i < _opmask_registers.length(); i++) {600opmask_register_save(_opmask_registers.at(i));601}602}603604~ZSaveLiveRegisters() {605// Restore opmask registers606for (int i = _opmask_registers.length() - 1; i >= 0; i--) {607opmask_register_restore(_opmask_registers.at(i));608}609610// Restore general purpose registers611for (int i = _gp_registers.length() - 1; i >= 0; i--) {612gp_register_restore(_gp_registers.at(i));613}614615__ vzeroupper();616617// Restore XMM/YMM/ZMM registers618for (int i = _xmm_registers.length() - 1; i >= 0; i--) {619xmm_register_restore(_xmm_registers.at(i));620}621622// Free stack space623if (_spill_size > 0) {624__ addptr(rsp, _spill_size);625}626}627};628629class ZSetupArguments {630private:631MacroAssembler* const _masm;632const Register _ref;633const Address _ref_addr;634635public:636ZSetupArguments(MacroAssembler* masm, ZLoadBarrierStubC2* stub) :637_masm(masm),638_ref(stub->ref()),639_ref_addr(stub->ref_addr()) {640641// Setup arguments642if (_ref_addr.base() == noreg) {643// No self healing644if (_ref != c_rarg0) {645__ movq(c_rarg0, _ref);646}647__ xorq(c_rarg1, c_rarg1);648} else {649// Self healing650if (_ref == c_rarg0) {651__ lea(c_rarg1, _ref_addr);652} else if (_ref != c_rarg1) {653__ lea(c_rarg1, _ref_addr);654__ movq(c_rarg0, _ref);655} else if (_ref_addr.base() != c_rarg0 && _ref_addr.index() != c_rarg0) {656__ movq(c_rarg0, _ref);657__ lea(c_rarg1, _ref_addr);658} else {659__ xchgq(c_rarg0, c_rarg1);660if (_ref_addr.base() == c_rarg0) {661__ lea(c_rarg1, Address(c_rarg1, _ref_addr.index(), _ref_addr.scale(), _ref_addr.disp()));662} else if (_ref_addr.index() == c_rarg0) {663__ lea(c_rarg1, Address(_ref_addr.base(), c_rarg1, _ref_addr.scale(), _ref_addr.disp()));664} else {665ShouldNotReachHere();666}667}668}669}670671~ZSetupArguments() {672// Transfer result673if (_ref != rax) {674__ movq(_ref, rax);675}676}677};678679#undef __680#define __ masm->681682void ZBarrierSetAssembler::generate_c2_load_barrier_stub(MacroAssembler* masm, ZLoadBarrierStubC2* stub) const {683BLOCK_COMMENT("ZLoadBarrierStubC2");684685// Stub entry686__ bind(*stub->entry());687688{689ZSaveLiveRegisters save_live_registers(masm, stub);690ZSetupArguments setup_arguments(masm, stub);691__ call(RuntimeAddress(stub->slow_path()));692}693694// Stub exit695__ jmp(*stub->continuation());696}697698#undef __699700#endif // COMPILER2701702703