< prev index next >
src/hotspot/share/opto/library_call.cpp
Print this page
*** 267,276 ****
--- 267,278 ----
bool inline_unsafe_access(bool is_store, BasicType type, AccessKind kind, bool is_unaligned);
static bool klass_needs_init_guard(Node* kls);
bool inline_unsafe_allocate();
bool inline_unsafe_newArray(bool uninitialized);
bool inline_unsafe_copyMemory();
+ bool inline_unsafe_make_private_buffer();
+ bool inline_unsafe_finish_private_buffer();
bool inline_native_currentThread();
bool inline_native_time_funcs(address method, const char* funcName);
#ifdef JFR_HAVE_INTRINSICS
bool inline_native_classID();
*** 601,629 ****
--- 603,635 ----
case vmIntrinsics::_compressStringC:
case vmIntrinsics::_compressStringB: return inline_string_copy( is_compress);
case vmIntrinsics::_inflateStringC:
case vmIntrinsics::_inflateStringB: return inline_string_copy(!is_compress);
+ case vmIntrinsics::_makePrivateBuffer: return inline_unsafe_make_private_buffer();
+ case vmIntrinsics::_finishPrivateBuffer: return inline_unsafe_finish_private_buffer();
case vmIntrinsics::_getReference: return inline_unsafe_access(!is_store, T_OBJECT, Relaxed, false);
case vmIntrinsics::_getBoolean: return inline_unsafe_access(!is_store, T_BOOLEAN, Relaxed, false);
case vmIntrinsics::_getByte: return inline_unsafe_access(!is_store, T_BYTE, Relaxed, false);
case vmIntrinsics::_getShort: return inline_unsafe_access(!is_store, T_SHORT, Relaxed, false);
case vmIntrinsics::_getChar: return inline_unsafe_access(!is_store, T_CHAR, Relaxed, false);
case vmIntrinsics::_getInt: return inline_unsafe_access(!is_store, T_INT, Relaxed, false);
case vmIntrinsics::_getLong: return inline_unsafe_access(!is_store, T_LONG, Relaxed, false);
case vmIntrinsics::_getFloat: return inline_unsafe_access(!is_store, T_FLOAT, Relaxed, false);
case vmIntrinsics::_getDouble: return inline_unsafe_access(!is_store, T_DOUBLE, Relaxed, false);
+ case vmIntrinsics::_getValue: return inline_unsafe_access(!is_store, T_VALUETYPE,Relaxed, false);
case vmIntrinsics::_putReference: return inline_unsafe_access( is_store, T_OBJECT, Relaxed, false);
case vmIntrinsics::_putBoolean: return inline_unsafe_access( is_store, T_BOOLEAN, Relaxed, false);
case vmIntrinsics::_putByte: return inline_unsafe_access( is_store, T_BYTE, Relaxed, false);
case vmIntrinsics::_putShort: return inline_unsafe_access( is_store, T_SHORT, Relaxed, false);
case vmIntrinsics::_putChar: return inline_unsafe_access( is_store, T_CHAR, Relaxed, false);
case vmIntrinsics::_putInt: return inline_unsafe_access( is_store, T_INT, Relaxed, false);
case vmIntrinsics::_putLong: return inline_unsafe_access( is_store, T_LONG, Relaxed, false);
case vmIntrinsics::_putFloat: return inline_unsafe_access( is_store, T_FLOAT, Relaxed, false);
case vmIntrinsics::_putDouble: return inline_unsafe_access( is_store, T_DOUBLE, Relaxed, false);
+ case vmIntrinsics::_putValue: return inline_unsafe_access( is_store, T_VALUETYPE,Relaxed, false);
case vmIntrinsics::_getReferenceVolatile: return inline_unsafe_access(!is_store, T_OBJECT, Volatile, false);
case vmIntrinsics::_getBooleanVolatile: return inline_unsafe_access(!is_store, T_BOOLEAN, Volatile, false);
case vmIntrinsics::_getByteVolatile: return inline_unsafe_access(!is_store, T_BYTE, Volatile, false);
case vmIntrinsics::_getShortVolatile: return inline_unsafe_access(!is_store, T_SHORT, Volatile, false);
*** 2360,2381 ****
ciSignature* sig = callee()->signature();
#ifdef ASSERT
if (!is_store) {
// Object getReference(Object base, int/long offset), etc.
BasicType rtype = sig->return_type()->basic_type();
! assert(rtype == type, "getter must return the expected value");
! assert(sig->count() == 2, "oop getter has 2 arguments");
assert(sig->type_at(0)->basic_type() == T_OBJECT, "getter base is object");
assert(sig->type_at(1)->basic_type() == T_LONG, "getter offset is correct");
} else {
// void putReference(Object base, int/long offset, Object x), etc.
assert(sig->return_type()->basic_type() == T_VOID, "putter must not return a value");
! assert(sig->count() == 3, "oop putter has 3 arguments");
assert(sig->type_at(0)->basic_type() == T_OBJECT, "putter base is object");
assert(sig->type_at(1)->basic_type() == T_LONG, "putter offset is correct");
BasicType vtype = sig->type_at(sig->count()-1)->basic_type();
! assert(vtype == type, "putter must accept the expected value");
}
#endif // ASSERT
}
#endif //PRODUCT
--- 2366,2387 ----
ciSignature* sig = callee()->signature();
#ifdef ASSERT
if (!is_store) {
// Object getReference(Object base, int/long offset), etc.
BasicType rtype = sig->return_type()->basic_type();
! assert(rtype == type || (rtype == T_OBJECT && type == T_VALUETYPE), "getter must return the expected value");
! assert(sig->count() == 2 || (type == T_VALUETYPE && sig->count() == 3), "oop getter has 2 or 3 arguments");
assert(sig->type_at(0)->basic_type() == T_OBJECT, "getter base is object");
assert(sig->type_at(1)->basic_type() == T_LONG, "getter offset is correct");
} else {
// void putReference(Object base, int/long offset, Object x), etc.
assert(sig->return_type()->basic_type() == T_VOID, "putter must not return a value");
! assert(sig->count() == 3 || (type == T_VALUETYPE && sig->count() == 4), "oop putter has 3 arguments");
assert(sig->type_at(0)->basic_type() == T_OBJECT, "putter base is object");
assert(sig->type_at(1)->basic_type() == T_LONG, "putter offset is correct");
BasicType vtype = sig->type_at(sig->count()-1)->basic_type();
! assert(vtype == type || (type == T_VALUETYPE && vtype == T_OBJECT), "putter must accept the expected value");
}
#endif // ASSERT
}
#endif //PRODUCT
*** 2397,2431 ****
// to be plain byte offsets, which are also the same as those accepted
// by oopDesc::field_addr.
assert(Unsafe_field_offset_to_byte_offset(11) == 11,
"fieldOffset must be byte-scaled");
! if (base->is_ValueType()) {
! if (is_store) {
return false;
}
ValueTypeNode* vt = base->as_ValueType();
if (offset->is_Con()) {
long off = find_long_con(offset, 0);
ciValueKlass* vk = _gvn.type(vt)->is_valuetype()->value_klass();
if ((long)(int)off != off || !vk->contains_field_offset(off)) {
return false;
}
! receiver = null_check(receiver);
! if (stopped()) {
! return true;
! }
! set_result(vt->field_value_by_offset((int)off, true));
! return true;
! } else {
! receiver = null_check(receiver);
! if (stopped()) {
return true;
}
vt = vt->allocate(this)->as_ValueType();
base = vt->get_oop();
}
}
--- 2403,2466 ----
// to be plain byte offsets, which are also the same as those accepted
// by oopDesc::field_addr.
assert(Unsafe_field_offset_to_byte_offset(11) == 11,
"fieldOffset must be byte-scaled");
! ciValueKlass* value_klass = NULL;
! if (type == T_VALUETYPE) {
! Node* cls = null_check(argument(4));
! if (stopped()) {
! return true;
! }
! Node* kls = load_klass_from_mirror(cls, false, NULL, 0);
! const TypeKlassPtr* kls_t = _gvn.type(kls)->isa_klassptr();
! if (!kls_t->klass_is_exact()) {
! return false;
! }
! ciKlass* klass = kls_t->klass();
! if (!klass->is_valuetype()) {
return false;
}
+ value_klass = klass->as_value_klass();
+ }
+ receiver = null_check(receiver);
+ if (stopped()) {
+ return true;
+ }
+
+ if (base->is_ValueType()) {
ValueTypeNode* vt = base->as_ValueType();
+
+ if (is_store) {
+ if (!vt->is_allocated(&_gvn) || !_gvn.type(vt)->is_valuetype()->larval()) {
+ return false;
+ }
+ base = vt->get_oop();
+ } else {
if (offset->is_Con()) {
long off = find_long_con(offset, 0);
ciValueKlass* vk = _gvn.type(vt)->is_valuetype()->value_klass();
if ((long)(int)off != off || !vk->contains_field_offset(off)) {
return false;
}
! ciField* f = vk->get_non_flattened_field_by_offset((int)off);
! if (f != NULL) {
! BasicType bt = f->layout_type();
! if (bt == T_ARRAY || bt == T_NARROWOOP) {
! bt = T_OBJECT;
! }
! if (bt == type) {
! if (bt != T_VALUETYPE || f->type() == value_klass) {
! set_result(vt->field_value_by_offset((int)off, false));
return true;
}
+ }
+ }
+ }
vt = vt->allocate(this)->as_ValueType();
base = vt->get_oop();
}
}
*** 2433,2454 ****
offset = ConvL2X(offset);
adr = make_unsafe_address(base, offset, is_store ? ACCESS_WRITE : ACCESS_READ, type, kind == Relaxed);
if (_gvn.type(base)->isa_ptr() != TypePtr::NULL_PTR) {
heap_base_oop = base;
! } else if (type == T_OBJECT) {
return false; // off-heap oop accesses are not supported
}
// Can base be NULL? Otherwise, always on-heap access.
bool can_access_non_heap = TypePtr::NULL_PTR->higher_equal(_gvn.type(heap_base_oop));
if (!can_access_non_heap) {
decorators |= IN_HEAP;
}
! val = is_store ? argument(4) : NULL;
const TypePtr *adr_type = _gvn.type(adr)->isa_ptr();
// Try to categorize the address.
Compile::AliasType* alias_type = C->alias_type(adr_type);
--- 2468,2489 ----
offset = ConvL2X(offset);
adr = make_unsafe_address(base, offset, is_store ? ACCESS_WRITE : ACCESS_READ, type, kind == Relaxed);
if (_gvn.type(base)->isa_ptr() != TypePtr::NULL_PTR) {
heap_base_oop = base;
! } else if (type == T_OBJECT || (value_klass != NULL && value_klass->has_object_fields())) {
return false; // off-heap oop accesses are not supported
}
// Can base be NULL? Otherwise, always on-heap access.
bool can_access_non_heap = TypePtr::NULL_PTR->higher_equal(_gvn.type(heap_base_oop));
if (!can_access_non_heap) {
decorators |= IN_HEAP;
}
! val = is_store ? argument(4 + (type == T_VALUETYPE ? 1 : 0)) : NULL;
const TypePtr *adr_type = _gvn.type(adr)->isa_ptr();
// Try to categorize the address.
Compile::AliasType* alias_type = C->alias_type(adr_type);
*** 2458,2468 ****
alias_type->adr_type() == TypeAryPtr::RANGE) {
return false; // not supported
}
bool mismatched = false;
! BasicType bt = alias_type->basic_type();
if (bt != T_ILLEGAL) {
assert(alias_type->adr_type()->is_oopptr(), "should be on-heap access");
if (bt == T_BYTE && adr_type->isa_aryptr()) {
// Alias type doesn't differentiate between byte[] and boolean[]).
// Use address type to get the element type.
--- 2493,2520 ----
alias_type->adr_type() == TypeAryPtr::RANGE) {
return false; // not supported
}
bool mismatched = false;
! BasicType bt = T_ILLEGAL;
! ciField* field = NULL;
! if (adr_type->isa_instptr()) {
! const TypeInstPtr* instptr = adr_type->is_instptr();
! ciInstanceKlass* k = instptr->klass()->as_instance_klass();
! int off = instptr->offset();
! field = k->get_non_flattened_field_by_offset(off);
! if (field != NULL) {
! bt = field->layout_type();
! }
! assert(bt == alias_type->basic_type() || bt == T_VALUETYPE, "should match");
! if (field != NULL && bt == T_VALUETYPE && !field->is_flattened()) {
! bt = T_OBJECT;
! }
! } else {
! bt = alias_type->basic_type();
! }
!
if (bt != T_ILLEGAL) {
assert(alias_type->adr_type()->is_oopptr(), "should be on-heap access");
if (bt == T_BYTE && adr_type->isa_aryptr()) {
// Alias type doesn't differentiate between byte[] and boolean[]).
// Use address type to get the element type.
*** 2479,2488 ****
--- 2531,2562 ----
mismatched = (bt != type);
} else if (alias_type->adr_type()->isa_oopptr()) {
mismatched = true; // conservatively mark all "wide" on-heap accesses as mismatched
}
+ if (type == T_VALUETYPE) {
+ if (adr_type->isa_instptr()) {
+ if (field == NULL || field->type() != value_klass) {
+ mismatched = true;
+ }
+ } else if (adr_type->isa_aryptr()) {
+ const Type* elem = adr_type->is_aryptr()->elem();
+ if (!elem->isa_valuetype()) {
+ mismatched = true;
+ } else if (elem->is_valuetype()->value_klass() != value_klass) {
+ mismatched = true;
+ }
+ }
+ if (is_store) {
+ const Type* val_t = _gvn.type(val);
+ if (!val_t->isa_valuetype() ||
+ val_t->is_valuetype()->value_klass() != value_klass) {
+ return false;
+ }
+ }
+ }
+
assert(!mismatched || alias_type->adr_type()->is_oopptr(), "off-heap access can't be mismatched");
if (mismatched) {
decorators |= C2_MISMATCHED;
}
*** 2491,2527 ****
const Type *value_type = Type::get_const_basic_type(type);
// Figure out the memory ordering.
decorators |= mo_decorator_for_access_kind(kind);
! if (!is_store && type == T_OBJECT) {
const TypeOopPtr* tjp = sharpen_unsafe_type(alias_type, adr_type);
if (tjp != NULL) {
value_type = tjp;
}
}
-
- receiver = null_check(receiver);
- if (stopped()) {
- return true;
}
// Heap pointers get a null-check from the interpreter,
// as a courtesy. However, this is not guaranteed by Unsafe,
// and it is not possible to fully distinguish unintended nulls
// from intended ones in this API.
if (!is_store) {
Node* p = NULL;
// Try to constant fold a load from a constant field
! ciField* field = alias_type->field();
if (heap_base_oop != top() && field != NULL && field->is_constant() && !mismatched) {
// final or stable field
p = make_constant_from_field(field, heap_base_oop);
}
if (p == NULL) { // Could not constant fold the load
p = access_load_at(heap_base_oop, adr, adr_type, value_type, type, decorators);
// Normalize the value returned by getBoolean in the following cases
if (type == T_BOOLEAN &&
(mismatched ||
heap_base_oop == top() || // - heap_base_oop is NULL or
(can_access_non_heap && field == NULL)) // - heap_base_oop is potentially NULL
--- 2565,2611 ----
const Type *value_type = Type::get_const_basic_type(type);
// Figure out the memory ordering.
decorators |= mo_decorator_for_access_kind(kind);
! if (!is_store) {
! if (type == T_OBJECT) {
const TypeOopPtr* tjp = sharpen_unsafe_type(alias_type, adr_type);
if (tjp != NULL) {
value_type = tjp;
}
+ } else if (type == T_VALUETYPE) {
+ value_type = NULL;
}
}
+
// Heap pointers get a null-check from the interpreter,
// as a courtesy. However, this is not guaranteed by Unsafe,
// and it is not possible to fully distinguish unintended nulls
// from intended ones in this API.
if (!is_store) {
Node* p = NULL;
// Try to constant fold a load from a constant field
!
if (heap_base_oop != top() && field != NULL && field->is_constant() && !mismatched) {
// final or stable field
p = make_constant_from_field(field, heap_base_oop);
}
if (p == NULL) { // Could not constant fold the load
+ if (type == T_VALUETYPE) {
+ if (adr_type->isa_instptr() && !mismatched) {
+ ciInstanceKlass* holder = adr_type->is_instptr()->klass()->as_instance_klass();
+ int offset = adr_type->is_instptr()->offset();
+ p = ValueTypeNode::make_from_flattened(this, value_klass, base, base, holder, offset, decorators);
+ } else {
+ p = ValueTypeNode::make_from_flattened(this, value_klass, base, adr, NULL, 0, decorators);
+ }
+ } else {
p = access_load_at(heap_base_oop, adr, adr_type, value_type, type, decorators);
+ }
// Normalize the value returned by getBoolean in the following cases
if (type == T_BOOLEAN &&
(mismatched ||
heap_base_oop == top() || // - heap_base_oop is NULL or
(can_access_non_heap && field == NULL)) // - heap_base_oop is potentially NULL
*** 2544,2556 ****
}
if (type == T_ADDRESS) {
p = gvn().transform(new CastP2XNode(NULL, p));
p = ConvX2UL(p);
}
! if (field != NULL && field->is_flattenable()) {
// Load a non-flattened but flattenable value type from memory
- assert(!field->is_flattened(), "unsafe value type load from flattened field");
if (value_type->value_klass()->is_scalarizable()) {
p = ValueTypeNode::make_from_oop(this, p, value_type->value_klass());
} else {
p = null2default(p, value_type->value_klass());
}
--- 2628,2639 ----
}
if (type == T_ADDRESS) {
p = gvn().transform(new CastP2XNode(NULL, p));
p = ConvX2UL(p);
}
! if (field != NULL && field->is_flattenable()&& !field->is_flattened()) {
// Load a non-flattened but flattenable value type from memory
if (value_type->value_klass()->is_scalarizable()) {
p = ValueTypeNode::make_from_oop(this, p, value_type->value_klass());
} else {
p = null2default(p, value_type->value_klass());
}
*** 2564,2575 ****
--- 2647,2710 ----
if (bt == T_ADDRESS) {
// Repackage the long as a pointer.
val = ConvL2X(val);
val = gvn().transform(new CastX2PNode(val));
}
+ if (type == T_VALUETYPE) {
+ if (adr_type->isa_instptr() && !mismatched) {
+ ciInstanceKlass* holder = adr_type->is_instptr()->klass()->as_instance_klass();
+ int offset = adr_type->is_instptr()->offset();
+ val->as_ValueType()->store_flattened(this, base, base, holder, offset, decorators);
+ } else {
+ val->as_ValueType()->store_flattened(this, base, adr, NULL, 0, decorators);
+ }
+ } else {
access_store_at(heap_base_oop, adr, adr_type, val, value_type, type, decorators);
}
+ }
+
+ return true;
+ }
+
+ bool LibraryCallKit::inline_unsafe_make_private_buffer() {
+ Node* receiver = argument(0);
+ Node* value = argument(1);
+
+ receiver = null_check(receiver);
+ if (stopped()) {
+ return true;
+ }
+
+ if (!value->is_ValueType()) {
+ return false;
+ }
+
+ set_result(value->as_ValueType()->make_larval(this));
+
+ return true;
+ }
+ bool LibraryCallKit::inline_unsafe_finish_private_buffer() {
+ Node* receiver = argument(0);
+ Node* buffer = argument(1);
+
+ if (!buffer->is_ValueType()) {
+ return false;
+ }
+ ValueTypeNode* vt = buffer->as_ValueType();
+ if (!vt->is_allocated(&_gvn) || !_gvn.type(vt)->is_valuetype()->larval()) {
+ return false;
+ }
+ buffer = vt->get_oop();
+
+ const Type* buffer_t = _gvn.type(buffer);
+
+ if (!buffer_t->is_valuetypeptr() || buffer_t->maybe_null()) {
+ return false;
+ }
+
+ Node* value = ValueTypeNode::make_from_oop(this, buffer, buffer_t->value_klass());
+ set_result(value);
return true;
}
//----------------------------inline_unsafe_load_store----------------------------
< prev index next >