Skip to content

Commit 0bbfece

Browse files
Quan Anh MaiJatin Bhateja
authored andcommitted
8352647: [lworld] Remove larval InlineTypeNode in Unsafe intrinsics
Reviewed-by: jbhateja, thartmann
1 parent a85d0a2 commit 0bbfece

File tree

4 files changed

+98
-19
lines changed

4 files changed

+98
-19
lines changed

src/hotspot/share/opto/doCall.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "compiler/compileBroker.hpp"
3030
#include "compiler/compileLog.hpp"
3131
#include "interpreter/linkResolver.hpp"
32+
#include "jvm_io.h"
3233
#include "logging/log.hpp"
3334
#include "logging/logLevel.hpp"
3435
#include "logging/logMessage.hpp"
@@ -146,7 +147,21 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
146147
// methods. If these methods are replaced with specialized code,
147148
// then we return it as the inlined version of the call.
148149
CallGenerator* cg_intrinsic = nullptr;
149-
if (allow_inline && allow_intrinsics) {
150+
if (callee->intrinsic_id() == vmIntrinsics::_makePrivateBuffer || callee->intrinsic_id() == vmIntrinsics::_finishPrivateBuffer) {
151+
// These methods must be inlined so that we don't have larval value objects crossing method
152+
// boundaries
153+
assert(!call_does_dispatch, "callee should not be virtual %s", callee->name()->as_utf8());
154+
CallGenerator* cg = find_intrinsic(callee, call_does_dispatch);
155+
156+
if (cg == nullptr) {
157+
// This is probably because the intrinsics is disabled from the command line
158+
char reason[256];
159+
jio_snprintf(reason, sizeof(reason), "cannot find an intrinsics for %s", callee->name()->as_utf8());
160+
C->record_method_not_compilable(reason);
161+
return nullptr;
162+
}
163+
return cg;
164+
} else if (allow_inline && allow_intrinsics) {
150165
CallGenerator* cg = find_intrinsic(callee, call_does_dispatch);
151166
if (cg != nullptr) {
152167
if (cg->is_predicated()) {
@@ -644,6 +659,10 @@ void Parse::do_call() {
644659
// This call checks with CHA, the interpreter profile, intrinsics table, etc.
645660
// It decides whether inlining is desirable or not.
646661
CallGenerator* cg = C->call_generator(callee, vtable_index, call_does_dispatch, jvms, try_inline, prof_factor(), speculative_receiver_type);
662+
if (failing()) {
663+
return;
664+
}
665+
assert(cg != nullptr, "must find a CallGenerator for callee %s", callee->name()->as_utf8());
647666

648667
// NOTE: Don't use orig_callee and callee after this point! Use cg->method() instead.
649668
orig_callee = callee = nullptr;

src/hotspot/share/opto/graphKit.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3503,9 +3503,22 @@ Node* GraphKit::gen_instanceof(Node* obj, Node* superklass, bool safe_for_replac
35033503
// If failure_control is supplied and not null, it is filled in with
35043504
// the control edge for the cast failure. Otherwise, an appropriate
35053505
// uncommon trap or exception is thrown.
3506-
Node* GraphKit::gen_checkcast(Node *obj, Node* superklass, Node* *failure_control, bool null_free) {
3506+
Node* GraphKit::gen_checkcast(Node* obj, Node* superklass, Node* *failure_control, bool null_free) {
35073507
kill_dead_locals(); // Benefit all the uncommon traps
35083508
const TypeKlassPtr* klass_ptr_type = _gvn.type(superklass)->is_klassptr();
3509+
const Type* obj_type = _gvn.type(obj);
3510+
if (obj_type->is_inlinetypeptr() && !obj_type->maybe_null() && klass_ptr_type->klass_is_exact() && obj_type->inline_klass() == klass_ptr_type->exact_klass(true)) {
3511+
// Special case: larval inline objects must not be scalarized. They are also generally not
3512+
// allowed to participate in most operations except as the first operand of putfield, or as an
3513+
// argument to a constructor invocation with it being a receiver, Unsafe::putXXX with it being
3514+
// the first argument, or Unsafe::finishPrivateBuffer. This allows us to aggressively scalarize
3515+
// value objects in all other places. This special case comes from the limitation of the Java
3516+
// language, Unsafe::makePrivateBuffer returns an Object that is checkcast-ed to the concrete
3517+
// value type. We must do this first because C->static_subtype_check may do nothing when
3518+
// StressReflectiveCode is set.
3519+
return obj;
3520+
}
3521+
35093522
const TypeKlassPtr* improved_klass_ptr_type = klass_ptr_type->try_improve();
35103523
const TypeOopPtr* toop = improved_klass_ptr_type->cast_to_exactness(false)->as_instance_type();
35113524
bool safe_for_replace = (failure_control == nullptr);
@@ -3519,13 +3532,13 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass, Node* *failure_contro
35193532
// for example, in some objArray manipulations, such as a[i]=a[j].)
35203533
if (improved_klass_ptr_type->singleton()) {
35213534
const TypeKlassPtr* kptr = nullptr;
3522-
const Type* t = _gvn.type(obj);
3523-
if (t->isa_oop_ptr()) {
3524-
kptr = t->is_oopptr()->as_klass_type();
3535+
if (obj_type->isa_oop_ptr()) {
3536+
kptr = obj_type->is_oopptr()->as_klass_type();
35253537
} else if (obj->is_InlineType()) {
3526-
ciInlineKlass* vk = t->inline_klass();
3538+
ciInlineKlass* vk = obj_type->inline_klass();
35273539
kptr = TypeInstKlassPtr::make(TypePtr::NotNull, vk, Type::Offset(0));
35283540
}
3541+
35293542
if (kptr != nullptr) {
35303543
switch (C->static_subtype_check(improved_klass_ptr_type, kptr)) {
35313544
case Compile::SSC_always_true:
@@ -3545,7 +3558,7 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass, Node* *failure_contro
35453558
obj = null_check(obj);
35463559
}
35473560
// It needs a null check because a null will *pass* the cast check.
3548-
if (t->isa_oopptr() != nullptr && !t->is_oopptr()->maybe_null()) {
3561+
if (obj_type->isa_oopptr() != nullptr && !obj_type->is_oopptr()->maybe_null()) {
35493562
bool is_aastore = (java_bc() == Bytecodes::_aastore);
35503563
Deoptimization::DeoptReason reason = is_aastore ?
35513564
Deoptimization::Reason_array_check : Deoptimization::Reason_class_check;

src/hotspot/share/opto/library_call.cpp

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2663,40 +2663,65 @@ bool LibraryCallKit::inline_unsafe_access(bool is_store, const BasicType type, c
26632663
bool LibraryCallKit::inline_unsafe_make_private_buffer() {
26642664
Node* receiver = argument(0);
26652665
Node* value = argument(1);
2666-
if (!value->is_InlineType()) {
2666+
2667+
const Type* type = gvn().type(value);
2668+
if (!type->is_inlinetypeptr()) {
2669+
C->record_method_not_compilable("value passed to Unsafe::makePrivateBuffer is not of a constant value type");
26672670
return false;
26682671
}
26692672

2670-
receiver = null_check(receiver);
2673+
null_check(receiver);
2674+
if (stopped()) {
2675+
return true;
2676+
}
2677+
2678+
value = null_check(value);
26712679
if (stopped()) {
26722680
return true;
26732681
}
26742682

2675-
set_result(value->as_InlineType()->make_larval(this, true));
2683+
ciInlineKlass* vk = type->inline_klass();
2684+
Node* klass = makecon(TypeKlassPtr::make(vk));
2685+
Node* obj = new_instance(klass);
2686+
AllocateNode::Ideal_allocation(obj)->_larval = true;
2687+
2688+
assert(value->is_InlineType(), "must be an InlineTypeNode");
2689+
value->as_InlineType()->store(this, obj, obj, vk);
2690+
2691+
set_result(obj);
26762692
return true;
26772693
}
26782694

26792695
bool LibraryCallKit::inline_unsafe_finish_private_buffer() {
26802696
Node* receiver = argument(0);
26812697
Node* buffer = argument(1);
2682-
if (!buffer->is_InlineType()) {
2683-
return false;
2684-
}
2685-
InlineTypeNode* vt = buffer->as_InlineType();
2686-
if (!vt->is_allocated(&_gvn)) {
2698+
2699+
const Type* type = gvn().type(buffer);
2700+
if (!type->is_inlinetypeptr()) {
2701+
C->record_method_not_compilable("value passed to Unsafe::finishPrivateBuffer is not of a constant value type");
26872702
return false;
26882703
}
2689-
// TODO 8239003 Why is this needed?
2690-
if (AllocateNode::Ideal_allocation(vt->get_oop()) == nullptr) {
2704+
2705+
AllocateNode* alloc = AllocateNode::Ideal_allocation(buffer);
2706+
if (alloc == nullptr) {
2707+
C->record_method_not_compilable("value passed to Unsafe::finishPrivateBuffer must be allocated by Unsafe::makePrivateBuffer");
26912708
return false;
26922709
}
26932710

2694-
receiver = null_check(receiver);
2711+
null_check(receiver);
26952712
if (stopped()) {
26962713
return true;
26972714
}
26982715

2699-
set_result(vt->finish_larval(this));
2716+
// Unset the larval bit in the object header
2717+
Node* old_header = make_load(control(), buffer, TypeX_X, TypeX_X->basic_type(), MemNode::unordered, LoadNode::Pinned);
2718+
Node* new_header = gvn().transform(new AndXNode(old_header, MakeConX(~markWord::larval_bit_in_place)));
2719+
access_store_at(buffer, buffer, type->is_ptr(), new_header, TypeX_X, TypeX_X->basic_type(), MO_UNORDERED | IN_HEAP);
2720+
2721+
// We must ensure that the buffer is properly published
2722+
insert_mem_bar(Op_MemBarStoreStore, alloc->proj_out(AllocateNode::RawAddress));
2723+
assert(!type->maybe_null(), "result of an allocation should not be null");
2724+
set_result(InlineTypeNode::make_from_oop(this, buffer, type->inline_klass(), false));
27002725
return true;
27012726
}
27022727

test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1697,6 +1697,28 @@ public void test83_verifier(RunInfo info) {
16971697
}
16981698
}
16991699

1700+
/*
1701+
TODO: 8335256: Properly handle merging of value object oops
1702+
@Test
1703+
@IR(failOn = {CALL_UNSAFE, ALLOC})
1704+
public MyValue1 test84(MyValue1 v) {
1705+
v = U.makePrivateBuffer(v);
1706+
for (int i = 0; i < 10; i++) {
1707+
U.putInt(v, X_OFFSET, i);
1708+
}
1709+
U.putInt(v, X_OFFSET, rI);
1710+
v = U.finishPrivateBuffer(v);
1711+
return v;
1712+
}
1713+
1714+
@Run(test = "test84")
1715+
public void test84_verifier() {
1716+
MyValue1 v1 = MyValue1.createWithFieldsInline(rI, rL);
1717+
MyValue1 v2 = test84(MyValue1.setX(v1, 0));
1718+
Asserts.assertEQ(v1.hash(), v2.hash());
1719+
}
1720+
*/
1721+
17001722
static value class MyValueClonable implements Cloneable {
17011723
int x;
17021724

0 commit comments

Comments
 (0)