Skip to content
Permalink
Browse files
8235914: [lworld] Profile acmp bytecode
Reviewed-by: thartmann
  • Loading branch information
rwestrel committed Oct 12, 2020
1 parent e815214 commit 378279c95e4e725bf666e65cb0d4ff220e3373d6
Show file tree
Hide file tree
Showing 44 changed files with 1,202 additions and 128 deletions.
@@ -3069,6 +3069,9 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
COMMENT("} emit_profile_type");
}

void LIR_Assembler::emit_profile_inline_type(LIR_OpProfileInlineType* op) {
Unimplemented();
}

void LIR_Assembler::align_backward_branch_target() {
}
@@ -2563,6 +2563,10 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
fatal("Type profiling not implemented on this platform");
}

void LIR_Assembler::emit_profile_inline_type(LIR_OpProfileInlineType* op) {
Unimplemented();
}

void LIR_Assembler::emit_delay(LIR_OpDelay*) {
Unimplemented();
}
@@ -3199,6 +3199,9 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
__ bind(Ldone);
}

void LIR_Assembler::emit_profile_inline_type(LIR_OpProfileInlineType* op) {
Unimplemented();
}

void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) {
assert(op->crc()->is_single_cpu(), "crc must be register");
@@ -3088,6 +3088,10 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
}
}

void LIR_Assembler::emit_profile_inline_type(LIR_OpProfileInlineType* op) {
Unimplemented();
}

void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) {
assert(op->crc()->is_single_cpu(), "crc must be register");
assert(op->val()->is_single_cpu(), "byte value must be register");
@@ -3982,6 +3982,26 @@ void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
}
}

void LIR_Assembler::emit_profile_inline_type(LIR_OpProfileInlineType* op) {
Register obj = op->obj()->as_register();
Register tmp = op->tmp()->as_pointer_register();
Address mdo_addr = as_Address(op->mdp()->as_address_ptr());
bool not_null = op->not_null();
int flag = op->flag();

Label not_inline_type;
if (!not_null) {
__ testptr(obj, obj);
__ jccb(Assembler::zero, not_inline_type);
}

__ test_oop_is_not_inline_type(obj, tmp, not_inline_type);

__ orb(mdo_addr, flag);

__ bind(not_inline_type);
}

void LIR_Assembler::emit_delay(LIR_OpDelay*) {
Unimplemented();
}
@@ -1695,7 +1695,7 @@ void InterpreterMacroAssembler::profile_taken_branch(Register mdp,
}


void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) {
void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp, bool acmp) {
if (ProfileInterpreter) {
Label profile_continue;

@@ -1707,7 +1707,7 @@ void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) {

// The method data pointer needs to be updated to correspond to
// the next bytecode
update_mdp_by_constant(mdp, in_bytes(BranchData::branch_data_size()));
update_mdp_by_constant(mdp, acmp ? in_bytes(ACmpData::acmp_data_size()): in_bytes(BranchData::branch_data_size()));
bind(profile_continue);
}
}
@@ -2131,6 +2131,37 @@ void InterpreterMacroAssembler::profile_element(Register mdp,
}
}

void InterpreterMacroAssembler::profile_acmp(Register mdp,
Register left,
Register right,
Register tmp) {
if (ProfileInterpreter) {
Label profile_continue;

// If no method data exists, go to profile_continue.
test_method_data_pointer(mdp, profile_continue);

mov(tmp, left);
profile_obj_type(tmp, Address(mdp, in_bytes(ACmpData::left_offset())));

Label left_not_inline_type;
test_oop_is_not_inline_type(left, tmp, left_not_inline_type);
set_mdp_flag_at(mdp, ACmpData::left_inline_type_byte_constant());
bind(left_not_inline_type);

mov(tmp, right);
profile_obj_type(tmp, Address(mdp, in_bytes(ACmpData::right_offset())));

Label right_not_inline_type;
test_oop_is_not_inline_type(right, tmp, right_not_inline_type);
set_mdp_flag_at(mdp, ACmpData::right_inline_type_byte_constant());
bind(right_not_inline_type);

bind(profile_continue);
}
}


