< prev index next >
src/share/vm/opto/valuetypenode.cpp
Print this page
@@ -1,7 +1,7 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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.
@@ -37,10 +37,11 @@
assert(!has_phi_inputs(region), "already cloned with phis");
ValueTypeBaseNode* vt = clone()->as_ValueTypeBase();
// Create a PhiNode for merging the oop values
const TypeValueTypePtr* vtptr = value_type_ptr();
+ vtptr = vtptr->cast_to_ptr_type(TypePtr::BotPTR)->is_valuetypeptr();
PhiNode* oop = PhiNode::make(region, vt->get_oop(), vtptr);
gvn->set_type(oop, vtptr);
vt->set_oop(oop);
// Create a PhiNode each for merging the field values
@@ -121,15 +122,21 @@
// If the field at 'offset' belongs to a flattened value type field, 'index' refers to the
// corresponding ValueTypeNode input and 'sub_offset' is the offset in flattened value type.
int index = value_klass()->field_index_by_offset(offset);
int sub_offset = offset - field_offset(index);
Node* value = field_value(index);
+ assert(value != NULL, "field value not found");
if (recursive && value->is_ValueType()) {
- // Flattened value type field
ValueTypeNode* vt = value->as_ValueType();
+ if (field_is_flattened(index)) {
+ // Flattened value type field
sub_offset += vt->value_klass()->first_field_offset(); // Add header size
- return vt->field_value_by_offset(sub_offset);
+ return vt->field_value_by_offset(sub_offset, recursive);
+ } else {
+ assert(sub_offset == 0, "should not have a sub offset");
+ return vt;
+ }
}
assert(!(recursive && value->is_ValueType()), "should not be a value type");
assert(sub_offset == 0, "offset mismatch");
return value;
}
@@ -139,21 +146,26 @@
set_req(Values + index, value);
}
int ValueTypeBaseNode::field_offset(uint index) const {
assert(index < field_count(), "index out of bounds");
- return value_klass()->field_offset_by_index(index);
+ return value_klass()->declared_nonstatic_field_at(index)->offset();
}
ciType* ValueTypeBaseNode::field_type(uint index) const {
assert(index < field_count(), "index out of bounds");
- return value_klass()->field_type_by_index(index);
+ return value_klass()->declared_nonstatic_field_at(index)->type();
}
-int ValueTypeBaseNode::make_scalar_in_safepoint(SafePointNode* sfpt, Node* root, PhaseGVN* gvn) {
+bool ValueTypeBaseNode::field_is_flattened(uint index) const {
+ assert(index < field_count(), "index out of bounds");
+ return value_klass()->declared_nonstatic_field_at(index)->is_flattened();
+}
+
+int ValueTypeBaseNode::make_scalar_in_safepoint(Unique_Node_List& worklist, SafePointNode* sfpt, Node* root, PhaseGVN* gvn) {
ciValueKlass* vk = value_klass();
- uint nfields = vk->flattened_field_count();
+ uint nfields = vk->nof_nonstatic_fields();
JVMState* jvms = sfpt->jvms();
int start = jvms->debug_start();
int end = jvms->debug_end();
// Replace safepoint edge by SafePointScalarObjectNode and add field values
assert(jvms != NULL, "missing JVMS");
@@ -168,11 +180,18 @@
// Iterate over the value type fields in order of increasing
// offset and add the field values to the safepoint.
for (uint j = 0; j < nfields; ++j) {
int offset = vk->nonstatic_field_at(j)->offset();
Node* value = field_value_by_offset(offset, true /* include flattened value type fields */);
- assert(value != NULL, "");
+ if (value->is_ValueType()) {
+ if (value->as_ValueType()->is_allocated(gvn)) {
+ value = value->as_ValueType()->get_oop();
+ } else {
+ // Add non-flattened value type field to the worklist to process later
+ worklist.push(value);
+ }
+ }
sfpt->add_req(value);
}
jvms->set_endoff(sfpt->req());
if (gvn != NULL) {
sobj = gvn->transform(sobj)->as_SafePointScalarObject();
@@ -180,32 +199,38 @@
}
return sfpt->replace_edges_in_range(this, sobj, start, end);
}
void ValueTypeBaseNode::make_scalar_in_safepoints(Node* root, PhaseGVN* gvn) {
+ Unique_Node_List worklist;
for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) {
Node* u = fast_out(i);
if (u->is_SafePoint() && (!u->is_Call() || u->as_Call()->has_debug_use(this))) {
SafePointNode* sfpt = u->as_SafePoint();
Node* in_oop = get_oop();
const Type* oop_type = in_oop->bottom_type();
- assert(Opcode() == Op_ValueTypePtr || TypePtr::NULL_PTR->higher_equal(oop_type), "already heap allocated value type should be linked directly");
- int nb = make_scalar_in_safepoint(sfpt, root, gvn);
+ assert(Opcode() == Op_ValueTypePtr || !isa_ValueType()->is_allocated(gvn), "already heap allocated value types should be linked directly");
+ int nb = make_scalar_in_safepoint(worklist, sfpt, root, gvn);
--i; imax -= nb;
}
}
+
+ for (uint next = 0; next < worklist.size(); ++next) {
+ Node* vt = worklist.at(next);
+ vt->as_ValueType()->make_scalar_in_safepoints(root, gvn);
+ }
}
-void ValueTypeBaseNode::make(PhaseGVN* gvn, Node* n, ValueTypeBaseNode* vt, ciValueKlass* base_vk, int base_offset, int base_input, bool in) {
+void ValueTypeBaseNode::make(PhaseGVN* gvn, Node*& ctl, Node* mem, Node* n, ValueTypeBaseNode* vt, ciValueKlass* base_vk, int base_offset, int base_input, bool in) {
assert(base_offset >= 0, "offset in value type always positive");
for (uint i = 0; i < vt->field_count(); i++) {
ciType* field_type = vt->field_type(i);
int offset = base_offset + vt->field_offset(i);
- if (field_type->is_valuetype()) {
+ if (field_type->is_valuetype() && vt->field_is_flattened(i)) {
ciValueKlass* embedded_vk = field_type->as_value_klass();
ValueTypeNode* embedded_vt = ValueTypeNode::make(*gvn, embedded_vk);
- ValueTypeBaseNode::make(gvn, n, embedded_vt, base_vk, offset - vt->value_klass()->first_field_offset(), base_input, in);
+ ValueTypeBaseNode::make(gvn, ctl, mem, n, embedded_vt, base_vk, offset - vt->value_klass()->first_field_offset(), base_input, in);
vt->set_field_value(i, gvn->transform(embedded_vt));
} else {
int j = 0; int extra = 0;
for (; j < base_vk->nof_nonstatic_fields(); j++) {
ciField* f = base_vk->nonstatic_field_at(j);
@@ -229,27 +254,32 @@
parm = n->in(base_input + j + extra);
} else {
parm = gvn->transform(new ProjNode(n->as_Call(), base_input + j + extra));
}
}
+ if (field_type->is_valuetype()) {
+ // Non-flattened value type field, check for null
+ parm = ValueTypeNode::make(*gvn, ctl, mem, parm, /* null_check */ true);
+
+ }
vt->set_field_value(i, parm);
// Record all these guys for later GVN.
gvn->record_for_igvn(parm);
}
}
}
-void ValueTypeBaseNode::load(PhaseGVN& gvn, Node* mem, Node* base, Node* ptr, ciInstanceKlass* holder, int holder_offset) {
+void ValueTypeBaseNode::load(PhaseGVN& gvn, Node*& ctl, Node* mem, Node* base, Node* ptr, ciInstanceKlass* holder, int holder_offset) {
// Initialize the value type by loading its field values from
// memory and adding the values as input edges to the node.
for (uint i = 0; i < field_count(); ++i) {
int offset = holder_offset + field_offset(i);
ciType* ftype = field_type(i);
Node* value = NULL;
- if (ftype->is_valuetype()) {
+ if (ftype->is_valuetype() && field_is_flattened(i)) {
// Recursively load the flattened value type field
- value = ValueTypeNode::make(gvn, ftype->as_value_klass(), mem, base, ptr, holder, offset);
+ value = ValueTypeNode::make(gvn, ftype->as_value_klass(), ctl, mem, base, ptr, holder, offset);
} else {
const Type* con_type = NULL;
if (base->is_Con()) {
// If the oop to the value type is constant (static final field), we can
// also treat the fields as constants because the value type is immutable.
@@ -259,77 +289,160 @@
ciConstant constant = constant_oop->as_instance()->field_value(field);
con_type = Type::make_from_constant(constant, /*require_const=*/ true);
}
if (con_type != NULL) {
// Found a constant field value
- value = gvn.makecon(con_type);
+ value = gvn.transform(gvn.makecon(con_type));
+ if (con_type->isa_valuetypeptr()) {
+ // Constant, non-flattened value type field
+ value = ValueTypeNode::make(gvn, ctl, mem, value);
+ }
} else {
// Load field value from memory
const Type* base_type = gvn.type(base);
const TypePtr* adr_type = NULL;
if (base_type->isa_aryptr()) {
- // In the case of a flattened value type array, each field
- // has its own slice
+ // In the case of a flattened value type array, each field has its own slice
adr_type = base_type->is_aryptr()->with_field_offset(offset)->add_offset(Type::OffsetBot);
} else {
ciField* field = holder->get_field_by_offset(offset, false);
adr_type = gvn.C->alias_type(field)->adr_type();
}
Node* adr = gvn.transform(new AddPNode(base, ptr, gvn.MakeConX(offset)));
BasicType bt = type2field[ftype->basic_type()];
- value = LoadNode::make(gvn, NULL, mem, adr, adr_type, Type::get_const_type(ftype), bt, MemNode::unordered);
+ const Type* ft = Type::get_const_type(ftype);
+ if (bt == T_VALUETYPE) {
+ ft = ft->is_valuetypeptr()->cast_to_ptr_type(TypePtr::BotPTR);
+ }
+ assert(is_java_primitive(bt) || adr->bottom_type()->is_ptr_to_narrowoop() == UseCompressedOops, "inconsistent");
+ value = gvn.transform(LoadNode::make(gvn, NULL, mem, adr, adr_type, ft, bt, MemNode::unordered));
+ if (bt == T_VALUETYPE) {
+ // Non-flattened value type field, check for null
+ value = ValueTypeNode::make(gvn, ctl, mem, value, /* null_check */ true);
+ }
}
}
- set_field_value(i, gvn.transform(value));
+ set_field_value(i, value);
}
}
-void ValueTypeBaseNode::store_flattened(PhaseGVN* gvn, Node* ctl, MergeMemNode* mem, Node* base, ciValueKlass* holder, int holder_offset) const {
+void ValueTypeBaseNode::store_flattened(GraphKit* kit, Node* base, Node* ptr, ciInstanceKlass* holder, int holder_offset) const {
// The value type is embedded into the object without an oop header. Subtract the
// offset of the first field to account for the missing header when storing the values.
holder_offset -= value_klass()->first_field_offset();
- store(gvn, ctl, mem, base, holder, holder_offset);
+ store(kit, base, ptr, holder, holder_offset);
}
-void ValueTypeBaseNode::store(PhaseGVN* gvn, Node* ctl, MergeMemNode* mem, Node* base, ciValueKlass* holder, int holder_offset) const {
+void ValueTypeBaseNode::store(GraphKit* kit, Node* base, Node* ptr, ciInstanceKlass* holder, int holder_offset) const {
if (holder == NULL) {
holder = value_klass();
}
// Write field values to memory
for (uint i = 0; i < field_count(); ++i) {
int offset = holder_offset + field_offset(i);
Node* value = field_value(i);
- if (value->is_ValueType()) {
+ if (value->is_ValueType() && field_is_flattened(i)) {
// Recursively store the flattened value type field
- value->isa_ValueTypeBase()->store_flattened(gvn, ctl, mem, base, holder, offset);
+ value->isa_ValueType()->store_flattened(kit, base, ptr, holder, offset);
} else {
- const Type* base_type = gvn->type(base);
+ const Type* base_type = kit->gvn().type(base);
const TypePtr* adr_type = NULL;
if (base_type->isa_aryptr()) {
// In the case of a flattened value type array, each field has its own slice
adr_type = base_type->is_aryptr()->with_field_offset(offset)->add_offset(Type::OffsetBot);
} else {
ciField* field = holder->get_field_by_offset(offset, false);
- adr_type = gvn->C->alias_type(field)->adr_type();
+ adr_type = kit->C->alias_type(field)->adr_type();
}
- Node* adr = gvn->transform(new AddPNode(base, base, gvn->MakeConX(offset)));
+ Node* adr = kit->basic_plus_adr(base, ptr, offset);
BasicType bt = type2field[field_type(i)->basic_type()];
- uint alias_idx = gvn->C->get_alias_index(adr_type);
- Node* st = StoreNode::make(*gvn, ctl, mem->memory_at(alias_idx), adr, adr_type, value, bt, MemNode::unordered);
- mem->set_memory_at(alias_idx, gvn->transform(st));
+ if (is_java_primitive(bt)) {
+ kit->store_to_memory(kit->control(), adr, value, bt, adr_type, MemNode::unordered);
+ } else {
+ const TypeOopPtr* ft = TypeOopPtr::make_from_klass(field_type(i)->as_klass());
+ // Field may be NULL
+ ft = ft->cast_to_ptr_type(TypePtr::BotPTR)->is_oopptr();
+ assert(adr->bottom_type()->is_ptr_to_narrowoop() == UseCompressedOops, "inconsistent");
+ bool is_array = base_type->isa_aryptr() != NULL;
+ kit->store_oop(kit->control(), base, adr, adr_type, value, ft, bt, is_array, MemNode::unordered);
+ }
+ }
}
+}
+
+ValueTypeBaseNode* ValueTypeBaseNode::allocate(GraphKit* kit) {
+ Node* in_oop = get_oop();
+ Node* null_ctl = kit->top();
+ // Check if value type is already allocated
+ Node* not_null_oop = kit->null_check_oop(in_oop, &null_ctl);
+ if (null_ctl->is_top()) {
+ // Value type is allocated
+ return this;
+ }
+ // Not able to prove that value type is allocated.
+ // Emit runtime check that may be folded later.
+ assert(!is_allocated(&kit->gvn()), "should not be allocated");
+ const TypeValueTypePtr* vtptr_type = bottom_type()->isa_valuetypeptr();
+ if (vtptr_type == NULL) {
+ vtptr_type = TypeValueTypePtr::make(bottom_type()->isa_valuetype(), TypePtr::NotNull);
}
+ RegionNode* region = new RegionNode(3);
+ PhiNode* oop = new PhiNode(region, vtptr_type);
+ PhiNode* io = new PhiNode(region, Type::ABIO);
+ PhiNode* mem = new PhiNode(region, Type::MEMORY, TypePtr::BOTTOM);
+
+ // Oop is non-NULL, use it
+ region->init_req(1, kit->control());
+ oop ->init_req(1, not_null_oop);
+ io ->init_req(1, kit->i_o());
+ mem ->init_req(1, kit->merged_memory());
+
+ // Oop is NULL, allocate value type
+ kit->set_control(null_ctl);
+ kit->kill_dead_locals();
+ ciValueKlass* vk = value_klass();
+ Node* klass_node = kit->makecon(TypeKlassPtr::make(vk));
+ Node* alloc_oop = kit->new_instance(klass_node, NULL, NULL, false, this);
+ // Write field values to memory
+ store(kit, alloc_oop, alloc_oop, vk);
+ region->init_req(2, kit->control());
+ oop ->init_req(2, alloc_oop);
+ io ->init_req(2, kit->i_o());
+ mem ->init_req(2, kit->merged_memory());
+
+ // Update GraphKit
+ kit->set_control(kit->gvn().transform(region));
+ kit->set_i_o(kit->gvn().transform(io));
+ kit->set_all_memory(kit->gvn().transform(mem));
+ kit->record_for_igvn(region);
+ kit->record_for_igvn(oop);
+ kit->record_for_igvn(io);
+ kit->record_for_igvn(mem);
+
+ // Use cloned ValueTypeNode to propagate oop from now on
+ Node* res_oop = kit->gvn().transform(oop);
+ ValueTypeBaseNode* vt = clone()->as_ValueTypeBase();
+ vt->set_oop(res_oop);
+ vt = kit->gvn().transform(vt)->as_ValueTypeBase();
+ kit->replace_in_map(this, vt);
+ return vt;
+}
+
+bool ValueTypeBaseNode::is_allocated(PhaseGVN* phase) const {
+ Node* oop = get_oop();
+ const Type* oop_type = (phase != NULL) ? phase->type(oop) : oop->bottom_type();
+ return oop_type->meet(TypePtr::NULL_PTR) != oop_type;
}
// When a call returns multiple values, it has several result
// projections, one per field. Replacing the result of the call by a
// value type node (after late inlining) requires that for each result
// projection, we find the corresponding value type field.
-void ValueTypeBaseNode::replace_call_results(Node* call, Compile* C) {
+void ValueTypeBaseNode::replace_call_results(GraphKit* kit, Node* call, Compile* C) {
ciValueKlass* vk = value_klass();
for (DUIterator_Fast imax, i = call->fast_outs(imax); i < imax; i++) {
- ProjNode *pn = call->fast_out(i)->as_Proj();
+ ProjNode* pn = call->fast_out(i)->as_Proj();
uint con = pn->_con;
if (con >= TypeFunc::Parms+1) {
uint field_nb = con - (TypeFunc::Parms+1);
int extra = 0;
for (uint j = 0; j < field_nb - extra; j++) {
@@ -339,92 +452,22 @@
extra++;
}
}
ciField* f = vk->nonstatic_field_at(field_nb - extra);
Node* field = field_value_by_offset(f->offset(), true);
-
+ if (field->is_ValueType()) {
+ assert(f->is_flattened(), "should be flattened");
+ field = field->as_ValueType()->allocate(kit)->get_oop();
+ }
C->gvn_replace_by(pn, field);
C->initial_gvn()->hash_delete(pn);
pn->set_req(0, C->top());
--i; --imax;
}
}
}
-Node* ValueTypeBaseNode::allocate(const Type* type, Node*& ctl, Node*& mem, Node*& io, Node* frameptr, Node*& ex_ctl, Node*& ex_mem, Node*& ex_io, JVMState* jvms, PhaseIterGVN *igvn) {
- ciValueKlass* vk = type->is_valuetypeptr()->value_type()->value_klass();
- Node* initial_mem = mem;
- uint last = igvn->C->unique();
- MergeMemNode* all_mem = MergeMemNode::make(mem);
- jint lhelper = vk->layout_helper();
- assert(lhelper != Klass::_lh_neutral_value, "unsupported");
-
- AllocateNode* alloc = new AllocateNode(igvn->C,
- AllocateNode::alloc_type(Type::TOP),
- ctl,
- mem,
- io,
- igvn->MakeConX(Klass::layout_helper_size_in_bytes(lhelper)),
- igvn->makecon(TypeKlassPtr::make(vk)),
- igvn->intcon(0),
- NULL);
- alloc->set_req(TypeFunc::FramePtr, frameptr);
- igvn->C->add_safepoint_edges(alloc, jvms);
- Node* n = igvn->transform(alloc);
- assert(n == alloc, "node shouldn't go away");
-
- ctl = igvn->transform(new ProjNode(alloc, TypeFunc::Control));
- mem = igvn->transform(new ProjNode(alloc, TypeFunc::Memory, true));
- all_mem->set_memory_at(Compile::AliasIdxRaw, mem);
-
- io = igvn->transform(new ProjNode(alloc, TypeFunc::I_O, true));
- Node* catc = igvn->transform(new CatchNode(ctl, io, 2));
- Node* norm = igvn->transform(new CatchProjNode(catc, CatchProjNode::fall_through_index, CatchProjNode::no_handler_bci));
- Node* excp = igvn->transform(new CatchProjNode(catc, CatchProjNode::catch_all_index, CatchProjNode::no_handler_bci));
-
- ex_ctl = excp;
- ex_mem = igvn->transform(all_mem);
- ex_io = io;
-
- ctl = norm;
- mem = igvn->transform(new ProjNode(alloc, TypeFunc::Memory));
- io = igvn->transform(new ProjNode(alloc, TypeFunc::I_O, false));
- Node* rawoop = igvn->transform(new ProjNode(alloc, TypeFunc::Parms));
-
- MemBarNode* membar = MemBarNode::make(igvn->C, Op_Initialize, Compile::AliasIdxRaw, rawoop);
- membar->set_req(TypeFunc::Control, ctl);
-
- InitializeNode* init = membar->as_Initialize();
-
- const TypeOopPtr* oop_type = type->is_oopptr();
- MergeMemNode* minit_in = MergeMemNode::make(mem);
- init->set_req(InitializeNode::Memory, minit_in);
- n = igvn->transform(membar);
- assert(n == membar, "node shouldn't go away");
- ctl = igvn->transform(new ProjNode(membar, TypeFunc::Control));
- mem = igvn->transform(new ProjNode(membar, TypeFunc::Memory));
-
- MergeMemNode* out_mem_merge = MergeMemNode::make(initial_mem);
- for (int i = 0, len = vk->nof_nonstatic_fields(); i < len; i++) {
- ciField* field = vk->nonstatic_field_at(i);
- if (field->offset() >= TrackedInitializationLimit * HeapWordSize)
- continue;
- int fieldidx = igvn->C->alias_type(field)->index();
- minit_in->set_memory_at(fieldidx, initial_mem);
- out_mem_merge->set_memory_at(fieldidx, mem);
- }
-
- n = igvn->transform(minit_in);
- assert(n == minit_in, "node shouldn't go away");
- out_mem_merge->set_memory_at(Compile::AliasIdxRaw, mem);
-
- Node* javaoop = igvn->transform(new CheckCastPPNode(ctl, rawoop, oop_type));
- mem = igvn->transform(out_mem_merge);
-
- return javaoop;
-}
-
ValueTypeNode* ValueTypeNode::make(PhaseGVN& gvn, ciValueKlass* klass) {
// Create a new ValueTypeNode with uninitialized values and NULL oop
const TypeValueType* type = TypeValueType::make(klass);
return new ValueTypeNode(type, gvn.zerocon(T_VALUETYPE));
}
@@ -444,42 +487,86 @@
vt->set_field_value(i, value);
}
return gvn.transform(vt);
}
-Node* ValueTypeNode::make(PhaseGVN& gvn, Node* mem, Node* oop) {
+Node* ValueTypeNode::make(PhaseGVN& gvn, Node*& ctl, Node* mem, Node* oop, bool null_check) {
// Create and initialize a ValueTypeNode by loading all field
// values from a heap-allocated version and also save the oop.
const TypeValueType* type = gvn.type(oop)->is_valuetypeptr()->value_type();
ValueTypeNode* vt = new ValueTypeNode(type, oop);
- vt->load(gvn, mem, oop, oop, type->value_klass());
+
+ if (null_check && !vt->is_allocated(&gvn)) {
+ // Add oop null check
+ Node* chk = gvn.transform(new CmpPNode(oop, gvn.zerocon(T_VALUETYPE)));
+ Node* tst = gvn.transform(new BoolNode(chk, BoolTest::ne));
+ IfNode* iff = gvn.transform(new IfNode(ctl, tst, PROB_MAX, COUNT_UNKNOWN))->as_If();
+ Node* not_null = gvn.transform(new IfTrueNode(iff));
+ Node* null = gvn.transform(new IfFalseNode(iff));
+ Node* region = new RegionNode(3);
+
+ // Load value type from memory if oop is non-null
+ oop = new CastPPNode(oop, TypePtr::NOTNULL);
+ oop->set_req(0, not_null);
+ oop = gvn.transform(oop);
+ vt->load(gvn, not_null, mem, oop, oop, type->value_klass());
+ region->init_req(1, not_null);
+
+ // Use default value type if oop is null
+ Node* def = make_default(gvn, type->value_klass());
+ region->init_req(2, null);
+
+ // Merge the two value types and update control
+ vt = vt->clone_with_phis(&gvn, region)->as_ValueType();
+ vt->merge_with(&gvn, def->as_ValueType(), 2, true);
+ ctl = gvn.transform(region);
+ } else {
+ Node* init_ctl = ctl;
+ vt->load(gvn, ctl, mem, oop, oop, type->value_klass());
+ vt = gvn.transform(vt)->as_ValueType();
assert(vt->is_allocated(&gvn), "value type should be allocated");
- assert(oop->is_Con() || oop->is_CheckCastPP() || oop->Opcode() == Op_ValueTypePtr || vt->is_loaded(&gvn, type) == oop, "value type should be loaded");
- return gvn.transform(vt);
+ assert(init_ctl != ctl || oop->is_Con() || oop->is_CheckCastPP() || oop->Opcode() == Op_ValueTypePtr ||
+ vt->is_loaded(&gvn, type) == oop, "value type should be loaded");
+ }
+ return vt;
}
-Node* ValueTypeNode::make(PhaseGVN& gvn, ciValueKlass* vk, Node* mem, Node* obj, Node* ptr, ciInstanceKlass* holder, int holder_offset) {
+Node* ValueTypeNode::make(GraphKit* kit, Node* oop, bool null_check) {
+ Node* ctl = kit->control();
+ Node* vt = make(kit->gvn(), ctl, kit->merged_memory(), oop, null_check);
+ kit->set_control(ctl);
+ return vt;
+}
+
+Node* ValueTypeNode::make(PhaseGVN& gvn, ciValueKlass* vk, Node*& ctl, Node* mem, Node* obj, Node* ptr, ciInstanceKlass* holder, int holder_offset) {
// Create and initialize a ValueTypeNode by loading all field values from
// a flattened value type field at 'holder_offset' or from a value type array.
ValueTypeNode* vt = make(gvn, vk);
// The value type is flattened into the object without an oop header. Subtract the
// offset of the first field to account for the missing header when loading the values.
holder_offset -= vk->first_field_offset();
- vt->load(gvn, mem, obj, ptr, holder, holder_offset);
+ vt->load(gvn, ctl, mem, obj, ptr, holder, holder_offset);
assert(vt->is_loaded(&gvn, vt->type()->isa_valuetype()) != obj, "holder oop should not be used as flattened value type oop");
return gvn.transform(vt)->as_ValueType();
}
-Node* ValueTypeNode::make(PhaseGVN& gvn, Node* n, ciValueKlass* vk, int base_input, bool in) {
+Node* ValueTypeNode::make(GraphKit* kit, ciValueKlass* vk, Node* obj, Node* ptr, ciInstanceKlass* holder, int holder_offset) {
+ Node* ctl = kit->control();
+ Node* vt = make(kit->gvn(), vk, ctl, kit->merged_memory(), obj, ptr, holder, holder_offset);
+ kit->set_control(ctl);
+ return vt;
+}
+
+Node* ValueTypeNode::make(PhaseGVN& gvn, Node*& ctl, Node* mem, Node* n, ciValueKlass* vk, int base_input, bool in) {
ValueTypeNode* vt = ValueTypeNode::make(gvn, vk);
- ValueTypeBaseNode::make(&gvn, n, vt, vk, 0, base_input, in);
+ ValueTypeBaseNode::make(&gvn, ctl, mem, n, vt, vk, 0, base_input, in);
return gvn.transform(vt);
}
Node* ValueTypeNode::is_loaded(PhaseGVN* phase, const TypeValueType* t, Node* base, int holder_offset) {
if (field_count() == 0) {
- assert(t->value_klass() == phase->C->env()->___Value_klass(), "unexpected value type klass");
+ assert(t->value_klass()->is__Value(), "unexpected value type klass");
assert(is_allocated(phase), "must be allocated");
return get_oop();
}
for (uint i = 0; i < field_count(); ++i) {
int offset = holder_offset + field_offset(i);
@@ -514,106 +601,27 @@
}
}
return base;
}
-void ValueTypeNode::store_flattened(GraphKit* kit, Node* base, Node* ptr, ciInstanceKlass* holder, int holder_offset) const {
- // The value type is embedded into the object without an oop header. Subtract the
- // offset of the first field to account for the missing header when storing the values.
- holder_offset -= value_klass()->first_field_offset();
- store(kit, base, ptr, holder, holder_offset);
-}
-
-void ValueTypeNode::store(GraphKit* kit, Node* base, Node* ptr, ciInstanceKlass* holder, int holder_offset) const {
- // Write field values to memory
- for (uint i = 0; i < field_count(); ++i) {
- int offset = holder_offset + field_offset(i);
+Node* ValueTypeNode::allocate_fields(GraphKit* kit) {
+ ValueTypeNode* vt = clone()->as_ValueType();
+ for (uint i = 0; i < field_count(); i++) {
Node* value = field_value(i);
if (value->is_ValueType()) {
- // Recursively store the flattened value type field
- value->isa_ValueType()->store_flattened(kit, base, ptr, holder, offset);
+ if (field_is_flattened(i)) {
+ value = value->as_ValueType()->allocate_fields(kit);
} else {
- const Type* base_type = kit->gvn().type(base);
- const TypePtr* adr_type = NULL;
- if (base_type->isa_aryptr()) {
- // In the case of a flattened value type array, each field has its own slice
- adr_type = base_type->is_aryptr()->with_field_offset(offset)->add_offset(Type::OffsetBot);
- } else {
- ciField* field = holder->get_field_by_offset(offset, false);
- adr_type = kit->C->alias_type(field)->adr_type();
- }
- Node* adr = kit->basic_plus_adr(base, ptr, offset);
- BasicType bt = type2field[field_type(i)->basic_type()];
- if (is_java_primitive(bt)) {
- kit->store_to_memory(kit->control(), adr, value, bt, adr_type, MemNode::unordered);
- } else {
- const TypeOopPtr* ft = TypeOopPtr::make_from_klass(field_type(i)->as_klass());
- assert(adr->bottom_type()->is_ptr_to_narrowoop() == UseCompressedOops, "inconsistent");
- bool is_array = base_type->isa_aryptr() != NULL;
- kit->store_oop(kit->control(), base, adr, adr_type, value, ft, bt, is_array, MemNode::unordered);
- }
+ // Non-flattened value type field
+ value = value->as_ValueType()->allocate(kit);
}
+ vt->set_field_value(i, value);
}
-}
-
-Node* ValueTypeNode::allocate(GraphKit* kit) {
- Node* in_oop = get_oop();
- Node* null_ctl = kit->top();
- // Check if value type is already allocated
- Node* not_null_oop = kit->null_check_oop(in_oop, &null_ctl);
- if (null_ctl->is_top()) {
- // Value type is allocated
- return not_null_oop;
}
- // Not able to prove that value type is allocated.
- // Emit runtime check that may be folded later.
- assert(!is_allocated(&kit->gvn()), "should not be allocated");
- const TypeValueTypePtr* vtptr_type = TypeValueTypePtr::make(bottom_type()->isa_valuetype(), TypePtr::NotNull);
- RegionNode* region = new RegionNode(3);
- PhiNode* oop = new PhiNode(region, vtptr_type);
- PhiNode* io = new PhiNode(region, Type::ABIO);
- PhiNode* mem = new PhiNode(region, Type::MEMORY, TypePtr::BOTTOM);
-
- // Oop is non-NULL, use it
- region->init_req(1, kit->control());
- oop ->init_req(1, not_null_oop);
- io ->init_req(1, kit->i_o());
- mem ->init_req(1, kit->merged_memory());
-
- // Oop is NULL, allocate value type
- kit->set_control(null_ctl);
- kit->kill_dead_locals();
- ciValueKlass* vk = value_klass();
- Node* klass_node = kit->makecon(TypeKlassPtr::make(vk));
- Node* alloc_oop = kit->new_instance(klass_node, NULL, NULL, false, this);
- // Write field values to memory
- store(kit, alloc_oop, alloc_oop, vk);
- region->init_req(2, kit->control());
- oop ->init_req(2, alloc_oop);
- io ->init_req(2, kit->i_o());
- mem ->init_req(2, kit->merged_memory());
-
- // Update GraphKit
- kit->set_control(kit->gvn().transform(region));
- kit->set_i_o(kit->gvn().transform(io));
- kit->set_all_memory(kit->gvn().transform(mem));
- kit->record_for_igvn(region);
- kit->record_for_igvn(oop);
- kit->record_for_igvn(io);
- kit->record_for_igvn(mem);
-
- // Use cloned ValueTypeNode to propagate oop from now on
- Node* res_oop = kit->gvn().transform(oop);
- ValueTypeNode* vt = clone()->as_ValueType();
- vt->set_oop(res_oop);
- kit->replace_in_map(this, kit->gvn().transform(vt));
- return res_oop;
-}
-
-bool ValueTypeNode::is_allocated(PhaseGVN* phase) const {
- const Type* oop_type = phase->type(get_oop());
- return oop_type->meet(TypePtr::NULL_PTR) != oop_type;
+ vt = kit->gvn().transform(vt)->as_ValueType();
+ kit->replace_in_map(this, vt);
+ return vt;
}
Node* ValueTypeNode::tagged_klass(PhaseGVN& gvn) {
ciValueKlass* vk = value_klass();
const TypeKlassPtr* tk = TypeKlassPtr::make(vk);
@@ -624,23 +632,23 @@
void ValueTypeNode::pass_klass(Node* n, uint pos, const GraphKit& kit) {
n->init_req(pos, tagged_klass(kit.gvn()));
}
-uint ValueTypeNode::pass_fields(Node* n, int base_input, const GraphKit& kit, ciValueKlass* base_vk, int base_offset) {
+uint ValueTypeNode::pass_fields(Node* n, int base_input, GraphKit& kit, bool assert_allocated, ciValueKlass* base_vk, int base_offset) {
ciValueKlass* vk = value_klass();
if (base_vk == NULL) {
base_vk = vk;
}
uint edges = 0;
for (uint i = 0; i < field_count(); i++) {
ciType* f_type = field_type(i);
int offset = base_offset + field_offset(i) - (base_offset > 0 ? vk->first_field_offset() : 0);
Node* arg = field_value(i);
- if (f_type->is_valuetype()) {
+ if (f_type->is_valuetype() && field_is_flattened(i)) {
ciValueKlass* embedded_vk = f_type->as_value_klass();
- edges += arg->as_ValueType()->pass_fields(n, base_input, kit, base_vk, offset);
+ edges += arg->as_ValueType()->pass_fields(n, base_input, kit, assert_allocated, base_vk, offset);
} else {
int j = 0; int extra = 0;
for (; j < base_vk->nof_nonstatic_fields(); j++) {
ciField* f = base_vk->nonstatic_field_at(j);
if (offset == f->offset()) {
@@ -650,10 +658,16 @@
BasicType bt = f->type()->basic_type();
if (bt == T_LONG || bt == T_DOUBLE) {
extra++;
}
}
+ if (arg->is_ValueType()) {
+ // non-flattened value type field
+ ValueTypeNode* vt = arg->as_ValueType();
+ assert(!assert_allocated || vt->is_allocated(&kit.gvn()), "value type field should be allocated");
+ arg = vt->allocate(&kit)->get_oop();
+ }
n->init_req(base_input + j + extra, arg);
edges++;
BasicType bt = f_type->basic_type();
if (bt == T_LONG || bt == T_DOUBLE) {
n->init_req(base_input + j + extra + 1, kit.top());
@@ -698,13 +712,12 @@
void ValueTypeNode::remove_redundant_allocations(PhaseIterGVN* igvn, PhaseIdealLoop* phase) {
assert(EliminateAllocations, "allocation elimination should be enabled");
Node_List dead_allocations;
// Search for allocations of this value type
for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) {
- Node* out1 = fast_out(i);
- if (out1->is_Allocate() && out1->in(AllocateNode::ValueNode) == this) {
- AllocateNode* alloc = out1->as_Allocate();
+ AllocateNode* alloc = fast_out(i)->isa_Allocate();
+ if (alloc != NULL && alloc->result_cast() != NULL && alloc->in(AllocateNode::ValueNode) == this) {
Node* res_dom = NULL;
if (is_allocated(igvn)) {
// The value type is already allocated but still connected to an AllocateNode.
// This can happen with late inlining when we first allocate a value type argument
// but later decide to inline the call with the callee code also allocating.
@@ -721,14 +734,12 @@
break;
}
}
}
if (res_dom != NULL) {
- // Found a dominating allocation
- Node* res = alloc->result_cast();
- assert(res != NULL, "value type allocation should not be dead");
// Move users to dominating allocation
+ Node* res = alloc->result_cast();
igvn->replace_node(res, res_dom);
// The dominated allocation is now dead, remove the
// value type node connection and adjust the iterator.
dead_allocations.push(alloc);
igvn->replace_input_of(alloc, AllocateNode::ValueNode, NULL);
@@ -758,31 +769,29 @@
phase->lazy_replace(projs.catchall_catchproj, phase->C->top());
phase->lazy_replace(projs.resproj, phase->C->top());
}
}
-
#ifndef PRODUCT
void ValueTypeNode::dump_spec(outputStream* st) const {
TypeNode::dump_spec(st);
}
#endif
-ValueTypePtrNode* ValueTypePtrNode::make(PhaseGVN* gvn, CheckCastPPNode* cast) {
- ciValueKlass* vk = cast->type()->is_valuetypeptr()->value_type()->value_klass();
- ValueTypePtrNode* vt = new ValueTypePtrNode(vk, gvn->C);
- assert(cast->in(1)->is_Proj(), "bad graph shape");
- ValueTypeBaseNode::make(gvn, cast->in(1)->in(0), vt, vk, 0, TypeFunc::Parms+1, false);
+ValueTypePtrNode* ValueTypePtrNode::make(GraphKit* kit, ciValueKlass* vk, CallNode* call) {
+ ValueTypePtrNode* vt = new ValueTypePtrNode(vk, kit->zerocon(T_VALUETYPE), kit->C);
+ Node* ctl = kit->control();
+ ValueTypeBaseNode::make(&kit->gvn(), ctl, kit->merged_memory(), call, vt, vk, 0, TypeFunc::Parms+1, false);
+ kit->set_control(ctl);
return vt;
}
-ValueTypePtrNode* ValueTypePtrNode::make(PhaseGVN& gvn, Node* mem, Node* oop) {
+ValueTypePtrNode* ValueTypePtrNode::make(PhaseGVN& gvn, Node*& ctl, Node* mem, Node* oop) {
// Create and initialize a ValueTypePtrNode by loading all field
// values from a heap-allocated version and also save the oop.
ciValueKlass* vk = gvn.type(oop)->is_valuetypeptr()->value_type()->value_klass();
- ValueTypePtrNode* vtptr = new ValueTypePtrNode(vk, gvn.C);
- vtptr->set_oop(oop);
- vtptr->load(gvn, mem, oop, oop, vk);
+ ValueTypePtrNode* vtptr = new ValueTypePtrNode(vk, oop, gvn.C);
+ vtptr->load(gvn, ctl, mem, oop, oop, vk);
return vtptr;
}
< prev index next >