--- /dev/null 2018-04-03 12:55:20.301839954 +0200 +++ new/src/hotspot/share/gc/z/c1/zBarrierSetC1.cpp 2018-06-08 19:45:48.263335203 +0200 @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "c1/c1_LIR.hpp" +#include "c1/c1_LIRGenerator.hpp" +#include "c1/c1_CodeStubs.hpp" +#include "gc/z/c1/zBarrierSetC1.hpp" +#include "gc/z/zBarrierSet.hpp" +#include "gc/z/zBarrierSetAssembler.hpp" +#include "gc/z/zThreadLocalData.hpp" +#include "utilities/macros.hpp" + +ZLoadBarrierStubC1::ZLoadBarrierStubC1(LIRAccess& access, LIR_Opr ref, address runtime_stub) : + _decorators(access.decorators()), + _ref_addr(access.resolved_addr()), + _ref(ref), + _tmp(LIR_OprFact::illegalOpr), + _patch_info(access.patch_emit_info()), + _runtime_stub(runtime_stub) { + + // Allocate tmp register if needed + if (!_ref_addr->is_register()) { + assert(_ref_addr->is_address(), "Must be an address"); + if (_ref_addr->as_address_ptr()->index()->is_valid() || + _ref_addr->as_address_ptr()->disp() != 0) { + // Has index or displacement, need tmp register to load address into + _tmp = access.gen()->new_pointer_register(); + } else { + // No index or displacement, address available in base register + _ref_addr = _ref_addr->as_address_ptr()->base(); + } + } + + assert(_ref->is_register(), "Must be a register"); + assert(_ref_addr->is_register() != _tmp->is_register(), "Only one should be a register"); +} + +DecoratorSet ZLoadBarrierStubC1::decorators() const { + return _decorators; +} + +LIR_Opr ZLoadBarrierStubC1::ref() const { + return _ref; +} + +LIR_Opr ZLoadBarrierStubC1::ref_addr() const { + return _ref_addr; +} + +LIR_Opr ZLoadBarrierStubC1::tmp() const { + return _tmp; +} + +LIR_PatchCode ZLoadBarrierStubC1::patch_code() const { + return (_decorators & C1_NEEDS_PATCHING) != 0 ? lir_patch_normal : lir_patch_none; +} + +CodeEmitInfo*& ZLoadBarrierStubC1::patch_info() { + return _patch_info; +} + +address ZLoadBarrierStubC1::runtime_stub() const { + return _runtime_stub; +} + +void ZLoadBarrierStubC1::visit(LIR_OpVisitState* visitor) { + if (_patch_info != NULL) { + visitor->do_slow_case(_patch_info); + } else { + visitor->do_slow_case(); + } + + visitor->do_input(_ref_addr); + visitor->do_output(_ref); + + if (_tmp->is_valid()) { + visitor->do_temp(_tmp); + } +} + +void ZLoadBarrierStubC1::emit_code(LIR_Assembler* ce) { + ZBarrierSet::assembler()->generate_c1_load_barrier_stub(ce, this); +} + +#ifndef PRODUCT +void ZLoadBarrierStubC1::print_name(outputStream* out) const { + out->print("ZLoadBarrierStubC1"); +} +#endif // PRODUCT + +class LIR_OpZLoadBarrierTest : public LIR_Op { +private: + LIR_Opr _opr; + +public: + LIR_OpZLoadBarrierTest(LIR_Opr opr) : + LIR_Op(), + _opr(opr) {} + + virtual void visit(LIR_OpVisitState* state) { + state->do_input(_opr); + } + + virtual void emit_code(LIR_Assembler* ce) { + ZBarrierSet::assembler()->generate_c1_load_barrier_test(ce, _opr); + } + + virtual void print_instr(outputStream* out) const { + _opr->print(out); + out->print(" "); + } + +#ifndef PRODUCT + virtual const char* name() const { + return "lir_z_load_barrier_test"; + } +#endif // PRODUCT +}; + +static bool barrier_needed(LIRAccess& access) { + return ZBarrierSet::barrier_needed(access.decorators(), access.type()); +} + +ZBarrierSetC1::ZBarrierSetC1() : + _load_barrier_on_oop_field_preloaded_runtime_stub(NULL), + _load_barrier_on_weak_oop_field_preloaded_runtime_stub(NULL) {} + +address ZBarrierSetC1::load_barrier_on_oop_field_preloaded_runtime_stub(DecoratorSet decorators) const { + assert((decorators & ON_PHANTOM_OOP_REF) == 0, "Unsupported decorator"); + //assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "Unsupported decorator"); + + if ((decorators & ON_WEAK_OOP_REF) != 0) { + return _load_barrier_on_weak_oop_field_preloaded_runtime_stub; + } else { + return _load_barrier_on_oop_field_preloaded_runtime_stub; + } +} + +#ifdef ASSERT +#define __ access.gen()->lir(__FILE__, __LINE__)-> +#else +#define __ access.gen()->lir()-> +#endif + +void ZBarrierSetC1::load_barrier(LIRAccess& access, LIR_Opr result) const { + // Fast path + __ append(new LIR_OpZLoadBarrierTest(result)); + + // Slow path + const address runtime_stub = load_barrier_on_oop_field_preloaded_runtime_stub(access.decorators()); + CodeStub* const stub = new ZLoadBarrierStubC1(access, result, runtime_stub); + __ branch(lir_cond_notEqual, T_ADDRESS, stub); + __ branch_destination(stub->continuation()); +} + +#undef __ + +void ZBarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) { + BarrierSetC1::load_at_resolved(access, result); + + if (barrier_needed(access)) { + load_barrier(access, result); + } +} + +static void pre_load_barrier(LIRAccess& access) { + DecoratorSet decorators = access.decorators(); + + // Downgrade access to MO_UNORDERED + decorators = (decorators & ~MO_DECORATOR_MASK) | MO_UNORDERED; + + // Remove C1_WRITE_ACCESS + decorators = (decorators & ~C1_WRITE_ACCESS); + + // Generate synthetic load at + access.gen()->access_load_at(decorators, + access.type(), + access.base().item(), + access.offset().opr(), + access.gen()->new_register(access.type()), + NULL /* patch_emit_info */, + NULL /* load_emit_info */); +} + +LIR_Opr ZBarrierSetC1::atomic_xchg_at_resolved(LIRAccess& access, LIRItem& value) { + if (barrier_needed(access)) { + pre_load_barrier(access); + } + + return BarrierSetC1::atomic_xchg_at_resolved(access, value); +} + +LIR_Opr ZBarrierSetC1::atomic_cmpxchg_at_resolved(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value) { + if (barrier_needed(access)) { + pre_load_barrier(access); + } + + return BarrierSetC1::atomic_cmpxchg_at_resolved(access, cmp_value, new_value); +} + +class ZLoadBarrierRuntimeStubCodeGenClosure : public StubAssemblerCodeGenClosure { +private: + const DecoratorSet _decorators; + +public: + ZLoadBarrierRuntimeStubCodeGenClosure(DecoratorSet decorators) : + _decorators(decorators) {} + + virtual OopMapSet* generate_code(StubAssembler* sasm) { + ZBarrierSet::assembler()->generate_c1_load_barrier_runtime_stub(sasm, _decorators); + return NULL; + } +}; + +static address generate_c1_runtime_stub(BufferBlob* blob, DecoratorSet decorators, const char* name) { + ZLoadBarrierRuntimeStubCodeGenClosure cl(decorators); + CodeBlob* const code_blob = Runtime1::generate_blob(blob, -1 /* stub_id */, name, false /* expect_oop_map*/, &cl); + return code_blob->code_begin(); +} + +void ZBarrierSetC1::generate_c1_runtime_stubs(BufferBlob* blob) { + _load_barrier_on_oop_field_preloaded_runtime_stub = + generate_c1_runtime_stub(blob, ON_STRONG_OOP_REF, "load_barrier_on_oop_field_preloaded_runtime_stub"); + _load_barrier_on_weak_oop_field_preloaded_runtime_stub = + generate_c1_runtime_stub(blob, ON_WEAK_OOP_REF, "load_barrier_on_weak_oop_field_preloaded_runtime_stub"); +}