void InterpreterMacroAssembler::_interp_verify_oop(Register reg, TosState state, const char* file, int line) {
if (state == atos) {
MacroAssembler::_verify_oop(reg, "broken oop", file, line);
@@ -286,7 +286,7 @@ class InterpreterMacroAssembler: public MacroAssembler {
void update_mdp_for_ret(Register return_bci);

void profile_taken_branch(Register mdp, Register bumped_count);
void profile_not_taken_branch(Register mdp);
void profile_not_taken_branch(Register mdp, bool acmp = false);
void profile_call(Register mdp);
void profile_final_call(Register mdp);
void profile_virtual_call(Register receiver, Register mdp,
@@ -301,6 +301,7 @@ class InterpreterMacroAssembler: public MacroAssembler {
Register scratch2);
void profile_array(Register mdp, Register array, Register tmp);
void profile_element(Register mdp, Register element, Register tmp);
void profile_acmp(Register mdp, Register left, Register right, Register tmp);

// Debugging
// only if +VerifyOops && state == atos
@@ -2616,6 +2616,16 @@ void MacroAssembler::test_klass_is_inline_type(Register klass, Register temp_reg
jcc(Assembler::notZero, is_inline_type);
}

void MacroAssembler::test_oop_is_not_inline_type(Register object, Register tmp, Label& not_inline_type) {
testptr(object, object);
jcc(Assembler::equal, not_inline_type);
const int is_inline_type_mask = markWord::always_locked_pattern;
movptr(tmp, Address(object, oopDesc::mark_offset_in_bytes()));
andptr(tmp, is_inline_type_mask);
cmpptr(tmp, is_inline_type_mask);
jcc(Assembler::notEqual, not_inline_type);
}

void MacroAssembler::test_klass_is_empty_inline_type(Register klass, Register temp_reg, Label& is_empty_inline_type) {
#ifdef ASSERT
{
@@ -104,6 +104,7 @@ class MacroAssembler: public Assembler {
// valueKlass queries, kills temp_reg
void test_klass_is_inline_type(Register klass, Register temp_reg, Label& is_inline_type);
void test_klass_is_empty_inline_type(Register klass, Register temp_reg, Label& is_empty_inline_type);
void test_oop_is_not_inline_type(Register object, Register tmp, Label& not_inline_type);

// Get the default value oop for the given InlineKlass
void get_default_value_oop(Register inline_klass, Register temp_reg, Register obj);
@@ -2482,24 +2482,22 @@ void TemplateTable::if_acmp(Condition cc) {
Label taken, not_taken;
__ pop_ptr(rdx);

__ profile_acmp(rbx, rdx, rax, rcx);

const int is_inline_type_mask = markWord::always_locked_pattern;
if (EnableValhalla) {
__ cmpoop(rdx, rax);
__ jcc(Assembler::equal, (cc == equal) ? taken : not_taken);

// might be substitutable, test if either rax or rdx is null
__ movptr(rbx, rdx);
__ andptr(rbx, rax);
__ testptr(rbx, rbx);
__ testptr(rdx, rax);
__ jcc(Assembler::zero, (cc == equal) ? not_taken : taken);

// and both are values ?
__ movptr(rbx, Address(rdx, oopDesc::mark_offset_in_bytes()));
__ andptr(rbx, Address(rax, oopDesc::mark_offset_in_bytes()));
__ andptr(rbx, is_inline_type_mask);
__ movptr(rcx, Address(rax, oopDesc::mark_offset_in_bytes()));
__ andptr(rbx, is_inline_type_mask);
__ andptr(rbx, rcx);
__ cmpl(rbx, is_inline_type_mask);
__ cmpptr(rbx, is_inline_type_mask);
__ jcc(Assembler::notEqual, (cc == equal) ? not_taken : taken);

// same value klass ?
@@ -2522,7 +2520,7 @@ void TemplateTable::if_acmp(Condition cc) {
__ bind(taken);
branch(false, false);
__ bind(not_taken);
__ profile_not_taken_branch(rax);
__ profile_not_taken_branch(rax, true);
}

void TemplateTable::invoke_is_substitutable(Register aobj, Register bobj,
@@ -1055,6 +1055,7 @@ void Canonicalizer::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {}
void Canonicalizer::do_ProfileCall(ProfileCall* x) {}
void Canonicalizer::do_ProfileReturnType(ProfileReturnType* x) {}
void Canonicalizer::do_ProfileInvoke(ProfileInvoke* x) {}
void Canonicalizer::do_ProfileACmpTypes(ProfileACmpTypes* x) {}
void Canonicalizer::do_RuntimeCall(RuntimeCall* x) {}
void Canonicalizer::do_RangeCheckPredicate(RangeCheckPredicate* x) {}
#ifdef ASSERT
@@ -110,6 +110,7 @@ class Canonicalizer: InstructionVisitor {
virtual void do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x);
virtual void do_ProfileCall (ProfileCall* x);
virtual void do_ProfileReturnType (ProfileReturnType* x);
virtual void do_ProfileACmpTypes(ProfileACmpTypes* x);
virtual void do_ProfileInvoke (ProfileInvoke* x);
virtual void do_RuntimeCall (RuntimeCall* x);
virtual void do_MemBar (MemBar* x);
@@ -1353,6 +1353,11 @@ void GraphBuilder::if_node(Value x, If::Condition cond, Value y, ValueStack* sta
}
}
}
if ((stream()->cur_bc() == Bytecodes::_if_acmpeq || stream()->cur_bc() == Bytecodes::_if_acmpne) &&
is_profiling() && profile_branches()) {
compilation()->set_would_profile(true);
append(new ProfileACmpTypes(method(), bci(), x, y));
}

// In case of loop invariant code motion or predicate insertion
// before the body of a loop the state is needed
@@ -108,6 +108,7 @@ class UnsafePutObject;
class UnsafeGetAndSetObject;
class ProfileCall;
class ProfileReturnType;
class ProfileACmpTypes;
class ProfileInvoke;
class RuntimeCall;
class MemBar;
@@ -210,6 +211,7 @@ class InstructionVisitor: public StackObj {
virtual void do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) = 0;
virtual void do_ProfileCall (ProfileCall* x) = 0;
virtual void do_ProfileReturnType (ProfileReturnType* x) = 0;
virtual void do_ProfileACmpTypes(ProfileACmpTypes* x) = 0;
virtual void do_ProfileInvoke (ProfileInvoke* x) = 0;
virtual void do_RuntimeCall (RuntimeCall* x) = 0;
virtual void do_MemBar (MemBar* x) = 0;
@@ -2681,7 +2683,7 @@ LEAF(ProfileReturnType, Instruction)
, _ret(ret)
{
set_needs_null_check(true);
// The ProfileType has side-effects and must occur precisely where located
// The ProfileReturnType has side-effects and must occur precisely where located
pin();
}

@@ -2697,6 +2699,48 @@ LEAF(ProfileReturnType, Instruction)
}
};

LEAF(ProfileACmpTypes, Instruction)
private:
ciMethod* _method;
int _bci;
Value _left;
Value _right;
bool _left_maybe_null;
bool _right_maybe_null;

public:
ProfileACmpTypes(ciMethod* method, int bci, Value left, Value right)
: Instruction(voidType)
, _method(method)
, _bci(bci)
, _left(left)
, _right(right)
{
// The ProfileACmp has side-effects and must occur precisely where located
pin();
_left_maybe_null = true;
_right_maybe_null = true;
}

ciMethod* method() const { return _method; }
int bci() const { return _bci; }
Value left() const { return _left; }
Value right() const { return _right; }
bool left_maybe_null() const { return _left_maybe_null; }
bool right_maybe_null() const { return _right_maybe_null; }
void set_left_maybe_null(bool v) { _left_maybe_null = v; }
void set_right_maybe_null(bool v) { _right_maybe_null = v; }

virtual void input_values_do(ValueVisitor* f) {
if (_left != NULL) {
f->visit(&_left);
}
if (_right != NULL) {
f->visit(&_right);
}
}
};

// Call some C runtime function that doesn't safepoint,
// optionally passing the current thread as the first argument.
LEAF(RuntimeCall, Instruction)
@@ -916,13 +916,21 @@ void InstructionPrinter::do_ProfileReturnType(ProfileReturnType* x) {
output()->print(" %s.%s", x->method()->holder()->name()->as_utf8(), x->method()->name()->as_utf8());
output()->put(')');
}

void InstructionPrinter::do_ProfileInvoke(ProfileInvoke* x) {
output()->print("profile_invoke ");
output()->print(" %s.%s", x->inlinee()->holder()->name()->as_utf8(), x->inlinee()->name()->as_utf8());
output()->put(')');

}

void InstructionPrinter::do_ProfileACmpTypes(ProfileACmpTypes* x) {
output()->print("profile acmp types ");
print_value(x->left());
output()->print(", ");
print_value(x->right());
}

void InstructionPrinter::do_RuntimeCall(RuntimeCall* x) {
output()->print("call_rt %s(", x->entry_name());
for (int i = 0; i < x->number_of_arguments(); i++) {
@@ -134,6 +134,7 @@ class InstructionPrinter: public InstructionVisitor {
virtual void do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x);
virtual void do_ProfileCall (ProfileCall* x);
virtual void do_ProfileReturnType (ProfileReturnType* x);
virtual void do_ProfileACmpTypes(ProfileACmpTypes* x);
virtual void do_ProfileInvoke (ProfileInvoke* x);
virtual void do_RuntimeCall (RuntimeCall* x);
virtual void do_MemBar (MemBar* x);
@@ -974,7 +974,18 @@ void LIR_OpVisitState::visit(LIR_Op* op) {
do_temp(opProfileType->_tmp);
break;
}
default:

// LIR_OpProfileInlineType:
case lir_profile_inline_type: {
assert(op->as_OpProfileInlineType() != NULL, "must be");
LIR_OpProfileInlineType* opProfileInlineType = (LIR_OpProfileInlineType*)op;

do_input(opProfileInlineType->_mdp); do_temp(opProfileInlineType->_mdp);
do_input(opProfileInlineType->_obj);
do_temp(opProfileInlineType->_tmp);
break;
}
default:
op->visit(this);
}
}
@@ -1191,6 +1202,10 @@ void LIR_OpProfileType::emit_code(LIR_Assembler* masm) {
masm->emit_profile_type(this);
}

void LIR_OpProfileInlineType::emit_code(LIR_Assembler* masm) {
masm->emit_profile_inline_type(this);
}

// LIR_List
LIR_List::LIR_List(Compilation* compilation, BlockBegin* block)
: _operations(8)
@@ -1877,6 +1892,8 @@ const char * LIR_Op::name() const {
case lir_profile_call: s = "profile_call"; break;
// LIR_OpProfileType
case lir_profile_type: s = "profile_type"; break;
// LIR_OpProfileInlineType
case lir_profile_inline_type: s = "profile_inline_type"; break;
// LIR_OpAssert
#ifdef ASSERT
case lir_assert: s = "assert"; break;
@@ -2213,6 +2230,14 @@ void LIR_OpProfileType::print_instr(outputStream* out) const {
tmp()->print(out); out->print(" ");
}

// LIR_OpProfileInlineType
void LIR_OpProfileInlineType::print_instr(outputStream* out) const {
out->print(" flag = %x ", flag());
mdp()->print(out); out->print(" ");
obj()->print(out); out->print(" ");
tmp()->print(out); out->print(" ");
}

#endif // PRODUCT

// Implementation of LIR_InsertionBuffer

0 comments on commit 378279c

Please sign in to comment.