Skip to content

8349110: [lworld] Intrinsics for Unsafe.get/putFlatValue #1482

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: lworld
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/hotspot/share/classfile/vmIntrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) {
case vmIntrinsics::_getFloat:
case vmIntrinsics::_getDouble:
case vmIntrinsics::_getValue:
case vmIntrinsics::_getFlatValue:
case vmIntrinsics::_putReference:
case vmIntrinsics::_putBoolean:
case vmIntrinsics::_putByte:
Expand All @@ -350,6 +351,7 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) {
case vmIntrinsics::_putFloat:
case vmIntrinsics::_putDouble:
case vmIntrinsics::_putValue:
case vmIntrinsics::_putFlatValue:
case vmIntrinsics::_getReferenceVolatile:
case vmIntrinsics::_getBooleanVolatile:
case vmIntrinsics::_getByteVolatile:
Expand Down
5 changes: 5 additions & 0 deletions src/hotspot/share/classfile/vmIntrinsics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,8 @@ class methodHandle;
do_signature(putDouble_signature, "(Ljava/lang/Object;JD)V") \
do_signature(getValue_signature, "(Ljava/lang/Object;JLjava/lang/Class;)Ljava/lang/Object;") \
do_signature(putValue_signature, "(Ljava/lang/Object;JLjava/lang/Class;Ljava/lang/Object;)V") \
do_signature(getFlatValue_signature, "(Ljava/lang/Object;JILjava/lang/Class;)Ljava/lang/Object;") \
do_signature(putFlatValue_signature, "(Ljava/lang/Object;JILjava/lang/Class;Ljava/lang/Object;)V") \
\
do_name(getReference_name,"getReference") do_name(putReference_name,"putReference") \
do_name(getBoolean_name,"getBoolean") do_name(putBoolean_name,"putBoolean") \
Expand All @@ -750,6 +752,7 @@ class methodHandle;
do_name(getFloat_name,"getFloat") do_name(putFloat_name,"putFloat") \
do_name(getDouble_name,"getDouble") do_name(putDouble_name,"putDouble") \
do_name(getValue_name,"getValue") do_name(putValue_name,"putValue") \
do_name(getFlatValue_name,"getFlatValue") do_name(putFlatValue_name,"putFlatValue") \
do_name(makePrivateBuffer_name,"makePrivateBuffer") \
do_name(finishPrivateBuffer_name,"finishPrivateBuffer") \
\
Expand All @@ -763,6 +766,7 @@ class methodHandle;
do_intrinsic(_getFloat, jdk_internal_misc_Unsafe, getFloat_name, getFloat_signature, F_RN) \
do_intrinsic(_getDouble, jdk_internal_misc_Unsafe, getDouble_name, getDouble_signature, F_RN) \
do_intrinsic(_getValue, jdk_internal_misc_Unsafe, getValue_name, getValue_signature, F_RN) \
do_intrinsic(_getFlatValue, jdk_internal_misc_Unsafe, getFlatValue_name, getFlatValue_signature, F_RN) \
do_intrinsic(_putReference, jdk_internal_misc_Unsafe, putReference_name, putReference_signature, F_RN) \
do_intrinsic(_putBoolean, jdk_internal_misc_Unsafe, putBoolean_name, putBoolean_signature, F_RN) \
do_intrinsic(_putByte, jdk_internal_misc_Unsafe, putByte_name, putByte_signature, F_RN) \
Expand All @@ -773,6 +777,7 @@ class methodHandle;
do_intrinsic(_putFloat, jdk_internal_misc_Unsafe, putFloat_name, putFloat_signature, F_RN) \
do_intrinsic(_putDouble, jdk_internal_misc_Unsafe, putDouble_name, putDouble_signature, F_RN) \
do_intrinsic(_putValue, jdk_internal_misc_Unsafe, putValue_name, putValue_signature, F_RN) \
do_intrinsic(_putFlatValue, jdk_internal_misc_Unsafe, putFlatValue_name, putFlatValue_signature, F_RN) \
\
do_intrinsic(_makePrivateBuffer, jdk_internal_misc_Unsafe, makePrivateBuffer_name, object_object_signature, F_RN) \
do_intrinsic(_finishPrivateBuffer, jdk_internal_misc_Unsafe, finishPrivateBuffer_name, object_object_signature, F_RN) \
Expand Down
3 changes: 3 additions & 0 deletions src/hotspot/share/opto/c2compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/

#include "classfile/vmClasses.hpp"
#include "classfile/vmIntrinsics.hpp"
#include "compiler/compilationMemoryStatistic.hpp"
#include "compiler/compilerDefinitions.inline.hpp"
#include "runtime/handles.inline.hpp"
Expand Down Expand Up @@ -663,6 +664,7 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) {
case vmIntrinsics::_getFloat:
case vmIntrinsics::_getDouble:
case vmIntrinsics::_getValue:
case vmIntrinsics::_getFlatValue:
case vmIntrinsics::_putReference:
case vmIntrinsics::_putBoolean:
case vmIntrinsics::_putByte:
Expand All @@ -673,6 +675,7 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) {
case vmIntrinsics::_putFloat:
case vmIntrinsics::_putDouble:
case vmIntrinsics::_putValue:
case vmIntrinsics::_putFlatValue:
case vmIntrinsics::_getReferenceVolatile:
case vmIntrinsics::_getBooleanVolatile:
case vmIntrinsics::_getByteVolatile:
Expand Down
170 changes: 170 additions & 0 deletions src/hotspot/share/opto/library_call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,21 @@
*/

#include "asm/macroAssembler.hpp"
#include "ci/ciArrayKlass.hpp"
#include "ci/ciFlatArrayKlass.hpp"
#include "ci/ciInstanceKlass.hpp"
#include "ci/ciUtilities.inline.hpp"
#include "ci/ciSymbols.hpp"
#include "classfile/vmIntrinsics.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/compileLog.hpp"
#include "gc/shared/barrierSet.hpp"
#include "gc/shared/c2/barrierSetC2.hpp"
#include "jfr/support/jfrIntrinsics.hpp"
#include "memory/resourceArea.hpp"
#include "oops/accessDecorators.hpp"
#include "oops/klass.inline.hpp"
#include "oops/layoutKind.hpp"
#include "oops/objArrayKlass.hpp"
#include "opto/addnode.hpp"
#include "opto/arraycopynode.hpp"
Expand All @@ -42,16 +46,20 @@
#include "opto/cfgnode.hpp"
#include "opto/convertnode.hpp"
#include "opto/countbitsnode.hpp"
#include "opto/graphKit.hpp"
#include "opto/idealKit.hpp"
#include "opto/library_call.hpp"
#include "opto/inlinetypenode.hpp"
#include "opto/mathexactnode.hpp"
#include "opto/mulnode.hpp"
#include "opto/narrowptrnode.hpp"
#include "opto/opaquenode.hpp"
#include "opto/opcodes.hpp"
#include "opto/parse.hpp"
#include "opto/runtime.hpp"
#include "opto/rootnode.hpp"
#include "opto/subnode.hpp"
#include "opto/type.hpp"
#include "opto/vectornode.hpp"
#include "prims/jvmtiExport.hpp"
#include "prims/jvmtiThreadState.hpp"
Expand All @@ -60,6 +68,7 @@
#include "runtime/objectMonitor.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
#include "utilities/powerOfTwo.hpp"

Expand Down Expand Up @@ -411,6 +420,9 @@ bool LibraryCallKit::try_to_inline(int predicate) {
case vmIntrinsics::_putFloatOpaque: return inline_unsafe_access( is_store, T_FLOAT, Opaque, false);
case vmIntrinsics::_putDoubleOpaque: return inline_unsafe_access( is_store, T_DOUBLE, Opaque, false);

case vmIntrinsics::_getFlatValue: return inline_unsafe_flat_access(!is_store, Relaxed);
case vmIntrinsics::_putFlatValue: return inline_unsafe_flat_access( is_store, Relaxed);

case vmIntrinsics::_compareAndSetReference: return inline_unsafe_load_store(T_OBJECT, LS_cmp_swap, Volatile);
case vmIntrinsics::_compareAndSetByte: return inline_unsafe_load_store(T_BYTE, LS_cmp_swap, Volatile);
case vmIntrinsics::_compareAndSetShort: return inline_unsafe_load_store(T_SHORT, LS_cmp_swap, Volatile);
Expand Down Expand Up @@ -2704,6 +2716,164 @@ bool LibraryCallKit::inline_unsafe_access(bool is_store, const BasicType type, c
return true;
}

bool LibraryCallKit::inline_unsafe_flat_access(bool is_store, AccessKind kind) {
#ifdef ASSERT
{
ResourceMark rm;
// Check the signatures.
ciSignature* sig = callee()->signature();
assert(sig->type_at(0)->basic_type() == T_OBJECT, "base should be object, but is %s", type2name(sig->type_at(0)->basic_type()));
assert(sig->type_at(1)->basic_type() == T_LONG, "offset should be long, but is %s", type2name(sig->type_at(1)->basic_type()));
assert(sig->type_at(2)->basic_type() == T_INT, "layout kind should be int, but is %s", type2name(sig->type_at(3)->basic_type()));
assert(sig->type_at(3)->basic_type() == T_OBJECT, "value klass should be object, but is %s", type2name(sig->type_at(4)->basic_type()));
if (is_store) {
assert(sig->return_type()->basic_type() == T_VOID, "putter must not return a value, but returns %s", type2name(sig->return_type()->basic_type()));
assert(sig->count() == 5, "flat putter should have 5 arguments, but has %d", sig->count());
assert(sig->type_at(4)->basic_type() == T_OBJECT, "put value should be object, but is %s", type2name(sig->type_at(5)->basic_type()));
} else {
assert(sig->return_type()->basic_type() == T_OBJECT, "getter must return an object, but returns %s", type2name(sig->return_type()->basic_type()));
assert(sig->count() == 4, "flat getter should have 4 arguments, but has %d", sig->count());
}
}
#endif // ASSERT

assert(kind == Relaxed, "Only plain accesses for now");
if (callee()->is_static()) {
// caller must have the capability!
return false;
}
C->set_has_unsafe_access(true);

const TypeInstPtr* value_klass_node = _gvn.type(argument(5))->isa_instptr();
if (value_klass_node == nullptr || value_klass_node->const_oop() == nullptr) {
// parameter valueType is not a constant
return false;
}
ciInlineKlass* value_klass = value_klass_node->const_oop()->as_instance()->java_mirror_type()->as_inline_klass();

const TypeInt* layout_type = _gvn.type(argument(4))->isa_int();
if (layout_type == nullptr || !layout_type->is_con()) {
// parameter layoutKind is not a constant
return false;
}
assert(layout_type->get_con() >= static_cast<int>(LayoutKind::REFERENCE) &&
layout_type->get_con() <= static_cast<int>(LayoutKind::UNKNOWN),
"invalid layoutKind %d", layout_type->get_con());
LayoutKind layout = static_cast<LayoutKind>(layout_type->get_con());
assert(layout == LayoutKind::REFERENCE || layout == LayoutKind::NON_ATOMIC_FLAT ||
layout == LayoutKind::ATOMIC_FLAT || layout == LayoutKind::NULLABLE_ATOMIC_FLAT,
"unexpected layoutKind %d", layout_type->get_con());

null_check(argument(0));
if (stopped()) {
return true;
}

Node* base = must_be_not_null(argument(1), true);
Node* offset = argument(2);
const Type* base_type = _gvn.type(base);

Node* ptr;
bool immutable_memory = false;
DecoratorSet decorators = C2_UNSAFE_ACCESS | IN_HEAP | MO_UNORDERED;
if (base_type->isa_instptr()) {
const TypeLong* offset_type = _gvn.type(offset)->isa_long();
if (offset_type == nullptr || !offset_type->is_con()) {
// Offset into a non-array should be a constant
decorators |= C2_MISMATCHED;
} else {
int offset_con = checked_cast<int>(offset_type->get_con());
ciInstanceKlass* base_klass = base_type->is_instptr()->instance_klass();
ciField* field = base_klass->get_non_flat_field_by_offset(offset_con);
if (field == nullptr) {
assert(!base_klass->is_final(), "non-existence field at offset %d of class %s", offset_con, base_klass->name()->as_utf8());
decorators |= C2_MISMATCHED;
} else {
assert(field->type() == value_klass, "field at offset %d of %s is of type %s, but valueType is %s",
offset_con, base_klass->name()->as_utf8(), field->type()->name(), value_klass->name()->as_utf8());
immutable_memory = field->is_strict() && field->is_final();

if (base->is_InlineType()) {
assert(!is_store, "Cannot store into a non-larval value object");
set_result(base->as_InlineType()->field_value_by_offset(offset_con, false));
return true;
}
}
}

if (base->is_InlineType()) {
assert(!is_store, "Cannot store into a non-larval value object");
base = base->as_InlineType()->buffer(this, true);
}
ptr = basic_plus_adr(base, ConvL2X(offset));
} else if (base_type->isa_aryptr()) {
decorators |= IS_ARRAY;
if (layout == LayoutKind::REFERENCE) {
if (!base_type->is_aryptr()->is_not_flat()) {
const TypeAryPtr* array_type = base_type->is_aryptr()->cast_to_not_flat();
Node* new_base = _gvn.transform(new CastPPNode(control(), base, array_type, ConstraintCastNode::StrongDependency));
replace_in_map(base, new_base);
base = new_base;
}
ptr = basic_plus_adr(base, ConvL2X(offset));
} else {
// Flat array must have an exact type
bool is_null_free = layout != LayoutKind::NULLABLE_ATOMIC_FLAT;
bool is_atomic = layout != LayoutKind::NON_ATOMIC_FLAT;
Node* new_base = cast_to_flat_array(base, value_klass, is_null_free, !is_null_free, is_atomic);
replace_in_map(base, new_base);
base = new_base;
ptr = basic_plus_adr(base, ConvL2X(offset));
const TypeAryPtr* ptr_type = _gvn.type(ptr)->is_aryptr();
if (ptr_type->field_offset().get() != 0) {
ptr = _gvn.transform(new CastPPNode(control(), ptr, ptr_type->with_field_offset(0), ConstraintCastNode::StrongDependency));
}
}
} else {
decorators |= C2_MISMATCHED;
ptr = basic_plus_adr(base, ConvL2X(offset));
}

if (is_store) {
Node* value = argument(6);
const Type* value_type = _gvn.type(value);
if (!value_type->is_inlinetypeptr()) {
value_type = Type::get_const_type(value_klass)->filter_speculative(value_type);
Node* new_value = _gvn.transform(new CastPPNode(control(), value, value_type, ConstraintCastNode::StrongDependency));
new_value = InlineTypeNode::make_from_oop(this, new_value, value_klass);
replace_in_map(value, new_value);
value = new_value;
}

assert(value_type->inline_klass() == value_klass, "value is of type %s while valueType is %s", value_type->inline_klass()->name()->as_utf8(), value_klass->name()->as_utf8());
if (layout == LayoutKind::REFERENCE) {
const TypePtr* ptr_type = (decorators & C2_MISMATCHED) != 0 ? TypeRawPtr::BOTTOM : _gvn.type(ptr)->is_ptr();
access_store_at(base, ptr, ptr_type, value, value_type, T_OBJECT, decorators);
} else {
bool atomic = layout != LayoutKind::NON_ATOMIC_FLAT;
bool null_free = layout != LayoutKind::NULLABLE_ATOMIC_FLAT;
value->as_InlineType()->store_flat(this, base, ptr, atomic, immutable_memory, null_free, decorators);
}

return true;
} else {
decorators |= (C2_CONTROL_DEPENDENT_LOAD | C2_UNKNOWN_CONTROL_LOAD);
InlineTypeNode* result;
if (layout == LayoutKind::REFERENCE) {
const TypePtr* ptr_type = (decorators & C2_MISMATCHED) != 0 ? TypeRawPtr::BOTTOM : _gvn.type(ptr)->is_ptr();
Node* oop = access_load_at(base, ptr, ptr_type, Type::get_const_type(value_klass), T_OBJECT, decorators);
result = InlineTypeNode::make_from_oop(this, oop, value_klass);
} else {
bool atomic = layout != LayoutKind::NON_ATOMIC_FLAT;
bool null_free = layout != LayoutKind::NULLABLE_ATOMIC_FLAT;
result = InlineTypeNode::make_from_flat(this, value_klass, base, ptr, atomic, immutable_memory, null_free, decorators);
}

set_result(result);
return true;
}
}

bool LibraryCallKit::inline_unsafe_make_private_buffer() {
Node* receiver = argument(0);
Node* value = argument(1);
Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/opto/library_call.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ class LibraryCallKit : public GraphKit {
typedef enum { Relaxed, Opaque, Volatile, Acquire, Release } AccessKind;
DecoratorSet mo_decorator_for_access_kind(AccessKind kind);
bool inline_unsafe_access(bool is_store, BasicType type, AccessKind kind, bool is_unaligned, bool is_flat = false);
bool inline_unsafe_flat_access(bool is_store, AccessKind kind);
static bool klass_needs_init_guard(Node* kls);
bool inline_unsafe_allocate();
bool inline_unsafe_newArray(bool uninitialized);
Expand Down
2 changes: 2 additions & 0 deletions src/java.base/share/classes/jdk/internal/misc/Unsafe.java
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ public native Object[] newSpecialArray(Class<?> componentType,
* @throws RuntimeException No defined exceptions are thrown, not even
* {@link NullPointerException}
*/
@IntrinsicCandidate
public native <V> V getFlatValue(Object o, long offset, int layoutKind, Class<?> valueType);


Expand Down Expand Up @@ -377,6 +378,7 @@ public native Object[] newSpecialArray(Class<?> componentType,
* @throws RuntimeException No defined exceptions are thrown, not even
* {@link NullPointerException}
*/
@IntrinsicCandidate
public native <V> void putFlatValue(Object o, long offset, int layoutKind, Class<?> valueType, V v);

/**
Expand Down
Loading