--- /dev/null 2017-03-07 11:44:12.271151064 +0100 +++ new/src/share/vm/runtime/access.hpp 2017-04-25 16:46:37.847170914 +0200 @@ -0,0 +1,562 @@ +/* + * Copyright (c) 2017, 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. + * + */ + +#ifndef SHARE_VM_RUNTIME_ACCESS_HPP +#define SHARE_VM_RUNTIME_ACCESS_HPP + +#include "oops/oopsHierarchy.hpp" +#include "utilities/traits/decay.hpp" + +// = GENERAL = +// Access is an API for performing memory accesses to the heap. Each access can have a number of "decorators". +// A decorator is an attribute or property that affects the way a memory access is performed in some way. +// There are different groups of decorators. Some have to do with memory ordering, others to do with +// e.g. strength of references, strength of GC barriers or whether compression should be applied or not. +// Some decorators are set at buildtime, such as whether primitives require GC barriers or not, others +// at callsites such as whether an access is in the heap or not, and others are resolved at runtime +// such as GC-specific barriers and encoding/decoding compressed oops. +// By pipelining handling of these decorators, the design of the Access API allows separation of concern +// over the different orthogonal concerns of decorators, while providing a powerful unified way of +// expressing these orthogonal properties in a unified way. + +// = THE PIPELINE = +// The design of accesses going through the Access interface consists of the following stages: +// 1. The interface connecting inferred types into AccessInternal. +// It uses proxy classes to infer return types when necessary. +// 2. Type decaying. This stage gets rid of CV qualifiers and reference types. +// It additionally sets volatile decorators for volatile accesses. +// 3. Type reduction. This stage merges the type of the address with the type of the value +// This might entail infering compressed oops need to be converted. +// 4. Decorator rule inferring. This stage adds decorators according to well defined rules. +// 5. Add buildtime decorators with buildtime capabilities +// 6. Figure out if a dynamic dispatch is necessary, and potentially hardwire basic and raw accesses +// 7. If not hardwired, make a dynamic dispatch through a function pointer that resolves itself at runtime +// The resolved function pointer is looked up in accessConfigure.inline.hpp +// 8. GC barriers can override any not hardwired access calls in the resolved barriers + +// == OPERATIONS == +// * load: Load a value from an address. +// * load_at: Load a value from an internal pointer relative to a base object. +// * store: Store a value at an address. +// * store_at: Store a value in an internal pointer relative to a base object. +// * cas: Atomically Compare-And-Swap a new value at an address if previous value matched the compared value. +// * cas_at: Atomically Compare-And-Swap a new value at an internal pointer address if previous value matched the compared value. +// * swap: Atomically swap a new value at an address if previous value matched the compared value. +// * swap_at: Atomically swap a new value at an internal pointer address if previous value matched the compared value. + +// == MEMORY ORDERING == +// The memory ordering decorators can be described in the following way: +// === Decorator Rules === +// The different types of memory ordering guarantees have a strict order of strength. +// Explicitly specifying the stronger ordering implies that the guarantees of the weaker +// property holds too. +// The following rules are applied to enforce this: +// * MO_SEQ_CST -> MO_ACQUIRE +// * MO_SEQ_CST -> MO_RELEASE +// * MO_ACQUIRE -> MO_ATOMIC +// * MO_RELEASE -> MO_ATOMIC +// * MO_ATOMIC -> MO_VOLATILE +// * !MO_VOLATILE -> MO_RELAXED +// === Stores === +// * MO_SEQ_CST: Sequentially consistent stores. +// - The stores are observed in the same order by MO_SEQ_CST loads on other processors +// - Preceding loads and stores in program order are not reordered with subsequent loads and stores in program order. +// - Guarantees from releasing stores hold. +// * MO_RELEASE: Releasing stores. +// - The releasing store will make its preceding memory accesses observable to memory accesses +// subsequent to an acquiring load observing this releasing store. +// - Guarantees from relaxed stores hold. +// * MO_ATOMIC: Relaxed atomic stores. +// - The stores are atomic. +// - Guarantees from volatile stores hold. +// * MO_VOLATILE: Volatile stores. +// - The stores are not reordered by the compiler (but possibly the HW) w.r.t. other +// volatile accesses in program order (but possibly non-volatile accesses). +// * MO_RELAXED (Default): No guarantees +// - The compiler and hardware are free to reorder aggressively. And they will. +// === Loads === +// * MO_SEQ_CST: Sequentially consistent loads. +// - These loads observe MO_SEQ_CST stores in the same order on other processors +// - Preceding loads and stores in program order are not reordered with subsequent loads and stores in program order. +// - Guarantees from acquiring loads hold. +// * MO_ACQUIRE: Acquiring loads. +// - An acquiring load will make subsequent memory accesses observe the memory accesses +// preceding the releasing store that the acquiring load observed. +// - Guarantees from relaxed stores hold. +// * MO_ATOMIC: Relaxed atomic loads. +// - The stores are atomic. +// - Guarantees from volatile stores hold. +// * MO_VOLATILE: Volatile loads. +// - The loads are not reordered by the compiler (but possibly the HW) w.r.t. other +// volatile accesses in program order (but possibly non-volatile accesses). +// * MO_RELAXED (Default): No guarantees +// - The compiler and hardware are free to reorder aggressively. And they will. +// === CAS === +// * MO_SEQ_CST: Sequentially consistent CAS. +// - Guarantees from MO_SEQ_CST loads and MO_SEQ_CST stores hold unconditionally. +// * MO_ATOMIC: Atomic but relaxed CAS. +// - Guarantees from MO_ATOMIC loads and MO_ATOMIC stores hold unconditionally. +// === Swap === +// * MO_SEQ_CST: Sequentially consistent swap. +// - Guarantees from MO_SEQ_CST loads and MO_SEQ_CST stores hold. +// * MO_ATOMIC: Atomic but relaxed CAS. +// - Guarantees from MO_ATOMIC loads and MO_ATOMIC stores hold. +// +// == GC DECORATORS == +// These decorators describe GC-related properties. +// === Access Location === +// Accesses can take place on in e.g. the heap, old or young generation and different native roots. +// The location is important to the GC as it may imply different actions. The following decorators are used: +// * ACCESS_ON_HEAP: The access is performed in the heap. Many barriers such as card marking will +// be omitted if this decorator is not set. +// * ACCESS_ON_NMETHOD: The access is performed on an nmethod. This decorator may be recognized by GCs +// that track references from nmethods to the heap in special ways. +// * ACCESS_ON_YOUNG: The access is guaranteed to be performed on an object in the young generation +// (if the GC is generational). Recognizing this decorator potentially allows eliding unnecessary GC +// barriers on such young objects. +// Default: EMPTY_DECORATOR +// === Heap Access Type === +// * ACCESS_ON_ARRAY: The access is performed on a heap allocated array. This is sometimes a special case +// for some GCs. +// === Reference Strength === +// These decorators only apply to accesses on oop-like types (oop/narrowOop). +// * GC_ACCESS_ON_STRONG: Memory access is performed on a strongly reachable reference. +// * GC_ACCESS_ON_WEAK: The memory access is performed on a weakly reachable reference. +// * GC_ACCESS_ON_PHANTOM: The memory access is performed on a phantomly reachable reference. +// * Default (no explicit reference strength specified): GC_ACCESS_ON_STRONG +// === Barrier Strength === +// * ACCESS_RAW: The access will translate into a raw memory access, hence ignoring all concerns +// except memory ordering. This will bypass all runtime checks in the pipeline. +// * ACCESS_BASIC: The accesses will ignore all GC-specific concerns except compressed oops, hence +// bypassing as much as possible in the normal pipeline in the most efficient way possible. +// - Accesses on oop* translate to raw memory accesses without runtime checks +// - Accesses on narrowOop* translate to encoded/decoded memory accesses without runtime checks +// - Accesses on HeapWord* translate to a runtime check choosing one of the above +// - Accesses on other types translate to raw memory accesses without runtime checks +// * ACCESS_WEAK: The barrier is weak, meaning that it will not perform GC bookkeeping such as keeping references +// alive, regardless of the type of reference being accessed. It will however perform the memory access +// in a consistent way w.r.t. e.g. concurrent compaction if applicable, so that the right field is being +// accessed. +// Default: Normal accesses do not specify any of the decorators above. They will be resolved at runtime +// according to the needs of the GC. If a GC requiring barriers on primitives is used, even primitive +// types will have their accessors resolved at runtime. +// Use of this decorator is for GC-specific code where hardwiring is possible, but should not be used in runtime code. +// == VALUE DECORATORS == +// * VALUE_NOT_NULL: This property can make certain barriers faster such as compressing oops. +// * DEST_NOT_INITIALIZED: This property can be important to e.g. SATB barriers by marking that the previous value +// uninitialized nonsense rather than a real value. + +typedef uint64_t DecoratorSet; + +enum Decorator { + EMPTY_DECORATOR = UCONST64(0), + DECORATOR_DEFAULT = EMPTY_DECORATOR, + BT_BARRIER_ON_PRIMITIVES = UCONST64(1) << 0, + BT_HAS_BUILDTIME_DECORATOR = UCONST64(1) << 1, + + // Runtime decorators + RT_USE_COMPRESSED_OOPS = UCONST64(1) << 2, + RT_HAS_RUNTIME_DECORATOR = UCONST64(1) << 3, + + // Memory ordering decorators + MO_RELAXED = UCONST64(1) << 4, + MO_VOLATILE = UCONST64(1) << 5, + MO_ATOMIC = UCONST64(1) << 6, + MO_ACQUIRE = UCONST64(1) << 7, + MO_RELEASE = UCONST64(1) << 8, + MO_SEQ_CST = UCONST64(1) << 9, + + // Access decorators + ACCESS_RAW = UCONST64(1) << 10, // Raw accesses with specified memory semantics + ACCESS_BASIC = UCONST64(1) << 11, // Includes compressed oops + ACCESS_WEAK = UCONST64(1) << 12, // Do not keep alive + + // Actor decorators + ACCESS_BY_MUTATOR = UCONST64(1) << 13, + ACCESS_BY_STW_GC = UCONST64(1) << 14, + ACCESS_BY_CONCURRENT_GC = UCONST64(1) << 15, + + // GC decorators + GC_ACCESS_ON_STRONG = UCONST64(1) << 16, + GC_ACCESS_ON_WEAK = UCONST64(1) << 17, + GC_ACCESS_ON_PHANTOM = UCONST64(1) << 18, + + ACCESS_ON_HEAP = UCONST64(1) << 19, + ACCESS_ON_ROOT = UCONST64(1) << 20, + ACCESS_ON_YOUNG = UCONST64(1) << 21, + ACCESS_ON_ARRAY = UCONST64(1) << 22, + ACCESS_ON_ANONYMOUS = UCONST64(1) << 23, + ACCESS_ON_NMETHOD = UCONST64(1) << 24, + ACCESS_ON_KLASS = UCONST64(1) << 25, + + // Barriers for compressed oops + GC_CONVERT_COMPRESSED_OOP = UCONST64(1) << 26, + + // Value decorators + VALUE_NOT_NULL = UCONST64(1) << 27, + VALUE_IS_OOP = UCONST64(1) << 28, + + // Destination address decorators + DEST_NOT_INITIALIZED = UCONST64(1) << 29, + DEST_COVARIANT = UCONST64(1) << 30, + DEST_CONTRAVARIANT = UCONST64(1) << 31, + DEST_CONJOINT = UCONST64(1) << 32, + DEST_DISJOINT = UCONST64(1) << 33, + COPY_ARRAYOF = UCONST64(1) << 34, + + ACCESS_ARRAYCOPY = UCONST64(1) << 35, + ACCESS_ATOMIC = UCONST64(1) << 36, + ACCESS_ALIGNED = UCONST64(1) << 37, + + DECORATOR_END = ACCESS_ALIGNED +}; + +template +struct HasDecorator { + enum { + value = (decorators & (DecoratorSet)decorator) != 0 + }; +}; + +template +struct DecoratorIntersection { + enum { + value = set1 & set2 + }; +}; + +template +struct DecoratorTest { + enum { + HAS_BUILDTIME_DECORATOR = HasDecorator::value, + HAS_RUNTIME_DECORATOR = HasDecorator::value, + HAS_BARRIER_ON_PRIMITIVES = HasDecorator::value, + HAS_USE_COMPRESSED_OOPS = HasDecorator::value, + + HAS_ACCESS_RAW = HasDecorator::value, + HAS_ACCESS_BASIC = HasDecorator::value, + HAS_ACCESS_WEAK = HasDecorator::value, + + HAS_ACCESS_ON_HEAP = HasDecorator::value, + HAS_ACCESS_ON_ARRAY = HasDecorator::value, + HAS_ACCESS_ON_NMETHOD = HasDecorator::value, + HAS_ACCESS_ON_KLASS = HasDecorator::value, + HAS_ACCESS_ON_ROOT = HasDecorator::value, + HAS_ACCESS_ON_ANONYMOUS = HasDecorator::value, + HAS_ACCESS_ON_YOUNG = HasDecorator::value, + + HAS_MO_RELAXED = HasDecorator::value, + HAS_MO_VOLATILE = HasDecorator::value, + HAS_MO_ATOMIC = HasDecorator::value, + HAS_MO_ACQUIRE = HasDecorator::value, + HAS_MO_RELEASE = HasDecorator::value, + HAS_MO_SEQ_CST = HasDecorator::value, + + HAS_GC_CONVERT_COMPRESSED_OOP = HasDecorator::value, + + NEEDS_OOP_COMPRESS = DecoratorTest::HAS_GC_CONVERT_COMPRESSED_OOP && DecoratorTest::HAS_USE_COMPRESSED_OOPS, + + HAS_GC_ACCESS_ON_STRONG = HasDecorator::value, + HAS_GC_ACCESS_ON_WEAK = HasDecorator::value, + HAS_GC_ACCESS_ON_PHANTOM = HasDecorator::value, + + IS_ON_STRONG = HAS_GC_ACCESS_ON_STRONG, + IS_ON_WEAK = HAS_GC_ACCESS_ON_WEAK, + IS_ON_PHANTOM = HAS_GC_ACCESS_ON_PHANTOM, + IS_ON_REFERENCE = HAS_GC_ACCESS_ON_WEAK || HAS_GC_ACCESS_ON_PHANTOM, + IS_WEAK_ACCESS = HAS_ACCESS_WEAK, + + HAS_DEST_CONJOINT = HasDecorator::value, + HAS_DEST_DISJOINT = HasDecorator::value, + HAS_DEST_COVARIANT = HasDecorator::value, + HAS_DEST_CONTRAVARIANT = HasDecorator::value, + HAS_DEST_NOT_INITIALIZED = HasDecorator::value, + + HAS_COPY_ARRAYOF = HasDecorator::value, + + HAS_ACCESS_ATOMIC = HasDecorator::value, + HAS_VALUE_NOT_NULL = HasDecorator::value, + HAS_VALUE_IS_OOP = HasDecorator::value + }; +}; + +namespace AccessInternal { + template + struct OopOrNarrowOopInternal { + typedef oop type; + }; + + template <> + struct OopOrNarrowOopInternal { + typedef narrowOop type; + }; + + template + struct OopOrNarrowOop { + typedef typename OopOrNarrowOopInternal::type>::type type; + }; + + inline void* field_addr(void* base, ptrdiff_t byte_offset) { + return (void*)(intptr_t(base) + byte_offset); + } + + template + void store(P* addr, T value); + + template + void store_at(P base, ptrdiff_t offset, T value); + + template + T load(P* addr); + + template + T load_at(P base, ptrdiff_t offset); + + template + T cas(T new_value, P* addr, T compare_value); + + template + T cas_at(T new_value, P base, ptrdiff_t offset, T compare_value); + + template + T swap(T new_value, P* addr); + + template + T swap_at(T new_value, P base, ptrdiff_t offset); + + template + bool copy(arrayOop src_obj, arrayOop dst_obj, T *src, T *dst, size_t length); + + template + void clone(oop src, oop dst, size_t size); + + template + class LoadProxy { + private: + P *const _addr; + public: + LoadProxy(P* addr) : _addr(addr) {} + + template + inline operator T() { + return load(_addr); + } + + inline operator P() { + return load(_addr); + } + }; + + template + class LoadAtProxy { + private: + const P _base; + const ptrdiff_t _offset; + public: + LoadAtProxy(P base, ptrdiff_t offset) : _base(base), _offset(offset) {} + + template + inline operator T() { + return load_at(_base, _offset); + } + }; +} + +template +class Access: public AllStatic { +public: + template + static inline void store(P* addr, T value) { + AccessInternal::store(addr, value); + } + + template + static inline void oop_store(P* addr, T value) { + AccessInternal::store(addr, value); + } + + template + static inline void store_at(P base, ptrdiff_t offset, T value) { + AccessInternal::store_at(base, offset, value); + } + + template + static inline void oop_store_at(P base, ptrdiff_t offset, T value) { + AccessInternal::store_at(base, offset, value); + } + + template + static inline AccessInternal::LoadProxy load(P* addr) { + return AccessInternal::LoadProxy(addr); + } + + template + static inline AccessInternal::LoadProxy oop_load(P* addr) { + return AccessInternal::LoadProxy(addr); + } + + template + static inline AccessInternal::LoadAtProxy load_at(P base, ptrdiff_t offset) { + return AccessInternal::LoadAtProxy(base, offset); + } + + template + static inline AccessInternal::LoadAtProxy oop_load_at(P base, ptrdiff_t offset) { + return AccessInternal::LoadAtProxy(base, offset); + } + + template + static inline T cas(T new_value, P* addr, T compare_value) { + return AccessInternal::cas(new_value, addr, compare_value); + } + + template + static inline T oop_cas(T new_value, P* addr, T compare_value) { + return AccessInternal::cas(new_value, addr, compare_value); + } + + template + static inline T cas_at(T new_value, P base, ptrdiff_t offset, T compare_value) { + return AccessInternal::cas_at(new_value, base, offset, compare_value); + } + + template + static inline T oop_cas_at(T new_value, P base, ptrdiff_t offset, T compare_value) { + return AccessInternal::cas_at(new_value, base, offset, compare_value); + } + + template + static inline T swap(T new_value, P* addr) { + return AccessInternal::swap(new_value, addr); + } + + template + static inline T oop_swap(T new_value, P* addr) { + return AccessInternal::swap(new_value, addr); + } + + template + static inline T swap_at(T new_value, P base, ptrdiff_t offset) { + return AccessInternal::swap_at(new_value, base, offset); + } + + template + static inline T oop_swap_at(T new_value, P base, ptrdiff_t offset) { + return AccessInternal::swap_at(new_value, base, offset); + } + + template + static inline bool copy(arrayOop src_obj, arrayOop dst_obj, T *src, T *dst, size_t length) { + return AccessInternal::copy(src_obj, dst_obj, src, dst, length); + } + + template + static inline bool oop_copy(arrayOop src_obj, arrayOop dst_obj, T *src, T *dst, size_t length) { + return AccessInternal::copy(src_obj, dst_obj, src, dst, length); + } + + static inline void clone(oop src, oop dst, size_t size) { + AccessInternal::clone(src, dst, size); + } +}; + +template +class RawAccess: public Access {}; + +template +class BasicAccess: public Access {}; + +template +class HeapAccess: public Access { + enum { + CLASS_DECORATORS = ACCESS_ON_HEAP | decorators + }; + typedef Access ClassAccess; + public: + // Constrain base pointers to always be an oop for heap accesses + template + static inline void store_at(oop base, ptrdiff_t offset, T value) { + ClassAccess::store_at(base, offset, value); + } + + template + static inline void oop_store_at(oop base, ptrdiff_t offset, T value) { + ClassAccess::oop_store_at(base, offset, (typename AccessInternal::OopOrNarrowOop::type)value); + } + + static inline AccessInternal::LoadAtProxy + load_at(oop base, ptrdiff_t offset) { + return ClassAccess::load_at(base, offset); + } + + static inline AccessInternal::LoadAtProxy + oop_load_at(oop base, ptrdiff_t offset) { + return ClassAccess::oop_load_at(base, offset); + } + + template + static inline T cas_at(T new_value, oop base, ptrdiff_t offset, T compare_value) { + return ClassAccess::cas_at(new_value, base, offset, compare_value); + } + + template + static inline T oop_cas_at(T new_value, oop base, ptrdiff_t offset, T compare_value) { + return ClassAccess::oop_cas_at((typename AccessInternal::OopOrNarrowOop::type)new_value, base, + offset, (typename AccessInternal::OopOrNarrowOop::type)compare_value); + } + + template + static inline T swap_at(T new_value, oop base, ptrdiff_t offset) { + return ClassAccess::swap_at(new_value, base, offset); + } + + template + static inline T oop_swap_at(T new_value, oop base, ptrdiff_t offset) { + return ClassAccess::oop_swap_at((typename AccessInternal::OopOrNarrowOop::type)new_value, base, offset); + } +}; + +template +class RootAccess: public Access { +}; + +template +class NMethodAccess: private RootAccess { + public: + // Only supported access on nmethods for now + static inline void oop_store_at(nmethod* base, ptrdiff_t offset, oop value) { + AccessInternal::store_at(base, offset, value); + } +}; + +template +class KlassAccess: private RootAccess { + public: + // Only supported access on Klass for now + static inline void oop_store_at(Klass* base, ptrdiff_t offset, oop value) { + AccessInternal::store_at(base, offset, value); + } +}; + +#endif // SHARE_VM_RUNTIME_ACCESS_HPP