Path: blob/master/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp
66646 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*22*/2324#include "precompiled.hpp"25#include "gc/shared/tlab_globals.hpp"26#include "gc/shared/c2/barrierSetC2.hpp"27#include "opto/arraycopynode.hpp"28#include "opto/convertnode.hpp"29#include "opto/graphKit.hpp"30#include "opto/idealKit.hpp"31#include "opto/macro.hpp"32#include "opto/narrowptrnode.hpp"33#include "opto/runtime.hpp"34#include "utilities/macros.hpp"3536// By default this is a no-op.37void BarrierSetC2::resolve_address(C2Access& access) const { }3839void* C2ParseAccess::barrier_set_state() const {40return _kit->barrier_set_state();41}4243PhaseGVN& C2ParseAccess::gvn() const { return _kit->gvn(); }4445bool C2Access::needs_cpu_membar() const {46bool mismatched = (_decorators & C2_MISMATCHED) != 0;47bool is_unordered = (_decorators & MO_UNORDERED) != 0;4849bool anonymous = (_decorators & C2_UNSAFE_ACCESS) != 0;50bool in_heap = (_decorators & IN_HEAP) != 0;51bool in_native = (_decorators & IN_NATIVE) != 0;52bool is_mixed = !in_heap && !in_native;5354bool is_write = (_decorators & C2_WRITE_ACCESS) != 0;55bool is_read = (_decorators & C2_READ_ACCESS) != 0;56bool is_atomic = is_read && is_write;5758if (is_atomic) {59// Atomics always need to be wrapped in CPU membars60return true;61}6263if (anonymous) {64// We will need memory barriers unless we can determine a unique65// alias category for this reference. (Note: If for some reason66// the barriers get omitted and the unsafe reference begins to "pollute"67// the alias analysis of the rest of the graph, either Compile::can_alias68// or Compile::must_alias will throw a diagnostic assert.)69if (is_mixed || !is_unordered || (mismatched && !_addr.type()->isa_aryptr())) {70return true;71}72} else {73assert(!is_mixed, "not unsafe");74}7576return false;77}7879Node* BarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& val) const {80DecoratorSet decorators = access.decorators();8182bool mismatched = (decorators & C2_MISMATCHED) != 0;83bool unaligned = (decorators & C2_UNALIGNED) != 0;84bool unsafe = (decorators & C2_UNSAFE_ACCESS) != 0;85bool requires_atomic_access = (decorators & MO_UNORDERED) == 0;8687bool in_native = (decorators & IN_NATIVE) != 0;88assert(!in_native || (unsafe && !access.is_oop()), "not supported yet");8990MemNode::MemOrd mo = access.mem_node_mo();9192Node* store;93BasicType bt = access.type();94if (access.is_parse_access()) {95C2ParseAccess& parse_access = static_cast<C2ParseAccess&>(access);9697GraphKit* kit = parse_access.kit();98if (bt == T_DOUBLE) {99Node* new_val = kit->dstore_rounding(val.node());100val.set_node(new_val);101}102103store = kit->store_to_memory(kit->control(), access.addr().node(), val.node(), bt,104access.addr().type(), mo, requires_atomic_access, unaligned, mismatched, unsafe);105} else {106assert(access.is_opt_access(), "either parse or opt access");107C2OptAccess& opt_access = static_cast<C2OptAccess&>(access);108Node* ctl = opt_access.ctl();109MergeMemNode* mm = opt_access.mem();110PhaseGVN& gvn = opt_access.gvn();111const TypePtr* adr_type = access.addr().type();112int alias = gvn.C->get_alias_index(adr_type);113Node* mem = mm->memory_at(alias);114115StoreNode* st = StoreNode::make(gvn, ctl, mem, access.addr().node(), adr_type, val.node(), bt, mo, requires_atomic_access);116if (unaligned) {117st->set_unaligned_access();118}119if (mismatched) {120st->set_mismatched_access();121}122store = gvn.transform(st);123if (store == st) {124mm->set_memory_at(alias, st);125}126}127access.set_raw_access(store);128129return store;130}131132Node* BarrierSetC2::load_at_resolved(C2Access& access, const Type* val_type) const {133DecoratorSet decorators = access.decorators();134135Node* adr = access.addr().node();136const TypePtr* adr_type = access.addr().type();137138bool mismatched = (decorators & C2_MISMATCHED) != 0;139bool requires_atomic_access = (decorators & MO_UNORDERED) == 0;140bool unaligned = (decorators & C2_UNALIGNED) != 0;141bool control_dependent = (decorators & C2_CONTROL_DEPENDENT_LOAD) != 0;142bool unknown_control = (decorators & C2_UNKNOWN_CONTROL_LOAD) != 0;143bool unsafe = (decorators & C2_UNSAFE_ACCESS) != 0;144bool immutable = (decorators & C2_IMMUTABLE_MEMORY) != 0;145146bool in_native = (decorators & IN_NATIVE) != 0;147148MemNode::MemOrd mo = access.mem_node_mo();149LoadNode::ControlDependency dep = unknown_control ? LoadNode::UnknownControl : LoadNode::DependsOnlyOnTest;150151Node* load;152if (access.is_parse_access()) {153C2ParseAccess& parse_access = static_cast<C2ParseAccess&>(access);154GraphKit* kit = parse_access.kit();155Node* control = control_dependent ? kit->control() : NULL;156157if (immutable) {158Compile* C = Compile::current();159Node* mem = kit->immutable_memory();160load = LoadNode::make(kit->gvn(), control, mem, adr,161adr_type, val_type, access.type(), mo, dep, requires_atomic_access,162unaligned, mismatched, unsafe, access.barrier_data());163load = kit->gvn().transform(load);164} else {165load = kit->make_load(control, adr, val_type, access.type(), adr_type, mo,166dep, requires_atomic_access, unaligned, mismatched, unsafe,167access.barrier_data());168}169} else {170assert(access.is_opt_access(), "either parse or opt access");171C2OptAccess& opt_access = static_cast<C2OptAccess&>(access);172Node* control = control_dependent ? opt_access.ctl() : NULL;173MergeMemNode* mm = opt_access.mem();174PhaseGVN& gvn = opt_access.gvn();175Node* mem = mm->memory_at(gvn.C->get_alias_index(adr_type));176load = LoadNode::make(gvn, control, mem, adr, adr_type, val_type, access.type(), mo, dep,177requires_atomic_access, unaligned, mismatched, unsafe, access.barrier_data());178load = gvn.transform(load);179}180access.set_raw_access(load);181182return load;183}184185class C2AccessFence: public StackObj {186C2Access& _access;187Node* _leading_membar;188189public:190C2AccessFence(C2Access& access) :191_access(access), _leading_membar(NULL) {192GraphKit* kit = NULL;193if (access.is_parse_access()) {194C2ParseAccess& parse_access = static_cast<C2ParseAccess&>(access);195kit = parse_access.kit();196}197DecoratorSet decorators = access.decorators();198199bool is_write = (decorators & C2_WRITE_ACCESS) != 0;200bool is_read = (decorators & C2_READ_ACCESS) != 0;201bool is_atomic = is_read && is_write;202203bool is_volatile = (decorators & MO_SEQ_CST) != 0;204bool is_release = (decorators & MO_RELEASE) != 0;205206if (is_atomic) {207assert(kit != NULL, "unsupported at optimization time");208// Memory-model-wise, a LoadStore acts like a little synchronized209// block, so needs barriers on each side. These don't translate210// into actual barriers on most machines, but we still need rest of211// compiler to respect ordering.212if (is_release) {213_leading_membar = kit->insert_mem_bar(Op_MemBarRelease);214} else if (is_volatile) {215if (support_IRIW_for_not_multiple_copy_atomic_cpu) {216_leading_membar = kit->insert_mem_bar(Op_MemBarVolatile);217} else {218_leading_membar = kit->insert_mem_bar(Op_MemBarRelease);219}220}221} else if (is_write) {222// If reference is volatile, prevent following memory ops from223// floating down past the volatile write. Also prevents commoning224// another volatile read.225if (is_volatile || is_release) {226assert(kit != NULL, "unsupported at optimization time");227_leading_membar = kit->insert_mem_bar(Op_MemBarRelease);228}229} else {230// Memory barrier to prevent normal and 'unsafe' accesses from231// bypassing each other. Happens after null checks, so the232// exception paths do not take memory state from the memory barrier,233// so there's no problems making a strong assert about mixing users234// of safe & unsafe memory.235if (is_volatile && support_IRIW_for_not_multiple_copy_atomic_cpu) {236assert(kit != NULL, "unsupported at optimization time");237_leading_membar = kit->insert_mem_bar(Op_MemBarVolatile);238}239}240241if (access.needs_cpu_membar()) {242assert(kit != NULL, "unsupported at optimization time");243kit->insert_mem_bar(Op_MemBarCPUOrder);244}245246if (is_atomic) {247// 4984716: MemBars must be inserted before this248// memory node in order to avoid a false249// dependency which will confuse the scheduler.250access.set_memory();251}252}253254~C2AccessFence() {255GraphKit* kit = NULL;256if (_access.is_parse_access()) {257C2ParseAccess& parse_access = static_cast<C2ParseAccess&>(_access);258kit = parse_access.kit();259}260DecoratorSet decorators = _access.decorators();261262bool is_write = (decorators & C2_WRITE_ACCESS) != 0;263bool is_read = (decorators & C2_READ_ACCESS) != 0;264bool is_atomic = is_read && is_write;265266bool is_volatile = (decorators & MO_SEQ_CST) != 0;267bool is_acquire = (decorators & MO_ACQUIRE) != 0;268269// If reference is volatile, prevent following volatiles ops from270// floating up before the volatile access.271if (_access.needs_cpu_membar()) {272kit->insert_mem_bar(Op_MemBarCPUOrder);273}274275if (is_atomic) {276assert(kit != NULL, "unsupported at optimization time");277if (is_acquire || is_volatile) {278Node* n = _access.raw_access();279Node* mb = kit->insert_mem_bar(Op_MemBarAcquire, n);280if (_leading_membar != NULL) {281MemBarNode::set_load_store_pair(_leading_membar->as_MemBar(), mb->as_MemBar());282}283}284} else if (is_write) {285// If not multiple copy atomic, we do the MemBarVolatile before the load.286if (is_volatile && !support_IRIW_for_not_multiple_copy_atomic_cpu) {287assert(kit != NULL, "unsupported at optimization time");288Node* n = _access.raw_access();289Node* mb = kit->insert_mem_bar(Op_MemBarVolatile, n); // Use fat membar290if (_leading_membar != NULL) {291MemBarNode::set_store_pair(_leading_membar->as_MemBar(), mb->as_MemBar());292}293}294} else {295if (is_volatile || is_acquire) {296assert(kit != NULL, "unsupported at optimization time");297Node* n = _access.raw_access();298assert(_leading_membar == NULL || support_IRIW_for_not_multiple_copy_atomic_cpu, "no leading membar expected");299Node* mb = kit->insert_mem_bar(Op_MemBarAcquire, n);300mb->as_MemBar()->set_trailing_load();301}302}303}304};305306Node* BarrierSetC2::store_at(C2Access& access, C2AccessValue& val) const {307C2AccessFence fence(access);308resolve_address(access);309return store_at_resolved(access, val);310}311312Node* BarrierSetC2::load_at(C2Access& access, const Type* val_type) const {313C2AccessFence fence(access);314resolve_address(access);315return load_at_resolved(access, val_type);316}317318MemNode::MemOrd C2Access::mem_node_mo() const {319bool is_write = (_decorators & C2_WRITE_ACCESS) != 0;320bool is_read = (_decorators & C2_READ_ACCESS) != 0;321if ((_decorators & MO_SEQ_CST) != 0) {322if (is_write && is_read) {323// For atomic operations324return MemNode::seqcst;325} else if (is_write) {326return MemNode::release;327} else {328assert(is_read, "what else?");329return MemNode::acquire;330}331} else if ((_decorators & MO_RELEASE) != 0) {332return MemNode::release;333} else if ((_decorators & MO_ACQUIRE) != 0) {334return MemNode::acquire;335} else if (is_write) {336// Volatile fields need releasing stores.337// Non-volatile fields also need releasing stores if they hold an338// object reference, because the object reference might point to339// a freshly created object.340// Conservatively release stores of object references.341return StoreNode::release_if_reference(_type);342} else {343return MemNode::unordered;344}345}346347void C2Access::fixup_decorators() {348bool default_mo = (_decorators & MO_DECORATOR_MASK) == 0;349bool is_unordered = (_decorators & MO_UNORDERED) != 0 || default_mo;350bool anonymous = (_decorators & C2_UNSAFE_ACCESS) != 0;351352bool is_read = (_decorators & C2_READ_ACCESS) != 0;353bool is_write = (_decorators & C2_WRITE_ACCESS) != 0;354355if (AlwaysAtomicAccesses && is_unordered) {356_decorators &= ~MO_DECORATOR_MASK; // clear the MO bits357_decorators |= MO_RELAXED; // Force the MO_RELAXED decorator with AlwaysAtomicAccess358}359360_decorators = AccessInternal::decorator_fixup(_decorators);361362if (is_read && !is_write && anonymous) {363// To be valid, unsafe loads may depend on other conditions than364// the one that guards them: pin the Load node365_decorators |= C2_CONTROL_DEPENDENT_LOAD;366_decorators |= C2_UNKNOWN_CONTROL_LOAD;367const TypePtr* adr_type = _addr.type();368Node* adr = _addr.node();369if (!needs_cpu_membar() && adr_type->isa_instptr()) {370assert(adr_type->meet(TypePtr::NULL_PTR) != adr_type->remove_speculative(), "should be not null");371intptr_t offset = Type::OffsetBot;372AddPNode::Ideal_base_and_offset(adr, &gvn(), offset);373if (offset >= 0) {374int s = Klass::layout_helper_size_in_bytes(adr_type->isa_instptr()->klass()->layout_helper());375if (offset < s) {376// Guaranteed to be a valid access, no need to pin it377_decorators ^= C2_CONTROL_DEPENDENT_LOAD;378_decorators ^= C2_UNKNOWN_CONTROL_LOAD;379}380}381}382}383}384385//--------------------------- atomic operations---------------------------------386387void BarrierSetC2::pin_atomic_op(C2AtomicParseAccess& access) const {388if (!access.needs_pinning()) {389return;390}391// SCMemProjNodes represent the memory state of a LoadStore. Their392// main role is to prevent LoadStore nodes from being optimized away393// when their results aren't used.394assert(access.is_parse_access(), "entry not supported at optimization time");395C2ParseAccess& parse_access = static_cast<C2ParseAccess&>(access);396GraphKit* kit = parse_access.kit();397Node* load_store = access.raw_access();398assert(load_store != NULL, "must pin atomic op");399Node* proj = kit->gvn().transform(new SCMemProjNode(load_store));400kit->set_memory(proj, access.alias_idx());401}402403void C2AtomicParseAccess::set_memory() {404Node *mem = _kit->memory(_alias_idx);405_memory = mem;406}407408Node* BarrierSetC2::atomic_cmpxchg_val_at_resolved(C2AtomicParseAccess& access, Node* expected_val,409Node* new_val, const Type* value_type) const {410GraphKit* kit = access.kit();411MemNode::MemOrd mo = access.mem_node_mo();412Node* mem = access.memory();413414Node* adr = access.addr().node();415const TypePtr* adr_type = access.addr().type();416417Node* load_store = NULL;418419if (access.is_oop()) {420#ifdef _LP64421if (adr->bottom_type()->is_ptr_to_narrowoop()) {422Node *newval_enc = kit->gvn().transform(new EncodePNode(new_val, new_val->bottom_type()->make_narrowoop()));423Node *oldval_enc = kit->gvn().transform(new EncodePNode(expected_val, expected_val->bottom_type()->make_narrowoop()));424load_store = new CompareAndExchangeNNode(kit->control(), mem, adr, newval_enc, oldval_enc, adr_type, value_type->make_narrowoop(), mo);425} else426#endif427{428load_store = new CompareAndExchangePNode(kit->control(), mem, adr, new_val, expected_val, adr_type, value_type->is_oopptr(), mo);429}430} else {431switch (access.type()) {432case T_BYTE: {433load_store = new CompareAndExchangeBNode(kit->control(), mem, adr, new_val, expected_val, adr_type, mo);434break;435}436case T_SHORT: {437load_store = new CompareAndExchangeSNode(kit->control(), mem, adr, new_val, expected_val, adr_type, mo);438break;439}440case T_INT: {441load_store = new CompareAndExchangeINode(kit->control(), mem, adr, new_val, expected_val, adr_type, mo);442break;443}444case T_LONG: {445load_store = new CompareAndExchangeLNode(kit->control(), mem, adr, new_val, expected_val, adr_type, mo);446break;447}448default:449ShouldNotReachHere();450}451}452453load_store->as_LoadStore()->set_barrier_data(access.barrier_data());454load_store = kit->gvn().transform(load_store);455456access.set_raw_access(load_store);457pin_atomic_op(access);458459#ifdef _LP64460if (access.is_oop() && adr->bottom_type()->is_ptr_to_narrowoop()) {461return kit->gvn().transform(new DecodeNNode(load_store, load_store->get_ptr_type()));462}463#endif464465return load_store;466}467468Node* BarrierSetC2::atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access, Node* expected_val,469Node* new_val, const Type* value_type) const {470GraphKit* kit = access.kit();471DecoratorSet decorators = access.decorators();472MemNode::MemOrd mo = access.mem_node_mo();473Node* mem = access.memory();474bool is_weak_cas = (decorators & C2_WEAK_CMPXCHG) != 0;475Node* load_store = NULL;476Node* adr = access.addr().node();477478if (access.is_oop()) {479#ifdef _LP64480if (adr->bottom_type()->is_ptr_to_narrowoop()) {481Node *newval_enc = kit->gvn().transform(new EncodePNode(new_val, new_val->bottom_type()->make_narrowoop()));482Node *oldval_enc = kit->gvn().transform(new EncodePNode(expected_val, expected_val->bottom_type()->make_narrowoop()));483if (is_weak_cas) {484load_store = new WeakCompareAndSwapNNode(kit->control(), mem, adr, newval_enc, oldval_enc, mo);485} else {486load_store = new CompareAndSwapNNode(kit->control(), mem, adr, newval_enc, oldval_enc, mo);487}488} else489#endif490{491if (is_weak_cas) {492load_store = new WeakCompareAndSwapPNode(kit->control(), mem, adr, new_val, expected_val, mo);493} else {494load_store = new CompareAndSwapPNode(kit->control(), mem, adr, new_val, expected_val, mo);495}496}497} else {498switch(access.type()) {499case T_BYTE: {500if (is_weak_cas) {501load_store = new WeakCompareAndSwapBNode(kit->control(), mem, adr, new_val, expected_val, mo);502} else {503load_store = new CompareAndSwapBNode(kit->control(), mem, adr, new_val, expected_val, mo);504}505break;506}507case T_SHORT: {508if (is_weak_cas) {509load_store = new WeakCompareAndSwapSNode(kit->control(), mem, adr, new_val, expected_val, mo);510} else {511load_store = new CompareAndSwapSNode(kit->control(), mem, adr, new_val, expected_val, mo);512}513break;514}515case T_INT: {516if (is_weak_cas) {517load_store = new WeakCompareAndSwapINode(kit->control(), mem, adr, new_val, expected_val, mo);518} else {519load_store = new CompareAndSwapINode(kit->control(), mem, adr, new_val, expected_val, mo);520}521break;522}523case T_LONG: {524if (is_weak_cas) {525load_store = new WeakCompareAndSwapLNode(kit->control(), mem, adr, new_val, expected_val, mo);526} else {527load_store = new CompareAndSwapLNode(kit->control(), mem, adr, new_val, expected_val, mo);528}529break;530}531default:532ShouldNotReachHere();533}534}535536load_store->as_LoadStore()->set_barrier_data(access.barrier_data());537load_store = kit->gvn().transform(load_store);538539access.set_raw_access(load_store);540pin_atomic_op(access);541542return load_store;543}544545Node* BarrierSetC2::atomic_xchg_at_resolved(C2AtomicParseAccess& access, Node* new_val, const Type* value_type) const {546GraphKit* kit = access.kit();547Node* mem = access.memory();548Node* adr = access.addr().node();549const TypePtr* adr_type = access.addr().type();550Node* load_store = NULL;551552if (access.is_oop()) {553#ifdef _LP64554if (adr->bottom_type()->is_ptr_to_narrowoop()) {555Node *newval_enc = kit->gvn().transform(new EncodePNode(new_val, new_val->bottom_type()->make_narrowoop()));556load_store = kit->gvn().transform(new GetAndSetNNode(kit->control(), mem, adr, newval_enc, adr_type, value_type->make_narrowoop()));557} else558#endif559{560load_store = new GetAndSetPNode(kit->control(), mem, adr, new_val, adr_type, value_type->is_oopptr());561}562} else {563switch (access.type()) {564case T_BYTE:565load_store = new GetAndSetBNode(kit->control(), mem, adr, new_val, adr_type);566break;567case T_SHORT:568load_store = new GetAndSetSNode(kit->control(), mem, adr, new_val, adr_type);569break;570case T_INT:571load_store = new GetAndSetINode(kit->control(), mem, adr, new_val, adr_type);572break;573case T_LONG:574load_store = new GetAndSetLNode(kit->control(), mem, adr, new_val, adr_type);575break;576default:577ShouldNotReachHere();578}579}580581load_store->as_LoadStore()->set_barrier_data(access.barrier_data());582load_store = kit->gvn().transform(load_store);583584access.set_raw_access(load_store);585pin_atomic_op(access);586587#ifdef _LP64588if (access.is_oop() && adr->bottom_type()->is_ptr_to_narrowoop()) {589return kit->gvn().transform(new DecodeNNode(load_store, load_store->get_ptr_type()));590}591#endif592593return load_store;594}595596Node* BarrierSetC2::atomic_add_at_resolved(C2AtomicParseAccess& access, Node* new_val, const Type* value_type) const {597Node* load_store = NULL;598GraphKit* kit = access.kit();599Node* adr = access.addr().node();600const TypePtr* adr_type = access.addr().type();601Node* mem = access.memory();602603switch(access.type()) {604case T_BYTE:605load_store = new GetAndAddBNode(kit->control(), mem, adr, new_val, adr_type);606break;607case T_SHORT:608load_store = new GetAndAddSNode(kit->control(), mem, adr, new_val, adr_type);609break;610case T_INT:611load_store = new GetAndAddINode(kit->control(), mem, adr, new_val, adr_type);612break;613case T_LONG:614load_store = new GetAndAddLNode(kit->control(), mem, adr, new_val, adr_type);615break;616default:617ShouldNotReachHere();618}619620load_store->as_LoadStore()->set_barrier_data(access.barrier_data());621load_store = kit->gvn().transform(load_store);622623access.set_raw_access(load_store);624pin_atomic_op(access);625626return load_store;627}628629Node* BarrierSetC2::atomic_cmpxchg_val_at(C2AtomicParseAccess& access, Node* expected_val,630Node* new_val, const Type* value_type) const {631C2AccessFence fence(access);632resolve_address(access);633return atomic_cmpxchg_val_at_resolved(access, expected_val, new_val, value_type);634}635636Node* BarrierSetC2::atomic_cmpxchg_bool_at(C2AtomicParseAccess& access, Node* expected_val,637Node* new_val, const Type* value_type) const {638C2AccessFence fence(access);639resolve_address(access);640return atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, value_type);641}642643Node* BarrierSetC2::atomic_xchg_at(C2AtomicParseAccess& access, Node* new_val, const Type* value_type) const {644C2AccessFence fence(access);645resolve_address(access);646return atomic_xchg_at_resolved(access, new_val, value_type);647}648649Node* BarrierSetC2::atomic_add_at(C2AtomicParseAccess& access, Node* new_val, const Type* value_type) const {650C2AccessFence fence(access);651resolve_address(access);652return atomic_add_at_resolved(access, new_val, value_type);653}654655int BarrierSetC2::arraycopy_payload_base_offset(bool is_array) {656// Exclude the header but include array length to copy by 8 bytes words.657// Can't use base_offset_in_bytes(bt) since basic type is unknown.658int base_off = is_array ? arrayOopDesc::length_offset_in_bytes() :659instanceOopDesc::base_offset_in_bytes();660// base_off:661// 8 - 32-bit VM662// 12 - 64-bit VM, compressed klass663// 16 - 64-bit VM, normal klass664if (base_off % BytesPerLong != 0) {665assert(UseCompressedClassPointers, "");666if (is_array) {667// Exclude length to copy by 8 bytes words.668base_off += sizeof(int);669} else {670// Include klass to copy by 8 bytes words.671base_off = instanceOopDesc::klass_offset_in_bytes();672}673assert(base_off % BytesPerLong == 0, "expect 8 bytes alignment");674}675return base_off;676}677678void BarrierSetC2::clone(GraphKit* kit, Node* src_base, Node* dst_base, Node* size, bool is_array) const {679int base_off = arraycopy_payload_base_offset(is_array);680Node* payload_size = size;681Node* offset = kit->MakeConX(base_off);682payload_size = kit->gvn().transform(new SubXNode(payload_size, offset));683payload_size = kit->gvn().transform(new URShiftXNode(payload_size, kit->intcon(LogBytesPerLong)));684ArrayCopyNode* ac = ArrayCopyNode::make(kit, false, src_base, offset, dst_base, offset, payload_size, true, false);685if (is_array) {686ac->set_clone_array();687} else {688ac->set_clone_inst();689}690Node* n = kit->gvn().transform(ac);691if (n == ac) {692const TypePtr* raw_adr_type = TypeRawPtr::BOTTOM;693ac->set_adr_type(TypeRawPtr::BOTTOM);694kit->set_predefined_output_for_runtime_call(ac, ac->in(TypeFunc::Memory), raw_adr_type);695} else {696kit->set_all_memory(n);697}698}699700Node* BarrierSetC2::obj_allocate(PhaseMacroExpand* macro, Node* mem, Node* toobig_false, Node* size_in_bytes,701Node*& i_o, Node*& needgc_ctrl,702Node*& fast_oop_ctrl, Node*& fast_oop_rawmem,703intx prefetch_lines) const {704705Node* eden_top_adr;706Node* eden_end_adr;707708macro->set_eden_pointers(eden_top_adr, eden_end_adr);709710// Load Eden::end. Loop invariant and hoisted.711//712// Note: We set the control input on "eden_end" and "old_eden_top" when using713// a TLAB to work around a bug where these values were being moved across714// a safepoint. These are not oops, so they cannot be include in the oop715// map, but they can be changed by a GC. The proper way to fix this would716// be to set the raw memory state when generating a SafepointNode. However717// this will require extensive changes to the loop optimization in order to718// prevent a degradation of the optimization.719// See comment in memnode.hpp, around line 227 in class LoadPNode.720Node *eden_end = macro->make_load(toobig_false, mem, eden_end_adr, 0, TypeRawPtr::BOTTOM, T_ADDRESS);721722// We need a Region for the loop-back contended case.723enum { fall_in_path = 1, contended_loopback_path = 2 };724Node *contended_region;725Node *contended_phi_rawmem;726if (UseTLAB) {727contended_region = toobig_false;728contended_phi_rawmem = mem;729} else {730contended_region = new RegionNode(3);731contended_phi_rawmem = new PhiNode(contended_region, Type::MEMORY, TypeRawPtr::BOTTOM);732// Now handle the passing-too-big test. We fall into the contended733// loop-back merge point.734contended_region ->init_req(fall_in_path, toobig_false);735contended_phi_rawmem->init_req(fall_in_path, mem);736macro->transform_later(contended_region);737macro->transform_later(contended_phi_rawmem);738}739740// Load(-locked) the heap top.741// See note above concerning the control input when using a TLAB742Node *old_eden_top = UseTLAB743? new LoadPNode (toobig_false, contended_phi_rawmem, eden_top_adr, TypeRawPtr::BOTTOM, TypeRawPtr::BOTTOM, MemNode::unordered)744: new LoadPLockedNode(contended_region, contended_phi_rawmem, eden_top_adr, MemNode::acquire);745746macro->transform_later(old_eden_top);747// Add to heap top to get a new heap top748Node *new_eden_top = new AddPNode(macro->top(), old_eden_top, size_in_bytes);749macro->transform_later(new_eden_top);750// Check for needing a GC; compare against heap end751Node *needgc_cmp = new CmpPNode(new_eden_top, eden_end);752macro->transform_later(needgc_cmp);753Node *needgc_bol = new BoolNode(needgc_cmp, BoolTest::ge);754macro->transform_later(needgc_bol);755IfNode *needgc_iff = new IfNode(contended_region, needgc_bol, PROB_UNLIKELY_MAG(4), COUNT_UNKNOWN);756macro->transform_later(needgc_iff);757758// Plug the failing-heap-space-need-gc test into the slow-path region759Node *needgc_true = new IfTrueNode(needgc_iff);760macro->transform_later(needgc_true);761needgc_ctrl = needgc_true;762763// No need for a GC. Setup for the Store-Conditional764Node *needgc_false = new IfFalseNode(needgc_iff);765macro->transform_later(needgc_false);766767i_o = macro->prefetch_allocation(i_o, needgc_false, contended_phi_rawmem,768old_eden_top, new_eden_top, prefetch_lines);769770Node* fast_oop = old_eden_top;771772// Store (-conditional) the modified eden top back down.773// StorePConditional produces flags for a test PLUS a modified raw774// memory state.775if (UseTLAB) {776Node* store_eden_top =777new StorePNode(needgc_false, contended_phi_rawmem, eden_top_adr,778TypeRawPtr::BOTTOM, new_eden_top, MemNode::unordered);779macro->transform_later(store_eden_top);780fast_oop_ctrl = needgc_false; // No contention, so this is the fast path781fast_oop_rawmem = store_eden_top;782} else {783Node* store_eden_top =784new StorePConditionalNode(needgc_false, contended_phi_rawmem, eden_top_adr,785new_eden_top, fast_oop/*old_eden_top*/);786macro->transform_later(store_eden_top);787Node *contention_check = new BoolNode(store_eden_top, BoolTest::ne);788macro->transform_later(contention_check);789store_eden_top = new SCMemProjNode(store_eden_top);790macro->transform_later(store_eden_top);791792// If not using TLABs, check to see if there was contention.793IfNode *contention_iff = new IfNode (needgc_false, contention_check, PROB_MIN, COUNT_UNKNOWN);794macro->transform_later(contention_iff);795Node *contention_true = new IfTrueNode(contention_iff);796macro->transform_later(contention_true);797// If contention, loopback and try again.798contended_region->init_req(contended_loopback_path, contention_true);799contended_phi_rawmem->init_req(contended_loopback_path, store_eden_top);800801// Fast-path succeeded with no contention!802Node *contention_false = new IfFalseNode(contention_iff);803macro->transform_later(contention_false);804fast_oop_ctrl = contention_false;805806// Bump total allocated bytes for this thread807Node* thread = new ThreadLocalNode();808macro->transform_later(thread);809Node* alloc_bytes_adr = macro->basic_plus_adr(macro->top()/*not oop*/, thread,810in_bytes(JavaThread::allocated_bytes_offset()));811Node* alloc_bytes = macro->make_load(fast_oop_ctrl, store_eden_top, alloc_bytes_adr,8120, TypeLong::LONG, T_LONG);813#ifdef _LP64814Node* alloc_size = size_in_bytes;815#else816Node* alloc_size = new ConvI2LNode(size_in_bytes);817macro->transform_later(alloc_size);818#endif819Node* new_alloc_bytes = new AddLNode(alloc_bytes, alloc_size);820macro->transform_later(new_alloc_bytes);821fast_oop_rawmem = macro->make_store(fast_oop_ctrl, store_eden_top, alloc_bytes_adr,8220, new_alloc_bytes, T_LONG);823}824return fast_oop;825}826827#define XTOP LP64_ONLY(COMMA phase->top())828829void BarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* ac) const {830Node* ctrl = ac->in(TypeFunc::Control);831Node* mem = ac->in(TypeFunc::Memory);832Node* src = ac->in(ArrayCopyNode::Src);833Node* src_offset = ac->in(ArrayCopyNode::SrcPos);834Node* dest = ac->in(ArrayCopyNode::Dest);835Node* dest_offset = ac->in(ArrayCopyNode::DestPos);836Node* length = ac->in(ArrayCopyNode::Length);837838Node* payload_src = phase->basic_plus_adr(src, src_offset);839Node* payload_dst = phase->basic_plus_adr(dest, dest_offset);840841const char* copyfunc_name = "arraycopy";842address copyfunc_addr = phase->basictype2arraycopy(T_LONG, NULL, NULL, true, copyfunc_name, true);843844const TypePtr* raw_adr_type = TypeRawPtr::BOTTOM;845const TypeFunc* call_type = OptoRuntime::fast_arraycopy_Type();846847Node* call = phase->make_leaf_call(ctrl, mem, call_type, copyfunc_addr, copyfunc_name, raw_adr_type, payload_src, payload_dst, length XTOP);848phase->transform_later(call);849850phase->igvn().replace_node(ac, call);851}852853#undef XTOP854855856