Skip to content
Permalink
Browse files
8229897: [lworld] C1 should avoid allocation when reading a field fro…
…m a flattened field

Reviewed-by: thartmann
  • Loading branch information
fparain committed Aug 28, 2020
1 parent 54b5410 commit 3540dd4d19c728c52f9141341835026e9bb17ce6
@@ -1837,25 +1837,27 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
assert(Interpreter::bytecode_should_reexecute(code), "should reexecute");
state_before = copy_state_before();
}
obj = apop();
ObjectType* obj_type = obj->type()->as_ObjectType();
if (field->is_constant() && !field->is_flattened() && obj_type->is_constant() && !PatchALot) {
ciObject* const_oop = obj_type->constant_value();
if (!const_oop->is_null_object() && const_oop->is_loaded()) {
ciConstant field_value = field->constant_value_of(const_oop);
if (field_value.is_valid()) {
if (field->signature()->is_Q_signature() && field_value.is_null_or_zero()) {
// Non-flattened inline type field. Replace null by the default value.
constant = new Constant(new InstanceConstant(field->type()->as_inline_klass()->default_instance()));
} else {
constant = make_constant(field_value, field);
}
// For CallSite objects add a dependency for invalidation of the optimization.
if (field->is_call_site_target()) {
ciCallSite* call_site = const_oop->as_call_site();
if (!call_site->is_fully_initialized_constant_call_site()) {
ciMethodHandle* target = field_value.as_object()->as_method_handle();
dependency_recorder()->assert_call_site_target_value(call_site, target);
if (!has_delayed_flattened_field_access()) {
obj = apop();
ObjectType* obj_type = obj->type()->as_ObjectType();
if (field->is_constant() && !field->is_flattened() && obj_type->is_constant() && !PatchALot) {
ciObject* const_oop = obj_type->constant_value();
if (!const_oop->is_null_object() && const_oop->is_loaded()) {
ciConstant field_value = field->constant_value_of(const_oop);
if (field_value.is_valid()) {
if (field->signature()->is_Q_signature() && field_value.is_null_or_zero()) {
// Non-flattened inline type field. Replace null by the default value.
constant = new Constant(new InstanceConstant(field->type()->as_inline_klass()->default_instance()));
} else {
constant = make_constant(field_value, field);
}
// For CallSite objects add a dependency for invalidation of the optimization.
if (field->is_call_site_target()) {
ciCallSite* call_site = const_oop->as_call_site();
if (!call_site->is_fully_initialized_constant_call_site()) {
ciMethodHandle* target = field_value.as_object()->as_method_handle();
dependency_recorder()->assert_call_site_target_value(call_site, target);
}
}
}
}
@@ -1868,7 +1870,15 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
state_before = copy_state_for_exception();
}
if (!field->is_flattened()) {
LoadField* load = new LoadField(obj, offset, field, false, state_before, needs_patching);
LoadField* load;
if (!has_delayed_flattened_field_access()) {
load = new LoadField(obj, offset, field, false, state_before, needs_patching);
} else {
load = new LoadField(_delayed_flattened_field_access->obj(),
_delayed_flattened_field_access->offset() + offset - field->holder()->as_inline_klass()->first_field_offset(),
field, false, state_before, needs_patching);
_delayed_flattened_field_access = NULL;
}
Value replacement = !needs_patching ? _memory->load(load) : load;
if (replacement != load) {
assert(replacement->is_linked() || !replacement->can_be_linked(), "should already by linked");
@@ -1893,18 +1903,38 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
} else {
push(type, append(load));
}
} else { // flattened field, not optimized solution: re-instantiate the flattened value
assert(field->type()->is_inlinetype(), "Sanity check");
ciInlineKlass* inline_klass = field->type()->as_inline_klass();
int flattening_offset = field->offset() - inline_klass->first_field_offset();
assert(field->type()->is_inlinetype(), "Sanity check");
scope()->set_wrote_final();
scope()->set_wrote_fields();
NewInlineTypeInstance* new_instance = new NewInlineTypeInstance(inline_klass, state_before, false);
_memory->new_instance(new_instance);
apush(append_split(new_instance));
copy_inline_content(inline_klass, obj, field->offset(), new_instance, inline_klass->first_field_offset(),
state_before, needs_patching);
} else {
ciBytecodeStream s(method());
s.force_bci(bci());
s.next();
if (s.cur_bc() == Bytecodes::_getfield && !needs_patching) {
if (!has_delayed_flattened_field_access()) {
null_check(obj);
DelayedFlattenedFieldAccess* dffa = new DelayedFlattenedFieldAccess(obj, field, field->offset());
_delayed_flattened_field_access = dffa;
} else {
_delayed_flattened_field_access->update(field, offset - field->holder()->as_inline_klass()->first_field_offset());
}
} else {
assert(field->type()->is_inlinetype(), "Sanity check");
ciInlineKlass* inline_klass = field->type()->as_inline_klass();
assert(field->type()->is_inlinetype(), "Sanity check");
scope()->set_wrote_final();
scope()->set_wrote_fields();
NewInlineTypeInstance* new_instance = new NewInlineTypeInstance(inline_klass, state_before, false);
_memory->new_instance(new_instance);
apush(append_split(new_instance));
if (!has_delayed_flattened_field_access()) {
copy_inline_content(inline_klass, obj, field->offset(), new_instance, inline_klass->first_field_offset(),
state_before, needs_patching);
} else {
copy_inline_content(inline_klass, _delayed_flattened_field_access->obj(),
_delayed_flattened_field_access->offset() + field->offset() - field->holder()->as_inline_klass()->first_field_offset(),
new_instance, inline_klass->first_field_offset(),
state_before, needs_patching);
_delayed_flattened_field_access = NULL;
}
}
}
}
break;
@@ -3491,6 +3521,7 @@ GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope)
, _inline_bailout_msg(NULL)
, _instruction_count(0)
, _osr_entry(NULL)
, _delayed_flattened_field_access(NULL)
{
int osr_bci = compilation->osr_bci();

@@ -35,6 +35,26 @@

class MemoryBuffer;

class DelayedFlattenedFieldAccess : public CompilationResourceObj {
private:
Value _obj;
ciField* _field;
int _offset;
public:
DelayedFlattenedFieldAccess(Value obj, ciField* field, int offset)
: _obj(obj)
, _field(field)
, _offset(offset) { }

void update(ciField* field, int offset) {
_field = field;
_offset += offset;
}
Value obj() { return _obj; }
ciField* field() { return _field; }
int offset() { return _offset; }
};

class GraphBuilder {
private:
// Per-scope data. These are pushed and popped as we descend into
@@ -191,6 +211,10 @@ class GraphBuilder {
Instruction* _last; // the last instruction added
bool _skip_block; // skip processing of the rest of this block

DelayedFlattenedFieldAccess* _delayed_flattened_field_access;
bool has_delayed_flattened_field_access() { return _delayed_flattened_field_access != NULL; }


// accessors
ScopeData* scope_data() const { return _scope_data; }
Compilation* compilation() const { return _compilation; }

0 comments on commit 3540dd4

Please sign in to comment.