From 9110592b85ba9d437b49b2d6ba5effac2144c805 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Thu, 12 Dec 2024 12:41:35 +0100 Subject: [PATCH] Refactoring --- src/hotspot/share/c1/c1_LIRGenerator.cpp | 3 +- src/hotspot/share/ci/ciReplay.cpp | 1 + src/hotspot/share/opto/inlinetypenode.cpp | 146 +++++++++++----------- src/hotspot/share/opto/inlinetypenode.hpp | 5 +- 4 files changed, 77 insertions(+), 78 deletions(-) diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index 699f1793b88..2e045ef78d4 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -2212,7 +2212,8 @@ void LIRGenerator::do_LoadField(LoadField* x) { ciInlineKlass* vk = field->type()->as_inline_klass(); BasicType bt = size_to_basic_type(vk->nullable_size_in_bytes()); - // Allocate buffer + // Allocate buffer (we can't easily do this conditionally on the null check below + // because branches added in the LIR are opaque to the register allocator). NewInstance* buffer = new NewInstance(vk, x->state_before(), false, true); do_NewInstance(buffer); LIRItem dest(buffer, this); diff --git a/src/hotspot/share/ci/ciReplay.cpp b/src/hotspot/share/ci/ciReplay.cpp index 99ec0d3b65d..044ca366d04 100644 --- a/src/hotspot/share/ci/ciReplay.cpp +++ b/src/hotspot/share/ci/ciReplay.cpp @@ -1151,6 +1151,7 @@ class CompileReplay : public StackObj { Klass* kelem = ObjArrayKlass::cast(actual_array_klass)->element_klass(); value = oopFactory::new_objArray(kelem, length, CHECK_(true)); } else if (field_signature[0] == JVM_SIGNATURE_ARRAY) { + // TODO this is dead, right? Klass* kelem = resolve_klass(field_signature + 1, CHECK_(true)); parse_klass(CHECK_(true)); // eat up the array class name value = oopFactory::new_valueArray(kelem, length, CHECK_(true)); diff --git a/src/hotspot/share/opto/inlinetypenode.cpp b/src/hotspot/share/opto/inlinetypenode.cpp index f6f442ea6db..b10f1040f05 100644 --- a/src/hotspot/share/opto/inlinetypenode.cpp +++ b/src/hotspot/share/opto/inlinetypenode.cpp @@ -192,20 +192,22 @@ Node* InlineTypeNode::field_value(uint index) const { return in(Values + index); } -// TODO implement with a worklist -static Node* helper2(const InlineTypeNode* vt, int search_offset, int holder_offset = 0) { - for (uint i = 0; i < vt->field_count(); ++i) { - if (vt->field_is_flat(i)) { - InlineTypeNode* value = vt->field_value(i)->as_InlineType(); - if (!vt->field_is_null_free(i)) { - int offset = holder_offset + vt->field_null_marker_offset(i); - if (offset == search_offset) { +// Get the value of the null marker at the given offset. +Node* InlineTypeNode::null_marker_by_offset(int offset, int holder_offset) const { + // Search through the null markers of all flat fields + for (uint i = 0; i < field_count(); ++i) { + if (field_is_flat(i)) { + InlineTypeNode* value = field_value(i)->as_InlineType(); + if (!field_is_null_free(i)) { + int nm_offset = holder_offset + field_null_marker_offset(i); + if (nm_offset == offset) { return value->get_is_init(); } } - Node* ret = helper2(value->as_InlineType(), search_offset, holder_offset + vt->field_offset(i) - value->bottom_type()->inline_klass()->first_field_offset()); - if (ret != nullptr) { - return ret; + int flat_holder_offset = holder_offset + field_offset(i) - value->inline_klass()->first_field_offset(); + Node* nm_value = value->null_marker_by_offset(offset, flat_holder_offset); + if (nm_value != nullptr) { + return nm_value; } } } @@ -214,15 +216,17 @@ static Node* helper2(const InlineTypeNode* vt, int search_offset, int holder_off // Get the value of the field at the given offset. // If 'recursive' is true, flat inline type fields will be resolved recursively. -Node* InlineTypeNode::field_value_by_offset(int offset, bool recursive, bool root) const { - // If the field at 'offset' belongs to a flat inline type field, 'index' refers to the - // corresponding InlineTypeNode input and 'sub_offset' is the offset in the flattened inline type. - if (root && recursive) { - // Check if we are loading a null marker - Node* val = helper2(this, offset); - if (val != nullptr) return val; +Node* InlineTypeNode::field_value_by_offset(int offset, bool recursive, bool search_null_marker) const { + // First check if we are loading a null marker which is not a real field + if (recursive && search_null_marker) { + Node* value = null_marker_by_offset(offset); + if (value != nullptr){ + return value; + } } + // If the field at 'offset' belongs to a flat inline type field, 'index' refers to the + // corresponding InlineTypeNode input and 'sub_offset' is the offset in the flattened inline type. int index = inline_klass()->field_index_by_offset(offset); int sub_offset = offset - field_offset(index); Node* value = field_value(index); @@ -290,30 +294,29 @@ int InlineTypeNode::field_null_marker_offset(uint index) const { return field->null_marker_offset(); } - -// TODO implement with a worklist -static uint helper(InlineTypeNode* vt, Unique_Node_List& worklist, Node_List& null_markers, SafePointNode* sfpt) { +uint InlineTypeNode::add_fields_to_safepoint(Unique_Node_List& worklist, Node_List& null_markers, SafePointNode* sfpt) { uint cnt = 0; - for (uint i = 0; i < vt->field_count(); ++i) { - Node* value = vt->field_value(i); - if (vt->field_is_flat(i)) { - cnt += helper(value->as_InlineType(), worklist, null_markers, sfpt); - if (!vt->field_is_null_free(i)) { - null_markers.push(value->as_InlineType()->get_is_init()); - } - } else { - if (value->is_InlineType()) { - // Add inline type field to the worklist to process later - worklist.push(value); + for (uint i = 0; i < field_count(); ++i) { + Node* value = field_value(i); + if (field_is_flat(i)) { + InlineTypeNode* vt = value->as_InlineType(); + cnt += vt->add_fields_to_safepoint(worklist, null_markers, sfpt); + if (!field_is_null_free(i)) { + null_markers.push(vt->get_is_init()); + cnt++; } - sfpt->add_req(value); - cnt++; + continue; } + if (value->is_InlineType()) { + // Add inline type to the worklist to process later + worklist.push(value); + } + sfpt->add_req(value); + cnt++; } return cnt; } - void InlineTypeNode::make_scalar_in_safepoint(PhaseIterGVN* igvn, Unique_Node_List& worklist, SafePointNode* sfpt) { // We should not scalarize larvals in debug info of their constructor calls because their fields could still be // updated. If we scalarize and update the fields in the constructor, the updates won't be visible in the caller after @@ -345,12 +348,10 @@ void InlineTypeNode::make_scalar_in_safepoint(PhaseIterGVN* igvn, Unique_Node_Li // Iterate over the inline type fields in order of increasing // offset and add the field values to the safepoint. Node_List null_markers; - uint nfields = helper(this, worklist, null_markers, sfpt); - + uint nfields = add_fields_to_safepoint(worklist, null_markers, sfpt); + // Add null markers after the field values for (uint i = 0; i < null_markers.size(); ++i) { - Node* is_init = null_markers.at(i); - sfpt->add_req(is_init); - nfields++; + sfpt->add_req(null_markers.at(i)); } jvms->set_endoff(sfpt->req()); SafePointScalarObjectNode* sobj = new SafePointScalarObjectNode(type()->isa_instptr(), @@ -712,28 +713,12 @@ bool InlineTypeNode::is_allocated(PhaseGVN* phase) const { return !oop_type->maybe_null(); } -// TODO implement with a worklist -static void helper3(Compile* C, CallNode* call, const InlineTypeNode* vt, uint& proj_idx) { - for (uint i = 0; i < vt->field_count(); ++i) { - Node* value = vt->field_value(i); - if (vt->field_is_flat(i)) { - helper3(C, call, value->as_InlineType(), proj_idx); - if (!vt->field_is_null_free(i)) { - ProjNode* pn = call->proj_out_or_null(proj_idx++); - if (pn != nullptr) { - C->gvn_replace_by(pn, value->as_InlineType()->get_is_init()); - C->initial_gvn()->hash_delete(pn); - pn->set_req(0, C->top()); - } - } - continue; - } - ProjNode* pn = call->proj_out_or_null(proj_idx++); - if (pn != nullptr) { - C->gvn_replace_by(pn, value); - C->initial_gvn()->hash_delete(pn); - pn->set_req(0, C->top()); - } +static void replace_proj(Compile* C, CallNode* call, uint& proj_idx, Node* value) { + ProjNode* pn = call->proj_out_or_null(proj_idx++); + if (pn != nullptr) { + C->gvn_replace_by(pn, value); + C->initial_gvn()->hash_delete(pn); + pn->set_req(0, C->top()); } } @@ -743,22 +728,31 @@ static void helper3(Compile* C, CallNode* call, const InlineTypeNode* vt, uint& // projection, we find the corresponding inline type field. void InlineTypeNode::replace_call_results(GraphKit* kit, CallNode* call, Compile* C) { uint proj_idx = TypeFunc::Parms; - ProjNode* pn = call->proj_out_or_null(proj_idx++); - if (pn != nullptr) { - C->gvn_replace_by(pn, get_oop()); - C->initial_gvn()->hash_delete(pn); - pn->set_req(0, C->top()); - } - - helper3(C, call, this, proj_idx); + // Replace oop projection + replace_proj(C, call, proj_idx, get_oop()); + // Replace field projections + replace_field_projs(C, call, proj_idx); + // Replace is_init projection + replace_proj(C, call, proj_idx, get_is_init()); + assert(proj_idx == call->tf()->range_cc()->cnt(), "missed a projection"); +} - pn = call->proj_out_or_null(proj_idx++); - if (pn != nullptr) { - C->gvn_replace_by(pn, get_is_init()); - C->initial_gvn()->hash_delete(pn); - pn->set_req(0, C->top()); +void InlineTypeNode::replace_field_projs(Compile* C, CallNode* call, uint& proj_idx) { + for (uint i = 0; i < field_count(); ++i) { + Node* value = field_value(i); + if (field_is_flat(i)) { + InlineTypeNode* vt = value->as_InlineType(); + // Replace field projections for flat field + vt->replace_field_projs(C, call, proj_idx); + if (!field_is_null_free(i)) { + // Replace is_init projection for nullable field + replace_proj(C, call, proj_idx, vt->get_is_init()); + } + continue; + } + // Replace projection for field value + replace_proj(C, call, proj_idx, value); } - assert(proj_idx == call->tf()->range_cc()->cnt(), "missed a projection"); } Node* InlineTypeNode::allocate_fields(GraphKit* kit) { diff --git a/src/hotspot/share/opto/inlinetypenode.hpp b/src/hotspot/share/opto/inlinetypenode.hpp index 9a4611443c4..c479115aea7 100644 --- a/src/hotspot/share/opto/inlinetypenode.hpp +++ b/src/hotspot/share/opto/inlinetypenode.hpp @@ -63,6 +63,7 @@ class InlineTypeNode : public TypeNode { ciInlineKlass* inline_klass() const { return type()->inline_klass(); } void make_scalar_in_safepoint(PhaseIterGVN* igvn, Unique_Node_List& worklist, SafePointNode* sfpt); + uint add_fields_to_safepoint(Unique_Node_List& worklist, Node_List& null_markers, SafePointNode* sfpt); const TypePtr* field_adr_type(Node* base, int offset, ciInstanceKlass* holder, DecoratorSet decorators, PhaseGVN& gvn) const; @@ -122,7 +123,8 @@ class InlineTypeNode : public TypeNode { // Inline type fields uint field_count() const { return req() - Values; } Node* field_value(uint index) const; - Node* field_value_by_offset(int offset, bool recursive = false, bool root = true) const; + Node* field_value_by_offset(int offset, bool recursive = false, bool search_null_marker = true) const; + Node* null_marker_by_offset(int offset, int holder_offset = 0) const; void set_field_value(uint index, Node* value); void set_field_value_by_offset(int offset, Node* value); int field_offset(uint index) const; @@ -149,6 +151,7 @@ class InlineTypeNode : public TypeNode { bool is_allocated(PhaseGVN* phase) const; void replace_call_results(GraphKit* kit, CallNode* call, Compile* C); + void replace_field_projs(Compile* C, CallNode* call, uint& proj_idx); // Allocate all non-flat inline type fields Node* allocate_fields(GraphKit* kit);