Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8235914: [lworld] Profile acmp bytecode #185

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -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