Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
8267846: [lworld] JIT support for the L/Q model (step 1)
Reviewed-by: fparain
  • Loading branch information
TobiHartmann committed May 31, 2021
1 parent bca447b commit 477ecf5
Show file tree
Hide file tree
Showing 39 changed files with 297 additions and 202 deletions.
6 changes: 2 additions & 4 deletions src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp
Expand Up @@ -513,10 +513,8 @@ void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) {
assert(result->is_illegal() || !result->is_single_cpu() || result->as_register() == r0, "word returns are in r0,");

ciMethod* method = compilation()->method();

ciType* return_type = method->return_type();
if (InlineTypeReturnedAsFields && return_type->is_inlinetype()) {
ciInlineKlass* vk = return_type->as_inline_klass();
if (InlineTypeReturnedAsFields && method->signature()->returns_null_free_inline_type()) {
ciInlineKlass* vk = method->return_type()->as_inline_klass();
if (vk->can_be_returned_as_fields()) {
address unpack_handler = vk->unpack_handler();
assert(unpack_handler != NULL, "must be");
Expand Down
5 changes: 2 additions & 3 deletions src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp
Expand Up @@ -531,9 +531,8 @@ void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) {
}

ciMethod* method = compilation()->method();
ciType* return_type = method->return_type();
if (InlineTypeReturnedAsFields && return_type->is_inlinetype() && return_type->is_null_free()) {
ciInlineKlass* vk = return_type->as_inline_klass();
if (InlineTypeReturnedAsFields && method->signature()->returns_null_free_inline_type()) {
ciInlineKlass* vk = method->return_type()->as_inline_klass();
if (vk->can_be_returned_as_fields()) {
#ifndef _LP64
Unimplemented();
Expand Down
9 changes: 4 additions & 5 deletions src/hotspot/share/c1/c1_Canonicalizer.cpp
Expand Up @@ -662,15 +662,14 @@ void Canonicalizer::do_CheckCast (CheckCast* x) {
klass->as_instance_klass()->is_interface();
// Interface casts can't be statically optimized away since verifier doesn't
// enforce interface types in bytecode.
if (!is_interface && klass->is_subtype_of(x->klass())) {
if (!is_interface && klass->is_subtype_of(x->klass()) && (!x->is_null_free() || obj->is_null_free())) {
assert(!x->klass()->is_inlinetype() || x->klass() == klass, "Inline klasses can't have subtypes");
set_canonical(obj);
return;
}
}
// checkcast of null returns null for non-inline klasses
if (!x->klass()->is_inlinetype() && x->is_null_free()
&& obj->as_Constant() && obj->type()->as_ObjectType()->constant_value()->is_null_object()) {
// checkcast of null returns null for non null-free klasses
if (!x->is_null_free() && obj->is_null_obj()) {
set_canonical(obj);
}
}
Expand All @@ -684,7 +683,7 @@ void Canonicalizer::do_InstanceOf (InstanceOf* x) {
return;
}
// instanceof null returns false
if (obj->as_Constant() && obj->type()->as_ObjectType()->constant_value()->is_null_object()) {
if (obj->as_Constant() && obj->is_null_obj()) {
set_constant(0);
}
}
Expand Down
26 changes: 13 additions & 13 deletions src/hotspot/share/c1/c1_GraphBuilder.cpp
Expand Up @@ -1844,9 +1844,9 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
assert(!field->is_stable() || !field_value.is_null_or_zero(),
"stable static w/ default value shouldn't be a constant");
constant = make_constant(field_value, field);
} else if (field_type == T_INLINE_TYPE && field->type()->is_null_free() && field->type()->unwrap()->as_inline_klass()->is_empty()) {
} else if (field->is_null_free() && field->type()->is_loaded() && field->type()->as_inline_klass()->is_empty()) {
// Loading from a field of an empty inline type. Just return the default instance.
constant = new Constant(new InstanceConstant(field->type()->unwrap()->as_inline_klass()->default_instance()));
constant = new Constant(new InstanceConstant(field->type()->as_inline_klass()->default_instance()));
}
if (constant != NULL) {
push(type, append(constant));
Expand All @@ -1869,7 +1869,7 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
Value mask = append(new Constant(new IntConstant(1)));
val = append(new LogicOp(Bytecodes::_iand, val, mask));
}
if (field_type == T_INLINE_TYPE && field->type()->unwrap()->as_inline_klass()->is_empty()) {
if (field->is_null_free() && field->type()->is_loaded() && field->type()->as_inline_klass()->is_empty()) {
// Storing to a field of an empty inline type. Ignore.
break;
}
Expand All @@ -1887,18 +1887,18 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
if (!has_pending_field_access() && !has_pending_load_indexed()) {
obj = apop();
ObjectType* obj_type = obj->type()->as_ObjectType();
if (field_type == T_INLINE_TYPE && field->type()->is_null_free() && field->type()->unwrap()->as_inline_klass()->is_empty()) {
if (field->is_null_free() && field->type()->is_loaded() && field->type()->as_inline_klass()->is_empty()) {
// Loading from a field of an empty inline type. Just return the default instance.
null_check(obj);
constant = new Constant(new InstanceConstant(field->type()->unwrap()->as_inline_klass()->default_instance()));
constant = new Constant(new InstanceConstant(field->type()->as_inline_klass()->default_instance()));
} else 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()) {
if (field->is_null_free() && field_value.is_null_or_zero()) {
// Non-flattened inline type field. Replace null by the default value.
constant = new Constant(new InstanceConstant(field->type()->unwrap()->as_inline_klass()->default_instance()));
constant = new Constant(new InstanceConstant(field->type()->as_inline_klass()->default_instance()));
} else {
constant = make_constant(field_value, field);
}
Expand Down Expand Up @@ -1985,7 +1985,7 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
set_pending_field_access(dfa);
}
} else {
ciInlineKlass* inline_klass = field->type()->unwrap()->as_inline_klass();
ciInlineKlass* inline_klass = field->type()->as_inline_klass();
scope()->set_wrote_final();
scope()->set_wrote_fields();
bool need_membar = false;
Expand Down Expand Up @@ -2042,7 +2042,7 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
Value mask = append(new Constant(new IntConstant(1)));
val = append(new LogicOp(Bytecodes::_iand, val, mask));
}
if (field_type == T_INLINE_TYPE && field->type()->is_null_free() && field->type()->unwrap()->as_inline_klass()->is_empty()) {
if (field->is_null_free() && field->type()->is_loaded() && field->type()->as_inline_klass()->is_empty()) {
// Storing to a field of an empty inline type. Ignore.
null_check(obj);
} else if (!field->is_flattened()) {
Expand All @@ -2053,7 +2053,7 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
}
} else {
assert(!needs_patching, "Can't patch flattened inline type field access");
ciInlineKlass* inline_klass = field->type()->unwrap()->as_inline_klass();
ciInlineKlass* inline_klass = field->type()->as_inline_klass();
copy_inline_content(inline_klass, val, inline_klass->first_field_offset(), obj, offset, state_before, field);
}
break;
Expand Down Expand Up @@ -2129,7 +2129,7 @@ void GraphBuilder::withfield(int field_index) {
}
if (field_modify->is_flattened()) {
assert(!needs_patching, "Can't patch flattened inline type field access");
ciInlineKlass* vk = field_modify->type()->unwrap()->as_inline_klass();
ciInlineKlass* vk = field_modify->type()->as_inline_klass();
if (!vk->is_empty()) {
copy_inline_content(vk, val, vk->first_field_offset(), new_instance, offset_modify, state_before, field_modify);
}
Expand Down Expand Up @@ -2478,7 +2478,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
}

Invoke* result = new Invoke(code, result_type, recv, args, target, state_before,
declared_signature->return_type()->is_null_free());
declared_signature->returns_null_free_inline_type());
// push result
append_split(result);

Expand Down Expand Up @@ -3579,7 +3579,7 @@ ValueStack* GraphBuilder::state_at_entry() {
// don't allow T_ARRAY to propagate into locals types
if (is_reference_type(basic_type)) basic_type = T_OBJECT;
ValueType* vt = as_ValueType(basic_type);
state->store_local(idx, new Local(type, vt, idx, false, type->is_null_free()));
state->store_local(idx, new Local(type, vt, idx, false, sig->is_null_free_at(i)));
idx += type->size();
}

Expand Down
13 changes: 5 additions & 8 deletions src/hotspot/share/c1/c1_Instruction.cpp
Expand Up @@ -108,7 +108,7 @@ void Instruction::state_values_do(ValueVisitor* f) {
}

ciType* Instruction::exact_type() const {
ciType* t = declared_type();
ciType* t = declared_type();
if (t != NULL && t->is_klass()) {
return t->as_klass()->exact_klass();
}
Expand Down Expand Up @@ -138,15 +138,13 @@ bool Instruction::maybe_flattened_array() {
if (UseFlatArray) {
ciType* type = declared_type();
if (type != NULL) {
if (type->is_obj_array_klass()) {
// Due to array covariance, the runtime type might be a flattened array.
if (type->is_obj_array_klass() && !type->as_obj_array_klass()->is_elem_null_free()) {
// The runtime type of [LMyValue might be [QMyValue due to [QMyValue <: [LMyValue.
ciKlass* element_klass = type->as_obj_array_klass()->element_klass();
if (element_klass->can_be_inline_klass() && (!element_klass->is_inlinetype() || element_klass->as_inline_klass()->flatten_array())) {
return true;
}
} else if (type->is_flat_array_klass()) {
ciKlass* element_klass = type->as_flat_array_klass()->element_klass();
assert(!element_klass->is_loaded() || element_klass->flatten_array(), "must be flattened");
return true;
} else if (type->is_klass() && type->as_klass()->is_java_lang_Object()) {
// This can happen as a parameter to System.arraycopy()
Expand All @@ -166,8 +164,7 @@ bool Instruction::maybe_null_free_array() {
if (type != NULL) {
if (type->is_obj_array_klass()) {
// Due to array covariance, the runtime type might be a null-free array.
ciKlass* element_klass = type->as_obj_array_klass()->element_klass();
if (element_klass->can_be_inline_klass()) {
if (type->as_obj_array_klass()->can_be_inline_array_klass()) {
return true;
}
}
Expand Down Expand Up @@ -268,7 +265,7 @@ ciType* LoadIndexed::declared_type() const {
bool StoreIndexed::is_exact_flattened_array_store() const {
if (array()->is_loaded_flattened_array() && value()->as_Constant() == NULL && value()->declared_type() != NULL) {
ciKlass* element_klass = array()->declared_type()->as_flat_array_klass()->element_klass();
ciKlass* actual_klass = value()->declared_type()->unwrap()->as_klass();
ciKlass* actual_klass = value()->declared_type()->as_klass();

// The following check can fail with inlining:
// void test45_inline(Object[] oa, Object o, int index) { oa[index] = o; }
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/c1/c1_Instruction.hpp
Expand Up @@ -866,7 +866,7 @@ LEAF(LoadField, AccessField)
ciInlineKlass* inline_klass = NULL, Value default_value = NULL )
: AccessField(obj, offset, field, is_static, state_before, needs_patching)
{
set_null_free(field->signature()->is_Q_signature());
set_null_free(field->is_null_free());
}

ciType* declared_type() const;
Expand Down
21 changes: 8 additions & 13 deletions src/hotspot/share/c1/c1_LIRGenerator.cpp
Expand Up @@ -1747,13 +1747,13 @@ void LIRGenerator::access_sub_element(LIRItem& array, LIRItem& index, LIR_Opr& r
elm_item, LIR_OprFact::intConst(sub_offset), result,
NULL, NULL);

if (field->signature()->is_Q_signature()) {
assert(field->type()->unwrap()->as_inline_klass()->is_loaded(), "Must be");
if (field->is_null_free()) {
assert(field->type()->as_inline_klass()->is_loaded(), "Must be");
LabelObj* L_end = new LabelObj();
__ cmp(lir_cond_notEqual, result, LIR_OprFact::oopConst(NULL));
__ branch(lir_cond_notEqual, L_end->label());
set_in_conditional_code(true);
Constant* default_value = new Constant(new InstanceConstant(field->type()->unwrap()->as_inline_klass()->default_instance()));
Constant* default_value = new Constant(new InstanceConstant(field->type()->as_inline_klass()->default_instance()));
if (default_value->is_pinned()) {
__ move(LIR_OprFact::value_type(default_value->type()), result);
} else {
Expand All @@ -1773,7 +1773,7 @@ void LIRGenerator::access_flattened_array(bool is_load, LIRItem& array, LIRItem&

ciInlineKlass* elem_klass = NULL;
if (field != NULL) {
elem_klass = field->type()->unwrap()->as_inline_klass();
elem_klass = field->type()->as_inline_klass();
} else {
elem_klass = array.value()->declared_type()->as_flat_array_klass()->element_klass()->as_inline_klass();
}
Expand Down Expand Up @@ -2046,7 +2046,7 @@ LIR_Opr LIRGenerator::access_atomic_add_at(DecoratorSet decorators, BasicType ty
bool LIRGenerator::inline_type_field_access_prolog(AccessField* x, CodeEmitInfo* info) {
ciField* field = x->field();
assert(!field->is_flattened(), "Flattened field access should have been expanded");
if (!field->signature()->is_Q_signature()) {
if (!field->is_null_free()) {
return true; // Not an inline type field
}
// Deoptimize if the access is non-static and requires patching (holder not loaded
Expand All @@ -2055,7 +2055,7 @@ bool LIRGenerator::inline_type_field_access_prolog(AccessField* x, CodeEmitInfo*
bool could_be_flat = !x->is_static() && x->needs_patching();
// Deoptimize if we load from a static field with an unloaded type because we need
// the default value if the field is null.
bool could_be_null = x->is_static() && x->as_LoadField() != NULL && !field->type()->unwrap()->is_loaded();
bool could_be_null = x->is_static() && x->as_LoadField() != NULL && !field->type()->is_loaded();
assert(!could_be_null || !field->holder()->is_loaded(), "inline type field should be loaded");
if (could_be_flat || could_be_null) {
assert(x->needs_patching(), "no deopt required");
Expand Down Expand Up @@ -2134,10 +2134,10 @@ void LIRGenerator::do_LoadField(LoadField* x) {
info ? new CodeEmitInfo(info) : NULL, info);

ciField* field = x->field();
if (field->signature()->is_Q_signature()) {
if (field->is_null_free()) {
// Load from non-flattened inline type field requires
// a null check to replace null with the default value.
ciInlineKlass* inline_klass = field->type()->unwrap()->as_inline_klass();
ciInlineKlass* inline_klass = field->type()->as_inline_klass();
assert(inline_klass->is_loaded(), "field klass must be loaded");

ciInstanceKlass* holder = field->holder();
Expand Down Expand Up @@ -3053,11 +3053,6 @@ ciKlass* LIRGenerator::profile_type(ciMethodData* md, int md_base_offset, int md
do_update = exact_klass == NULL || ciTypeEntries::valid_ciklass(profiled_k) != exact_klass;
}

// Inline types can't be null
if (exact_klass != NULL && exact_klass->is_inlinetype()) {
do_null = false;
}

if (!do_null && !do_update) {
return result;
}
Expand Down
31 changes: 13 additions & 18 deletions src/hotspot/share/ci/ciArrayKlass.cpp
Expand Up @@ -102,27 +102,22 @@ bool ciArrayKlass::is_leaf_type() {
// ciArrayKlass::base_element_type
//
// What type is obtained when this array is indexed as many times as possible?
ciArrayKlass* ciArrayKlass::make(ciType* element_type) {
ciArrayKlass* ciArrayKlass::make(ciType* element_type, bool null_free) {
if (element_type->is_primitive_type()) {
return ciTypeArrayKlass::make(element_type->basic_type());
} else {
return make(element_type->as_klass(), element_type->is_null_free());
}
}

ciArrayKlass* ciArrayKlass::make(ciKlass* klass, bool null_free) {
if (null_free && klass->is_loaded()) {
GUARDED_VM_ENTRY(
EXCEPTION_CONTEXT;
Klass* ak = InlineKlass::cast(klass->get_Klass())->null_free_inline_array_klass(THREAD);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
} else if (ak != NULL && ak->is_flatArray_klass()) {
return ciFlatArrayKlass::make(klass);
}
)
return ciObjArrayKlass::make(klass, true);
} else {
ciKlass* klass = element_type->as_klass();
if (null_free && klass->is_loaded()) {
GUARDED_VM_ENTRY(
EXCEPTION_CONTEXT;
Klass* ak = InlineKlass::cast(klass->get_Klass())->null_free_inline_array_klass(THREAD);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
} else if (ak != NULL && ak->is_flatArray_klass()) {
return ciFlatArrayKlass::make(klass);
}
)
}
return ciObjArrayKlass::make(klass, null_free);
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/hotspot/share/ci/ciArrayKlass.hpp
Expand Up @@ -59,11 +59,12 @@ class ciArrayKlass : public ciKlass {
// The one-level type of the array elements.
virtual ciKlass* element_klass() { return NULL; }

static ciArrayKlass* make(ciType* element_type);
static ciArrayKlass* make(ciKlass* klass, bool null_free);
static ciArrayKlass* make(ciType* klass, bool null_free = false);

int array_header_in_bytes();
ciInstance* component_mirror_instance() const;

virtual bool is_elem_null_free() const { return false; }
};

#endif // SHARE_CI_CIARRAYKLASS_HPP
22 changes: 5 additions & 17 deletions src/hotspot/share/ci/ciField.cpp
Expand Up @@ -98,12 +98,7 @@ ciField::ciField(ciInstanceKlass* klass, int index) :
bool ignore;
// This is not really a class reference; the index always refers to the
// field's type signature, as a symbol. Linkage checks do not apply.
ciType* type = ciEnv::current(THREAD)->get_klass_by_index(cpool, sig_index, ignore, klass);
if (signature->is_Q_signature()) {
_type = ciEnv::current(THREAD)->make_null_free_wrapper(type);
} else {
_type = type;
}
_type = ciEnv::current(THREAD)->get_klass_by_index(cpool, sig_index, ignore, klass);
} else {
_type = ciType::make(field_type);
}
Expand Down Expand Up @@ -381,12 +376,6 @@ ciType* ciField::compute_type() {

ciType* ciField::compute_type_impl() {
ciKlass* type = CURRENT_ENV->get_klass_by_name_impl(_holder, constantPoolHandle(), _signature, false);
ciType* rtype;
if (_signature->is_Q_signature()) {
rtype = CURRENT_ENV->make_null_free_wrapper(type);
} else {
rtype = type;
}
if (!type->is_primitive_type() && is_shared()) {
// We must not cache a pointer to an unshared type, in a shared field.
bool type_is_also_shared = false;
Expand All @@ -398,12 +387,11 @@ ciType* ciField::compute_type_impl() {
// Currently there is no 'shared' query for array types.
type_is_also_shared = !ciObjectFactory::is_initialized();
}
if (!type_is_also_shared) {
return rtype; // Bummer.
}
if (!type_is_also_shared)
return type; // Bummer.
}
_type = rtype;
return rtype;
_type = type;
return type;
}


Expand Down
2 changes: 2 additions & 0 deletions src/hotspot/share/ci/ciFlatArrayKlass.hpp
Expand Up @@ -84,6 +84,8 @@ class ciFlatArrayKlass : public ciArrayKlass {
virtual bool can_be_inline_array_klass() {
return true;
}

virtual bool is_elem_null_free() const { return true; }
};


Expand Down

0 comments on commit 477ecf5

Please sign in to comment.