Skip to content
Closed
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
36 changes: 16 additions & 20 deletions src/hotspot/share/opto/memnode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,37 +214,33 @@ static bool call_can_modify_local_object(ciField* field, CallNode* call) {

Node* MemNode::optimize_simple_memory_chain(Node* mchain, const TypeOopPtr* t_oop, Node* load, PhaseGVN* phase) {
assert(t_oop != nullptr, "sanity");
bool is_instance = t_oop->is_known_instance_field();

ciField* field = phase->C->alias_type(t_oop)->field();
bool is_known_instance = t_oop->is_known_instance_field();
bool is_strict_final_load = false;

// After macro expansion, an allocation may become a call, changing the memory input to the
// memory output of that call would be illegal. As a result, disallow this transformation after
// macro expansion.
if (phase->is_IterGVN() && phase->C->allow_macro_nodes() && load != nullptr && load->is_Load() && !load->as_Load()->is_mismatched_access()) {
if (EnableValhalla) {
if (field != nullptr && (field->holder()->is_inlinetype() || field->holder()->is_abstract_value_klass())) {
is_strict_final_load = true;
}
is_strict_final_load = t_oop->is_ptr_to_strict_final_field();
#ifdef ASSERT
if (t_oop->is_inlinetypeptr() && t_oop->inline_klass()->contains_field_offset(t_oop->offset())) {
assert(is_strict_final_load, "sanity check for basic cases");
}
#endif
} else {
is_strict_final_load = field != nullptr && t_oop->is_ptr_to_boxed_value();
if ((t_oop->is_inlinetypeptr() && t_oop->inline_klass()->contains_field_offset(t_oop->offset())) || t_oop->is_ptr_to_boxed_value()) {
assert(is_strict_final_load, "sanity check for basic cases");
}
#endif // ASSERT
}

if (!is_instance && !is_strict_final_load) {
if (!is_known_instance && !is_strict_final_load) {
return mchain;
}

Node* result = mchain;
ProjNode* base_local = nullptr;

ciField* field = nullptr;
if (is_strict_final_load) {
field = phase->C->alias_type(t_oop)->field();
assert(field != nullptr, "must point to a field");

Node* adr = load->in(MemNode::Address);
assert(phase->type(adr) == t_oop, "inconsistent type");
Node* tmp = try_optimize_strict_final_load_memory(phase, adr, base_local);
Expand Down Expand Up @@ -284,7 +280,7 @@ Node* MemNode::optimize_simple_memory_chain(Node* mchain, const TypeOopPtr* t_oo
if ((alloc == nullptr) || (alloc->_idx == instance_id)) {
break;
}
if (is_instance) {
if (is_known_instance) {
result = proj_in->in(TypeFunc::Memory);
} else if (is_strict_final_load) {
Node* klass = alloc->in(AllocateNode::KlassNode);
Expand All @@ -309,7 +305,7 @@ Node* MemNode::optimize_simple_memory_chain(Node* mchain, const TypeOopPtr* t_oo
assert(false, "unexpected projection");
}
} else if (result->is_ClearArray()) {
if (!is_instance || !ClearArrayNode::step_through(&result, instance_id, phase)) {
if (!is_known_instance || !ClearArrayNode::step_through(&result, instance_id, phase)) {
// Can not bypass initialization of the instance
// we are looking for.
break;
Expand Down Expand Up @@ -1406,9 +1402,9 @@ bool LoadNode::is_instance_field_load_with_local_phi(Node* ctrl) {
if( in(Memory)->is_Phi() && in(Memory)->in(0) == ctrl &&
in(Address)->is_AddP() ) {
const TypeOopPtr* t_oop = in(Address)->bottom_type()->isa_oopptr();
// Only instances and boxed values.
// Only known instances and immutable fields
if( t_oop != nullptr &&
(t_oop->is_ptr_to_boxed_value() ||
(t_oop->is_ptr_to_strict_final_field() ||
t_oop->is_known_instance_field()) &&
t_oop->offset() != Type::OffsetBot &&
t_oop->offset() != Type::OffsetTop) {
Expand Down Expand Up @@ -1457,8 +1453,8 @@ Node* LoadNode::Identity(PhaseGVN* phase) {
int this_offset = addr_t->offset();
int this_iid = addr_t->instance_id();
if (!addr_t->is_known_instance() &&
addr_t->is_ptr_to_boxed_value()) {
// Use _idx of address base (could be Phi node) for boxed values.
addr_t->is_ptr_to_strict_final_field()) {
// Use _idx of address base (could be Phi node) for immutable fields in unknown instances
intptr_t ignore = 0;
Node* base = AddPNode::Ideal_base_and_offset(in(Address), phase, ignore);
if (base == nullptr) {
Expand Down
13 changes: 12 additions & 1 deletion src/hotspot/share/opto/type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3575,6 +3575,7 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const TypeInterfaces* inter
_is_ptr_to_narrowoop(false),
_is_ptr_to_narrowklass(false),
_is_ptr_to_boxed_value(false),
_is_ptr_to_strict_final_field(false),
_instance_id(instance_id) {
#ifdef ASSERT
if (klass() != nullptr && klass()->is_loaded()) {
Expand All @@ -3584,7 +3585,17 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const TypeInterfaces* inter
if (Compile::current()->eliminate_boxing() && (t == InstPtr) &&
(offset.get() > 0) && xk && (k != nullptr) && k->is_instance_klass()) {
_is_ptr_to_boxed_value = k->as_instance_klass()->is_boxed_value_offset(offset.get());
_is_ptr_to_strict_final_field = _is_ptr_to_boxed_value;
}

if (klass() != nullptr && klass()->is_instance_klass() && klass()->is_loaded() &&
this->offset() != Type::OffsetBot && this->offset() != Type::OffsetTop) {
ciField* field = klass()->as_instance_klass()->get_field_by_offset(this->offset(), false);
if (field != nullptr && field->is_strict() && field->is_final()) {
_is_ptr_to_strict_final_field = true;
}
}

#ifdef _LP64
if (this->offset() > 0 || this->offset() == Type::OffsetTop || this->offset() == Type::OffsetBot) {
if (this->offset() == oopDesc::klass_offset_in_bytes()) {
Expand Down Expand Up @@ -3658,7 +3669,7 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const TypeInterfaces* inter
}
}
}
#endif
#endif // _LP64
}

//------------------------------make-------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/share/opto/type.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@
#include "opto/adlcVMDeps.hpp"
#include "opto/compile.hpp"
#include "opto/rangeinference.hpp"
#include "runtime/handles.hpp"
#include "runtime/sharedRuntime.hpp"

// Portions of code courtesy of Clifford Click

Expand Down Expand Up @@ -1395,6 +1393,7 @@ class TypeOopPtr : public TypePtr {
bool _is_ptr_to_narrowoop;
bool _is_ptr_to_narrowklass;
bool _is_ptr_to_boxed_value;
bool _is_ptr_to_strict_final_field;

// If not InstanceTop or InstanceBot, indicates that this is
// a particular instance of this type which is distinct.
Expand Down Expand Up @@ -1476,6 +1475,7 @@ class TypeOopPtr : public TypePtr {
bool is_ptr_to_narrowoop_nv() const { return _is_ptr_to_narrowoop; }
bool is_ptr_to_narrowklass_nv() const { return _is_ptr_to_narrowklass; }
bool is_ptr_to_boxed_value() const { return _is_ptr_to_boxed_value; }
bool is_ptr_to_strict_final_field() const { return _is_ptr_to_strict_final_field; }
bool is_known_instance() const { return _instance_id > 0; }
int instance_id() const { return _instance_id; }
bool is_known_instance_field() const { return is_known_instance() && _offset.get() >= 0; }
Expand Down