Path: blob/master/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp
40974 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;93if (access.is_parse_access()) {94C2ParseAccess& parse_access = static_cast<C2ParseAccess&>(access);9596GraphKit* kit = parse_access.kit();97if (access.type() == T_DOUBLE) {98Node* new_val = kit->dstore_rounding(val.node());99val.set_node(new_val);100}101102store = kit->store_to_memory(kit->control(), access.addr().node(), val.node(), access.type(),103access.addr().type(), mo, requires_atomic_access, unaligned, mismatched, unsafe);104} else {105assert(!requires_atomic_access, "not yet supported");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(), access.type(), mo);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) {158assert(!requires_atomic_access, "can't ensure atomicity");159Compile* C = Compile::current();160Node* mem = kit->immutable_memory();161load = LoadNode::make(kit->gvn(), control, mem, adr,162adr_type, val_type, access.type(), mo, dep, unaligned,163mismatched, unsafe, access.barrier_data());164load = kit->gvn().transform(load);165} else {166load = kit->make_load(control, adr, val_type, access.type(), adr_type, mo,167dep, requires_atomic_access, unaligned, mismatched, unsafe,168access.barrier_data());169}170} else {171assert(!requires_atomic_access, "not yet supported");172assert(access.is_opt_access(), "either parse or opt access");173C2OptAccess& opt_access = static_cast<C2OptAccess&>(access);174Node* control = control_dependent ? opt_access.ctl() : NULL;175MergeMemNode* mm = opt_access.mem();176PhaseGVN& gvn = opt_access.gvn();177Node* mem = mm->memory_at(gvn.C->get_alias_index(adr_type));178load = LoadNode::make(gvn, control, mem, adr, adr_type, val_type, access.type(), mo,179dep, unaligned, mismatched, unsafe, access.barrier_data());180load = gvn.transform(load);181}182access.set_raw_access(load);183184return load;185}186187class C2AccessFence: public StackObj {188C2Access& _access;189Node* _leading_membar;190191public:192C2AccessFence(C2Access& access) :193_access(access), _leading_membar(NULL) {194GraphKit* kit = NULL;195if (access.is_parse_access()) {196C2ParseAccess& parse_access = static_cast<C2ParseAccess&>(access);197kit = parse_access.kit();198}199DecoratorSet decorators = access.decorators();200201bool is_write = (decorators & C2_WRITE_ACCESS) != 0;202bool is_read = (decorators & C2_READ_ACCESS) != 0;203bool is_atomic = is_read && is_write;204205bool is_volatile = (decorators & MO_SEQ_CST) != 0;206bool is_release = (decorators & MO_RELEASE) != 0;207208if (is_atomic) {209assert(kit != NULL, "unsupported at optimization time");210// Memory-model-wise, a LoadStore acts like a little synchronized211// block, so needs barriers on each side. These don't translate212// into actual barriers on most machines, but we still need rest of213// compiler to respect ordering.214if (is_release) {215_leading_membar = kit->insert_mem_bar(Op_MemBarRelease);216} else if (is_volatile) {217if (support_IRIW_for_not_multiple_copy_atomic_cpu) {218_leading_membar = kit->insert_mem_bar(Op_MemBarVolatile);219} else {220_leading_membar = kit->insert_mem_bar(Op_MemBarRelease);221}222}223} else if (is_write) {224// If reference is volatile, prevent following memory ops from225// floating down past the volatile write. Also prevents commoning226// another volatile read.227if (is_volatile || is_release) {228assert(kit != NULL, "unsupported at optimization time");229_leading_membar = kit->insert_mem_bar(Op_MemBarRelease);230}231} else {232// Memory barrier to prevent normal and 'unsafe' accesses from233// bypassing each other. Happens after null checks, so the234// exception paths do not take memory state from the memory barrier,235// so there's no problems making a strong assert about mixing users236// of safe & unsafe memory.237if (is_volatile && support_IRIW_for_not_multiple_copy_atomic_cpu) {238assert(kit != NULL, "unsupported at optimization time");239_leading_membar = kit->insert_mem_bar(Op_MemBarVolatile);240}241}242243if (access.needs_cpu_membar()) {244assert(kit != NULL, "unsupported at optimization time");245kit->insert_mem_bar(Op_MemBarCPUOrder);246}247248if (is_atomic) {249// 4984716: MemBars must be inserted before this250// memory node in order to avoid a false251// dependency which will confuse the scheduler.252access.set_memory();253}254}255256~C2AccessFence() {257GraphKit* kit = NULL;258if (_access.is_parse_access()) {259C2ParseAccess& parse_access = static_cast<C2ParseAccess&>(_access);260kit = parse_access.kit();261}262DecoratorSet decorators = _access.decorators();263264bool is_write = (decorators & C2_WRITE_ACCESS) != 0;265bool is_read = (decorators & C2_READ_ACCESS) != 0;266bool is_atomic = is_read && is_write;267268bool is_volatile = (decorators & MO_SEQ_CST) != 0;269bool is_acquire = (decorators & MO_ACQUIRE) != 0;270271// If reference is volatile, prevent following volatiles ops from272// floating up before the volatile access.273if (_access.needs_cpu_membar()) {274kit->insert_mem_bar(Op_MemBarCPUOrder);275}276277if (is_atomic) {278assert(kit != NULL, "unsupported at optimization time");279if (is_acquire || is_volatile) {280Node* n = _access.raw_access();281Node* mb = kit->insert_mem_bar(Op_MemBarAcquire, n);282if (_leading_membar != NULL) {283MemBarNode::set_load_store_pair(_leading_membar->as_MemBar(), mb->as_MemBar());284}285}286} else if (is_write) {287// If not multiple copy atomic, we do the MemBarVolatile before the load.288if (is_volatile && !support_IRIW_for_not_multiple_copy_atomic_cpu) {289assert(kit != NULL, "unsupported at optimization time");290Node* n = _access.raw_access();291Node* mb = kit->insert_mem_bar(Op_MemBarVolatile, n); // Use fat membar292if (_leading_membar != NULL) {293MemBarNode::set_store_pair(_leading_membar->as_MemBar(), mb->as_MemBar());294}295}296} else {297if (is_volatile || is_acquire) {298assert(kit != NULL, "unsupported at optimization time");299Node* n = _access.raw_access();300assert(_leading_membar == NULL || support_IRIW_for_not_multiple_copy_atomic_cpu, "no leading membar expected");301Node* mb = kit->insert_mem_bar(Op_MemBarAcquire, n);302mb->as_MemBar()->set_trailing_load();303}304}305}306};307308Node* BarrierSetC2::store_at(C2Access& access, C2AccessValue& val) const {309C2AccessFence fence(access);310resolve_address(access);311return store_at_resolved(access, val);312}313314Node* BarrierSetC2::load_at(C2Access& access, const Type* val_type) const {315C2AccessFence fence(access);316resolve_address(access);317return load_at_resolved(access, val_type);318}319320MemNode::MemOrd C2Access::mem_node_mo() const {321bool is_write = (_decorators & C2_WRITE_ACCESS) != 0;322bool is_read = (_decorators & C2_READ_ACCESS) != 0;323if ((_decorators & MO_SEQ_CST) != 0) {324if (is_write && is_read) {325// For atomic operations326return MemNode::seqcst;327} else if (is_write) {328return MemNode::release;329} else {330assert(is_read, "what else?");331return MemNode::acquire;332}333} else if ((_decorators & MO_RELEASE) != 0) {334return MemNode::release;335} else if ((_decorators & MO_ACQUIRE) != 0) {336return MemNode::acquire;337} else if (is_write) {338// Volatile fields need releasing stores.339// Non-volatile fields also need releasing stores if they hold an340// object reference, because the object reference might point to341// a freshly created object.342// Conservatively release stores of object references.343return StoreNode::release_if_reference(_type);344} else {345return MemNode::unordered;346}347}348349void C2Access::fixup_decorators() {350bool default_mo = (_decorators & MO_DECORATOR_MASK) == 0;351bool is_unordered = (_decorators & MO_UNORDERED) != 0 || default_mo;352bool anonymous = (_decorators & C2_UNSAFE_ACCESS) != 0;353354bool is_read = (_decorators & C2_READ_ACCESS) != 0;355bool is_write = (_decorators & C2_WRITE_ACCESS) != 0;356357if (AlwaysAtomicAccesses && is_unordered) {358_decorators &= ~MO_DECORATOR_MASK; // clear the MO bits359_decorators |= MO_RELAXED; // Force the MO_RELAXED decorator with AlwaysAtomicAccess360}361362_decorators = AccessInternal::decorator_fixup(_decorators);363364if (is_read && !is_write && anonymous) {365// To be valid, unsafe loads may depend on other conditions than366// the one that guards them: pin the Load node367_decorators |= C2_CONTROL_DEPENDENT_LOAD;368_decorators |= C2_UNKNOWN_CONTROL_LOAD;369const TypePtr* adr_type = _addr.type();370Node* adr = _addr.node();371if (!needs_cpu_membar() && adr_type->isa_instptr()) {372assert(adr_type->meet(TypePtr::NULL_PTR) != adr_type->remove_speculative(), "should be not null");373intptr_t offset = Type::OffsetBot;374AddPNode::Ideal_base_and_offset(adr, &gvn(), offset);375if (offset >= 0) {376int s = Klass::layout_helper_size_in_bytes(adr_type->isa_instptr()->klass()->layout_helper());377if (offset < s) {378// Guaranteed to be a valid access, no need to pin it379_decorators ^= C2_CONTROL_DEPENDENT_LOAD;380_decorators ^= C2_UNKNOWN_CONTROL_LOAD;381}382}383}384}385}386387//--------------------------- atomic operations---------------------------------388389void BarrierSetC2::pin_atomic_op(C2AtomicParseAccess& access) const {390if (!access.needs_pinning()) {391return;392}393// SCMemProjNodes represent the memory state of a LoadStore. Their394// main role is to prevent LoadStore nodes from being optimized away395// when their results aren't used.396assert(access.is_parse_access(), "entry not supported at optimization time");397C2ParseAccess& parse_access = static_cast<C2ParseAccess&>(access);398GraphKit* kit = parse_access.kit();399Node* load_store = access.raw_access();400assert(load_store != NULL, "must pin atomic op");401Node* proj = kit->gvn().transform(new SCMemProjNode(load_store));402kit->set_memory(proj, access.alias_idx());403}404405void C2AtomicParseAccess::set_memory() {406Node *mem = _kit->memory(_alias_idx);407_memory = mem;408}409410Node* BarrierSetC2::atomic_cmpxchg_val_at_resolved(C2AtomicParseAccess& access, Node* expected_val,411Node* new_val, const Type* value_type) const {412GraphKit* kit = access.kit();413MemNode::MemOrd mo = access.mem_node_mo();414Node* mem = access.memory();415416Node* adr = access.addr().node();417const TypePtr* adr_type = access.addr().type();418419Node* load_store = NULL;420421if (access.is_oop()) {422#ifdef _LP64423if (adr->bottom_type()->is_ptr_to_narrowoop()) {424Node *newval_enc = kit->gvn().transform(new EncodePNode(new_val, new_val->bottom_type()->make_narrowoop()));425Node *oldval_enc = kit->gvn().transform(new EncodePNode(expected_val, expected_val->bottom_type()->make_narrowoop()));426load_store = new CompareAndExchangeNNode(kit->control(), mem, adr, newval_enc, oldval_enc, adr_type, value_type->make_narrowoop(), mo);427} else428#endif429{430load_store = new CompareAndExchangePNode(kit->control(), mem, adr, new_val, expected_val, adr_type, value_type->is_oopptr(), mo);431}432} else {433switch (access.type()) {434case T_BYTE: {435load_store = new CompareAndExchangeBNode(kit->control(), mem, adr, new_val, expected_val, adr_type, mo);436break;437}438case T_SHORT: {439load_store = new CompareAndExchangeSNode(kit->control(), mem, adr, new_val, expected_val, adr_type, mo);440break;441}442case T_INT: {443load_store = new CompareAndExchangeINode(kit->control(), mem, adr, new_val, expected_val, adr_type, mo);444break;445}446case T_LONG: {447load_store = new CompareAndExchangeLNode(kit->control(), mem, adr, new_val, expected_val, adr_type, mo);448break;449}450default:451ShouldNotReachHere();452}453}454455load_store->as_LoadStore()->set_barrier_data(access.barrier_data());456load_store = kit->gvn().transform(load_store);457458access.set_raw_access(load_store);459pin_atomic_op(access);460461#ifdef _LP64462if (access.is_oop() && adr->bottom_type()->is_ptr_to_narrowoop()) {463return kit->gvn().transform(new DecodeNNode(load_store, load_store->get_ptr_type()));464}465#endif466467return load_store;468}469470Node* BarrierSetC2::atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access, Node* expected_val,471Node* new_val, const Type* value_type) const {472GraphKit* kit = access.kit();473DecoratorSet decorators = access.decorators();474MemNode::MemOrd mo = access.mem_node_mo();475Node* mem = access.memory();476bool is_weak_cas = (decorators & C2_WEAK_CMPXCHG) != 0;477Node* load_store = NULL;478Node* adr = access.addr().node();479480if (access.is_oop()) {481#ifdef _LP64482if (adr->bottom_type()->is_ptr_to_narrowoop()) {483Node *newval_enc = kit->gvn().transform(new EncodePNode(new_val, new_val->bottom_type()->make_narrowoop()));484Node *oldval_enc = kit->gvn().transform(new EncodePNode(expected_val, expected_val->bottom_type()->make_narrowoop()));485if (is_weak_cas) {486load_store = new WeakCompareAndSwapNNode(kit->control(), mem, adr, newval_enc, oldval_enc, mo);487} else {488load_store = new CompareAndSwapNNode(kit->control(), mem, adr, newval_enc, oldval_enc, mo);489}490} else491#endif492{493if (is_weak_cas) {494load_store = new WeakCompareAndSwapPNode(kit->control(), mem, adr, new_val, expected_val, mo);495} else {496load_store = new CompareAndSwapPNode(kit->control(), mem, adr, new_val, expected_val, mo);497}498}499} else {500switch(access.type()) {501case T_BYTE: {502if (is_weak_cas) {503load_store = new WeakCompareAndSwapBNode(kit->control(), mem, adr, new_val, expected_val, mo);504} else {505load_store = new CompareAndSwapBNode(kit->control(), mem, adr, new_val, expected_val, mo);506}507break;508}509case T_SHORT: {510if (is_weak_cas) {511load_store = new WeakCompareAndSwapSNode(kit->control(), mem, adr, new_val, expected_val, mo);512} else {513load_store = new CompareAndSwapSNode(kit->control(), mem, adr, new_val, expected_val, mo);514}515break;516}517case T_INT: {518if (is_weak_cas) {519load_store = new WeakCompareAndSwapINode(kit->control(), mem, adr, new_val, expected_val, mo);520} else {521load_store = new CompareAndSwapINode(kit->control(), mem, adr, new_val, expected_val, mo);522}523break;524}525case T_LONG: {526if (is_weak_cas) {527load_store = new WeakCompareAndSwapLNode(kit->control(), mem, adr, new_val, expected_val, mo);528} else {529load_store = new CompareAndSwapLNode(kit->control(), mem, adr, new_val, expected_val, mo);530}531break;532}533default:534ShouldNotReachHere();535}536}537538load_store->as_LoadStore()->set_barrier_data(access.barrier_data());539load_store = kit->gvn().transform(load_store);540541access.set_raw_access(load_store);542pin_atomic_op(access);543544return load_store;545}546547Node* BarrierSetC2::atomic_xchg_at_resolved(C2AtomicParseAccess& access, Node* new_val, const Type* value_type) const {548GraphKit* kit = access.kit();549Node* mem = access.memory();550Node* adr = access.addr().node();551const TypePtr* adr_type = access.addr().type();552Node* load_store = NULL;553554if (access.is_oop()) {555#ifdef _LP64556if (adr->bottom_type()->is_ptr_to_narrowoop()) {557Node *newval_enc = kit->gvn().transform(new EncodePNode(new_val, new_val->bottom_type()->make_narrowoop()));558load_store = kit->gvn().transform(new GetAndSetNNode(kit->control(), mem, adr, newval_enc, adr_type, value_type->make_narrowoop()));559} else560#endif561{562load_store = new GetAndSetPNode(kit->control(), mem, adr, new_val, adr_type, value_type->is_oopptr());563}564} else {565switch (access.type()) {566case T_BYTE:567load_store = new GetAndSetBNode(kit->control(), mem, adr, new_val, adr_type);568break;569case T_SHORT:570load_store = new GetAndSetSNode(kit->control(), mem, adr, new_val, adr_type);571break;572case T_INT:573load_store = new GetAndSetINode(kit->control(), mem, adr, new_val, adr_type);574break;575case T_LONG:576load_store = new GetAndSetLNode(kit->control(), mem, adr, new_val, adr_type);577break;578default:579ShouldNotReachHere();580}581}582583load_store->as_LoadStore()->set_barrier_data(access.barrier_data());584load_store = kit->gvn().transform(load_store);585586access.set_raw_access(load_store);587pin_atomic_op(access);588589#ifdef _LP64590if (access.is_oop() && adr->bottom_type()->is_ptr_to_narrowoop()) {591return kit->gvn().transform(new DecodeNNode(load_store, load_store->get_ptr_type()));592}593#endif594595return load_store;596}597598Node* BarrierSetC2::atomic_add_at_resolved(C2AtomicParseAccess& access, Node* new_val, const Type* value_type) const {599Node* load_store = NULL;600GraphKit* kit = access.kit();601Node* adr = access.addr().node();602const TypePtr* adr_type = access.addr().type();603Node* mem = access.memory();604605switch(access.type()) {606case T_BYTE:607load_store = new GetAndAddBNode(kit->control(), mem, adr, new_val, adr_type);608break;609case T_SHORT:610load_store = new GetAndAddSNode(kit->control(), mem, adr, new_val, adr_type);611break;612case T_INT:613load_store = new GetAndAddINode(kit->control(), mem, adr, new_val, adr_type);614break;615case T_LONG:616load_store = new GetAndAddLNode(kit->control(), mem, adr, new_val, adr_type);617break;618default:619ShouldNotReachHere();620}621622load_store->as_LoadStore()->set_barrier_data(access.barrier_data());623load_store = kit->gvn().transform(load_store);624625access.set_raw_access(load_store);626pin_atomic_op(access);627628return load_store;629}630631Node* BarrierSetC2::atomic_cmpxchg_val_at(C2AtomicParseAccess& access, Node* expected_val,632Node* new_val, const Type* value_type) const {633C2AccessFence fence(access);634resolve_address(access);635return atomic_cmpxchg_val_at_resolved(access, expected_val, new_val, value_type);636}637638Node* BarrierSetC2::atomic_cmpxchg_bool_at(C2AtomicParseAccess& access, Node* expected_val,639Node* new_val, const Type* value_type) const {640C2AccessFence fence(access);641resolve_address(access);642return atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, value_type);643}644645Node* BarrierSetC2::atomic_xchg_at(C2AtomicParseAccess& access, Node* new_val, const Type* value_type) const {646C2AccessFence fence(access);647resolve_address(access);648return atomic_xchg_at_resolved(access, new_val, value_type);649}650651Node* BarrierSetC2::atomic_add_at(C2AtomicParseAccess& access, Node* new_val, const Type* value_type) const {652C2AccessFence fence(access);653resolve_address(access);654return atomic_add_at_resolved(access, new_val, value_type);655}656657int BarrierSetC2::arraycopy_payload_base_offset(bool is_array) {658// Exclude the header but include array length to copy by 8 bytes words.659// Can't use base_offset_in_bytes(bt) since basic type is unknown.660int base_off = is_array ? arrayOopDesc::length_offset_in_bytes() :661instanceOopDesc::base_offset_in_bytes();662// base_off:663// 8 - 32-bit VM664// 12 - 64-bit VM, compressed klass665// 16 - 64-bit VM, normal klass666if (base_off % BytesPerLong != 0) {667assert(UseCompressedClassPointers, "");668if (is_array) {669// Exclude length to copy by 8 bytes words.670base_off += sizeof(int);671} else {672// Include klass to copy by 8 bytes words.673base_off = instanceOopDesc::klass_offset_in_bytes();674}675assert(base_off % BytesPerLong == 0, "expect 8 bytes alignment");676}677return base_off;678}679680void BarrierSetC2::clone(GraphKit* kit, Node* src_base, Node* dst_base, Node* size, bool is_array) const {681int base_off = arraycopy_payload_base_offset(is_array);682Node* payload_size = size;683Node* offset = kit->MakeConX(base_off);684payload_size = kit->gvn().transform(new SubXNode(payload_size, offset));685payload_size = kit->gvn().transform(new URShiftXNode(payload_size, kit->intcon(LogBytesPerLong)));686ArrayCopyNode* ac = ArrayCopyNode::make(kit, false, src_base, offset, dst_base, offset, payload_size, true, false);687if (is_array) {688ac->set_clone_array();689} else {690ac->set_clone_inst();691}692Node* n = kit->gvn().transform(ac);693if (n == ac) {694const TypePtr* raw_adr_type = TypeRawPtr::BOTTOM;695ac->set_adr_type(TypeRawPtr::BOTTOM);696kit->set_predefined_output_for_runtime_call(ac, ac->in(TypeFunc::Memory), raw_adr_type);697} else {698kit->set_all_memory(n);699}700}701702Node* BarrierSetC2::obj_allocate(PhaseMacroExpand* macro, Node* mem, Node* toobig_false, Node* size_in_bytes,703Node*& i_o, Node*& needgc_ctrl,704Node*& fast_oop_ctrl, Node*& fast_oop_rawmem,705intx prefetch_lines) const {706707Node* eden_top_adr;708Node* eden_end_adr;709710macro->set_eden_pointers(eden_top_adr, eden_end_adr);711712// Load Eden::end. Loop invariant and hoisted.713//714// Note: We set the control input on "eden_end" and "old_eden_top" when using715// a TLAB to work around a bug where these values were being moved across716// a safepoint. These are not oops, so they cannot be include in the oop717// map, but they can be changed by a GC. The proper way to fix this would718// be to set the raw memory state when generating a SafepointNode. However719// this will require extensive changes to the loop optimization in order to720// prevent a degradation of the optimization.721// See comment in memnode.hpp, around line 227 in class LoadPNode.722Node *eden_end = macro->make_load(toobig_false, mem, eden_end_adr, 0, TypeRawPtr::BOTTOM, T_ADDRESS);723724// We need a Region for the loop-back contended case.725enum { fall_in_path = 1, contended_loopback_path = 2 };726Node *contended_region;727Node *contended_phi_rawmem;728if (UseTLAB) {729contended_region = toobig_false;730contended_phi_rawmem = mem;731} else {732contended_region = new RegionNode(3);733contended_phi_rawmem = new PhiNode(contended_region, Type::MEMORY, TypeRawPtr::BOTTOM);734// Now handle the passing-too-big test. We fall into the contended735// loop-back merge point.736contended_region ->init_req(fall_in_path, toobig_false);737contended_phi_rawmem->init_req(fall_in_path, mem);738macro->transform_later(contended_region);739macro->transform_later(contended_phi_rawmem);740}741742// Load(-locked) the heap top.743// See note above concerning the control input when using a TLAB744Node *old_eden_top = UseTLAB745? new LoadPNode (toobig_false, contended_phi_rawmem, eden_top_adr, TypeRawPtr::BOTTOM, TypeRawPtr::BOTTOM, MemNode::unordered)746: new LoadPLockedNode(contended_region, contended_phi_rawmem, eden_top_adr, MemNode::acquire);747748macro->transform_later(old_eden_top);749// Add to heap top to get a new heap top750Node *new_eden_top = new AddPNode(macro->top(), old_eden_top, size_in_bytes);751macro->transform_later(new_eden_top);752// Check for needing a GC; compare against heap end753Node *needgc_cmp = new CmpPNode(new_eden_top, eden_end);754macro->transform_later(needgc_cmp);755Node *needgc_bol = new BoolNode(needgc_cmp, BoolTest::ge);756macro->transform_later(needgc_bol);757IfNode *needgc_iff = new IfNode(contended_region, needgc_bol, PROB_UNLIKELY_MAG(4), COUNT_UNKNOWN);758macro->transform_later(needgc_iff);759760// Plug the failing-heap-space-need-gc test into the slow-path region761Node *needgc_true = new IfTrueNode(needgc_iff);762macro->transform_later(needgc_true);763needgc_ctrl = needgc_true;764765// No need for a GC. Setup for the Store-Conditional766Node *needgc_false = new IfFalseNode(needgc_iff);767macro->transform_later(needgc_false);768769i_o = macro->prefetch_allocation(i_o, needgc_false, contended_phi_rawmem,770old_eden_top, new_eden_top, prefetch_lines);771772Node* fast_oop = old_eden_top;773774// Store (-conditional) the modified eden top back down.775// StorePConditional produces flags for a test PLUS a modified raw776// memory state.777if (UseTLAB) {778Node* store_eden_top =779new StorePNode(needgc_false, contended_phi_rawmem, eden_top_adr,780TypeRawPtr::BOTTOM, new_eden_top, MemNode::unordered);781macro->transform_later(store_eden_top);782fast_oop_ctrl = needgc_false; // No contention, so this is the fast path783fast_oop_rawmem = store_eden_top;784} else {785Node* store_eden_top =786new StorePConditionalNode(needgc_false, contended_phi_rawmem, eden_top_adr,787new_eden_top, fast_oop/*old_eden_top*/);788macro->transform_later(store_eden_top);789Node *contention_check = new BoolNode(store_eden_top, BoolTest::ne);790macro->transform_later(contention_check);791store_eden_top = new SCMemProjNode(store_eden_top);792macro->transform_later(store_eden_top);793794// If not using TLABs, check to see if there was contention.795IfNode *contention_iff = new IfNode (needgc_false, contention_check, PROB_MIN, COUNT_UNKNOWN);796macro->transform_later(contention_iff);797Node *contention_true = new IfTrueNode(contention_iff);798macro->transform_later(contention_true);799// If contention, loopback and try again.800contended_region->init_req(contended_loopback_path, contention_true);801contended_phi_rawmem->init_req(contended_loopback_path, store_eden_top);802803// Fast-path succeeded with no contention!804Node *contention_false = new IfFalseNode(contention_iff);805macro->transform_later(contention_false);806fast_oop_ctrl = contention_false;807808// Bump total allocated bytes for this thread809Node* thread = new ThreadLocalNode();810macro->transform_later(thread);811Node* alloc_bytes_adr = macro->basic_plus_adr(macro->top()/*not oop*/, thread,812in_bytes(JavaThread::allocated_bytes_offset()));813Node* alloc_bytes = macro->make_load(fast_oop_ctrl, store_eden_top, alloc_bytes_adr,8140, TypeLong::LONG, T_LONG);815#ifdef _LP64816Node* alloc_size = size_in_bytes;817#else818Node* alloc_size = new ConvI2LNode(size_in_bytes);819macro->transform_later(alloc_size);820#endif821Node* new_alloc_bytes = new AddLNode(alloc_bytes, alloc_size);822macro->transform_later(new_alloc_bytes);823fast_oop_rawmem = macro->make_store(fast_oop_ctrl, store_eden_top, alloc_bytes_adr,8240, new_alloc_bytes, T_LONG);825}826return fast_oop;827}828829#define XTOP LP64_ONLY(COMMA phase->top())830831void BarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* ac) const {832Node* ctrl = ac->in(TypeFunc::Control);833Node* mem = ac->in(TypeFunc::Memory);834Node* src = ac->in(ArrayCopyNode::Src);835Node* src_offset = ac->in(ArrayCopyNode::SrcPos);836Node* dest = ac->in(ArrayCopyNode::Dest);837Node* dest_offset = ac->in(ArrayCopyNode::DestPos);838Node* length = ac->in(ArrayCopyNode::Length);839840Node* payload_src = phase->basic_plus_adr(src, src_offset);841Node* payload_dst = phase->basic_plus_adr(dest, dest_offset);842843const char* copyfunc_name = "arraycopy";844address copyfunc_addr = phase->basictype2arraycopy(T_LONG, NULL, NULL, true, copyfunc_name, true);845846const TypePtr* raw_adr_type = TypeRawPtr::BOTTOM;847const TypeFunc* call_type = OptoRuntime::fast_arraycopy_Type();848849Node* call = phase->make_leaf_call(ctrl, mem, call_type, copyfunc_addr, copyfunc_name, raw_adr_type, payload_src, payload_dst, length XTOP);850phase->transform_later(call);851852phase->igvn().replace_node(ac, call);853}854855856