Skip to content
Permalink
Browse files
First set of changes to initiate the transition to the L/Q model
  • Loading branch information
fparain committed May 10, 2021
1 parent 4de6a48 commit adff6884c8647e6263127e2616d32da8c569672e
Showing with 148 additions and 66 deletions.
  1. +1 −1 src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp
  2. +6 −6 src/hotspot/cpu/x86/macroAssembler_x86.cpp
  3. +2 −2 src/hotspot/cpu/x86/macroAssembler_x86.hpp
  4. +8 −8 src/hotspot/cpu/x86/templateTable_x86.cpp
  5. +2 −1 src/hotspot/share/c1/c1_Canonicalizer.cpp
  6. +14 −14 src/hotspot/share/c1/c1_GraphBuilder.cpp
  7. +1 −1 src/hotspot/share/c1/c1_LIR.cpp
  8. +2 −2 src/hotspot/share/c1/c1_LIRGenerator.cpp
  9. +2 −0 src/hotspot/share/ci/ciClassList.hpp
  10. +1 −1 src/hotspot/share/ci/ciEnv.cpp
  11. +5 −1 src/hotspot/share/ci/ciEnv.hpp
  12. +23 −5 src/hotspot/share/ci/ciField.cpp
  13. +2 −0 src/hotspot/share/ci/ciField.hpp
  14. +5 −0 src/hotspot/share/ci/ciMetadata.hpp
  15. +6 −0 src/hotspot/share/ci/ciObjectFactory.cpp
  16. +2 −0 src/hotspot/share/ci/ciObjectFactory.hpp
  17. +4 −1 src/hotspot/share/ci/ciSignature.cpp
  18. +1 −1 src/hotspot/share/ci/ciSignature.hpp
  19. +2 −2 src/hotspot/share/ci/ciStreams.cpp
  20. +1 −1 src/hotspot/share/ci/ciStreams.hpp
  21. +35 −0 src/hotspot/share/ci/ciType.hpp
  22. +1 −1 src/hotspot/share/ci/ciTypeFlow.cpp
  23. +1 −1 src/hotspot/share/classfile/classFileParser.cpp
  24. +1 −2 src/hotspot/share/classfile/systemDictionary.cpp
  25. +3 −2 src/hotspot/share/interpreter/interpreterRuntime.cpp
  26. +3 −3 src/hotspot/share/oops/cpCache.cpp
  27. +4 −4 src/hotspot/share/oops/cpCache.hpp
  28. +2 −2 src/hotspot/share/oops/instanceKlass.cpp
  29. +1 −1 src/hotspot/share/oops/instanceKlass.hpp
  30. +1 −1 src/hotspot/share/opto/parseHelper.cpp
  31. +4 −0 src/hotspot/share/runtime/signature.hpp
  32. +1 −1 src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
  33. +1 −1 test/hotspot/jtreg/runtime/valhalla/inlinetypes/InlineTypesTest.java
@@ -532,7 +532,7 @@ 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()) {
if (InlineTypeReturnedAsFields && return_type->is_inlinetype() && return_type->is_null_free()) {
ciInlineKlass* vk = return_type->as_inline_klass();
if (vk->can_be_returned_as_fields()) {
#ifndef _LP64
@@ -2739,20 +2739,20 @@ void MacroAssembler::test_klass_is_empty_inline_type(Register klass, Register te
jcc(Assembler::notZero, is_empty_inline_type);
}

void MacroAssembler::test_field_is_inline_type(Register flags, Register temp_reg, Label& is_inline_type) {
void MacroAssembler::test_field_is_null_free_inline_type(Register flags, Register temp_reg, Label& is_null_free_inline_type) {
movl(temp_reg, flags);
shrl(temp_reg, ConstantPoolCacheEntry::is_inline_type_shift);
shrl(temp_reg, ConstantPoolCacheEntry::is_null_free_inline_type_shift);
andl(temp_reg, 0x1);
testl(temp_reg, temp_reg);
jcc(Assembler::notZero, is_inline_type);
jcc(Assembler::notZero, is_null_free_inline_type);
}

void MacroAssembler::test_field_is_not_inline_type(Register flags, Register temp_reg, Label& not_inline_type) {
void MacroAssembler::test_field_is_not_null_free_inline_type(Register flags, Register temp_reg, Label& not_null_free_inline_type) {
movl(temp_reg, flags);
shrl(temp_reg, ConstantPoolCacheEntry::is_inline_type_shift);
shrl(temp_reg, ConstantPoolCacheEntry::is_null_free_inline_type_shift);
andl(temp_reg, 0x1);
testl(temp_reg, temp_reg);
jcc(Assembler::zero, not_inline_type);
jcc(Assembler::zero, not_null_free_inline_type);
}

void MacroAssembler::test_field_is_inlined(Register flags, Register temp_reg, Label& is_inlined) {
@@ -116,8 +116,8 @@ class MacroAssembler: public Assembler {
// get_default_value_oop with extra assertion for empty inline klass
void get_empty_inline_type_oop(Register inline_klass, Register temp_reg, Register obj);

void test_field_is_inline_type(Register flags, Register temp_reg, Label& is_inline);
void test_field_is_not_inline_type(Register flags, Register temp_reg, Label& not_inline);
void test_field_is_null_free_inline_type(Register flags, Register temp_reg, Label& is_null_free);
void test_field_is_not_null_free_inline_type(Register flags, Register temp_reg, Label& not_null_free);
void test_field_is_inlined(Register flags, Register temp_reg, Label& is_inlined);

// Check oops for special arrays, i.e. flattened and/or null-free
@@ -3011,14 +3011,14 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr
} else {
if (is_static) {
__ load_heap_oop(rax, field);
Label is_inline_type, uninitialized;
Label is_null_free_inline_type, uninitialized;
// Issue below if the static field has not been initialized yet
__ test_field_is_inline_type(flags2, rscratch1, is_inline_type);
// field is not an inline type
__ test_field_is_null_free_inline_type(flags2, rscratch1, is_null_free_inline_type);
// field is not a null free inline type
__ push(atos);
__ jmp(Done);
// field is an inline type, must not return null even if uninitialized
__ bind(is_inline_type);
// field is a null free inline type, must not return null even if uninitialized
__ bind(is_null_free_inline_type);
__ testptr(rax, rax);
__ jcc(Assembler::zero, uninitialized);
__ push(atos);
@@ -3043,7 +3043,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr
__ jmp(Done);
} else {
Label is_inlined, nonnull, is_inline_type, rewrite_inline;
__ test_field_is_inline_type(flags2, rscratch1, is_inline_type);
__ test_field_is_null_free_inline_type(flags2, rscratch1, is_inline_type);
// field is not an inline type
pop_and_check_object(obj);
__ load_heap_oop(rax, field);
@@ -3392,14 +3392,14 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri
__ pop(atos);
if (is_static) {
Label is_inline_type;
__ test_field_is_not_inline_type(flags2, rscratch1, is_inline_type);
__ test_field_is_not_null_free_inline_type(flags2, rscratch1, is_inline_type);
__ null_check(rax);
__ bind(is_inline_type);
do_oop_store(_masm, field, rax);
__ jmp(Done);
} else {
Label is_inline_type, is_inlined, rewrite_not_inline, rewrite_inline;
__ test_field_is_inline_type(flags2, rscratch1, is_inline_type);
__ test_field_is_null_free_inline_type(flags2, rscratch1, is_inline_type);
// Not an inline type
pop_and_check_object(obj);
// Store into the field
@@ -669,7 +669,8 @@ void Canonicalizer::do_CheckCast (CheckCast* x) {
}
}
// checkcast of null returns null for non-inline klasses
if (!x->klass()->is_inlinetype() && obj->as_Constant() && obj->type()->as_ObjectType()->constant_value()->is_null_object()) {
if (!x->klass()->is_inlinetype() && x->is_null_free()
&& obj->as_Constant() && obj->type()->as_ObjectType()->constant_value()->is_null_object()) {
set_canonical(obj);
}
}
@@ -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()->as_inline_klass()->is_empty()) {
} else if (field_type == T_INLINE_TYPE && field->type()->is_null_free() && field->type()->unwrap()->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()->as_inline_klass()->default_instance()));
constant = new Constant(new InstanceConstant(field->type()->unwrap()->as_inline_klass()->default_instance()));
}
if (constant != NULL) {
push(type, append(constant));
@@ -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()->as_inline_klass()->is_empty()) {
if (field_type == T_INLINE_TYPE && field->type()->unwrap()->as_inline_klass()->is_empty()) {
// Storing to a field of an empty inline type. Ignore.
break;
}
@@ -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()->as_inline_klass()->is_empty()) {
if (field_type == T_INLINE_TYPE && field->type()->is_null_free() && field->type()->unwrap()->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()->as_inline_klass()->default_instance()));
constant = new Constant(new InstanceConstant(field->type()->unwrap()->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()) {
// Non-flattened inline type field. Replace null by the default value.
constant = new Constant(new InstanceConstant(field->type()->as_inline_klass()->default_instance()));
constant = new Constant(new InstanceConstant(field->type()->unwrap()->as_inline_klass()->default_instance()));
} else {
constant = make_constant(field_value, field);
}
@@ -1985,7 +1985,7 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
set_pending_field_access(dfa);
}
} else {
ciInlineKlass* inline_klass = field->type()->as_inline_klass();
ciInlineKlass* inline_klass = field->type()->unwrap()->as_inline_klass();
scope()->set_wrote_final();
scope()->set_wrote_fields();
bool need_membar = false;
@@ -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()->as_inline_klass()->is_empty()) {
if (field_type == T_INLINE_TYPE && field->type()->is_null_free() && field->type()->unwrap()->as_inline_klass()->is_empty()) {
// Storing to a field of an empty inline type. Ignore.
null_check(obj);
} else if (!field->is_flattened()) {
@@ -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()->as_inline_klass();
ciInlineKlass* inline_klass = field->type()->unwrap()->as_inline_klass();
copy_inline_content(inline_klass, val, inline_klass->first_field_offset(), obj, offset, state_before, field);
}
break;
@@ -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()->as_inline_klass();
ciInlineKlass* vk = field_modify->type()->unwrap()->as_inline_klass();
if (!vk->is_empty()) {
copy_inline_content(vk, val, vk->first_field_offset(), new_instance, offset_modify, state_before, field_modify);
}
@@ -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_inlinetype());
declared_signature->return_type()->is_null_free());
// push result
append_split(result);

@@ -2526,7 +2526,7 @@ void GraphBuilder::new_type_array() {
void GraphBuilder::new_object_array() {
bool will_link;
ciKlass* klass = stream()->get_klass(will_link);
bool null_free = stream()->is_inline_klass();
bool null_free = stream()->has_Q_signature();
ValueStack* state_before = !klass->is_loaded() || PatchALot ? copy_state_before() : copy_state_exhandling();
NewArray* n = new NewObjectArray(klass, ipop(), state_before, null_free);
apush(append_split(n));
@@ -2553,7 +2553,7 @@ bool GraphBuilder::direct_compare(ciKlass* k) {
void GraphBuilder::check_cast(int klass_index) {
bool will_link;
ciKlass* klass = stream()->get_klass(will_link);
bool null_free = stream()->is_inline_klass();
bool null_free = stream()->has_Q_signature();
ValueStack* state_before = !klass->is_loaded() || PatchALot ? copy_state_before() : copy_state_for_exception();
CheckCast* c = new CheckCast(klass, apop(), state_before, null_free);
apush(append_split(c));
@@ -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_inlinetype()));
state->store_local(idx, new Local(type, vt, idx, false, type->is_null_free()));
idx += type->size();
}

@@ -1074,7 +1074,7 @@ void LIR_OpJavaCall::emit_code(LIR_Assembler* masm) {

bool LIR_OpJavaCall::maybe_return_as_fields(ciInlineKlass** vk_ret) const {
if (InlineTypeReturnedAsFields &&
(method()->signature()->returns_inline_type() ||
(method()->signature()->returns_null_free_inline_type() ||
method()->is_method_handle_intrinsic())) {
ciType* return_type = method()->return_type();
if (return_type->is_inlinetype()) {
@@ -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()->is_loaded();
bool could_be_null = x->is_static() && x->as_LoadField() != NULL && !field->type()->unwrap()->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");
@@ -2137,7 +2137,7 @@ void LIRGenerator::do_LoadField(LoadField* x) {
if (field->signature()->is_Q_signature()) {
// Load from non-flattened inline type field requires
// a null check to replace null with the default value.
ciInlineKlass* inline_klass = field->type()->as_inline_klass();
ciInlineKlass* inline_klass = field->type()->unwrap()->as_inline_klass();
assert(inline_klass->is_loaded(), "field klass must be loaded");

ciInstanceKlass* holder = field->holder();
@@ -60,6 +60,7 @@ class ciMethod;
class ciMethodData;
class ciReceiverTypeData; // part of ciMethodData
class ciType;
class ciWrapper;
class ciReturnAddress;
class ciKlass;
class ciInstanceKlass;
@@ -116,6 +117,7 @@ friend class ciReplay; \
friend class ciTypeArray; \
friend class ciType; \
friend class ciReturnAddress; \
friend class ciWrapper; \
friend class ciKlass; \
friend class ciInstanceKlass; \
friend class ciInlineKlass; \
@@ -602,7 +602,7 @@ ciKlass* ciEnv::get_klass_by_index(const constantPoolHandle& cpool,
// ciEnv::is_inline_klass
//
// Check if the klass is an inline klass.
bool ciEnv::is_inline_klass(const constantPoolHandle& cpool, int index) {
bool ciEnv::has_Q_signature(const constantPoolHandle& cpool, int index) {
GUARDED_VM_ENTRY(return cpool->klass_name_at(index)->is_Q_signature();)
}

@@ -135,7 +135,7 @@ class ciEnv : StackObj {
ciMethod* get_method_by_index(const constantPoolHandle& cpool,
int method_index, Bytecodes::Code bc,
ciInstanceKlass* loading_klass);
bool is_inline_klass(const constantPoolHandle& cpool,
bool has_Q_signature(const constantPoolHandle& cpool,
int klass_index);

// Implementation methods for loading and constant pool access.
@@ -472,6 +472,10 @@ class ciEnv : StackObj {
void dump_replay_data(outputStream* out);
void dump_replay_data_unsafe(outputStream* out);
void dump_compile_data(outputStream* out);

ciWrapper* make_null_free_wrapper(ciType* type) {
return _factory->make_null_free_wrapper(type);
}
};

#endif // SHARE_CI_CIENV_HPP
@@ -98,13 +98,21 @@ 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.
_type = ciEnv::current(THREAD)->get_klass_by_index(cpool, sig_index, ignore, klass);
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;
}
} else {
_type = ciType::make(field_type);
}

_name = (ciSymbol*)ciEnv::current(THREAD)->get_symbol(name);

// this is needed if the field class is not yet loaded.
_is_null_free = _signature->is_Q_signature();

// Get the field's declared holder.
//
// Note: we actually create a ciInstanceKlass for this klass,
@@ -237,6 +245,7 @@ ciField::ciField(ciField* field, ciInstanceKlass* holder, int offset, bool is_fi
_constant_value = field->_constant_value;
assert(!field->is_flattened(), "field must not be flattened");
_is_flattened = false;
_is_null_free = field->is_null_free();
}

static bool trust_final_non_static_fields(ciInstanceKlass* holder) {
@@ -287,6 +296,7 @@ void ciField::initialize_from(fieldDescriptor* fd) {
assert(field_holder != NULL, "null field_holder");
_holder = CURRENT_ENV->get_instance_klass(field_holder);
_is_flattened = fd->is_inlined();
_is_null_free = fd->signature()->is_Q_signature();

// Check to see if the field is constant.
Klass* k = _holder->get_Klass();
@@ -371,6 +381,12 @@ 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;
@@ -382,11 +398,12 @@ 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 type; // Bummer.
if (!type_is_also_shared) {
return rtype; // Bummer.
}
}
_type = type;
return type;
_type = rtype;
return rtype;
}


@@ -484,6 +501,7 @@ void ciField::print() {
_constant_value.print();
}
tty->print(" is_flattened=%s", bool_to_str(_is_flattened));
tty->print(" is_null_free=%s", bool_to_str(_is_null_free));
tty->print(">");
}

@@ -50,6 +50,7 @@ class ciField : public ResourceObj {
int _offset;
bool _is_constant;
bool _is_flattened;
bool _is_null_free;
ciMethod* _known_to_link_with_put;
ciInstanceKlass* _known_to_link_with_get;
ciConstant _constant_value;
@@ -177,6 +178,7 @@ class ciField : public ResourceObj {
bool is_volatile () const { return flags().is_volatile(); }
bool is_transient () const { return flags().is_transient(); }
bool is_flattened () const { return _is_flattened; }
bool is_null_free () const { return _is_null_free; }

// The field is modified outside of instance initializer methods
// (or class/initializer methods if the field is static).

0 comments on commit adff688

Please sign in to comment.