< prev index next > src/hotspot/share/c1/c1_Instruction.hpp
Print this page
class NewInstance;
class NewArray;
class NewTypeArray;
class NewObjectArray;
class NewMultiArray;
+ class Deoptimize;
class TypeCheck;
class CheckCast;
class InstanceOf;
class AccessMonitor;
class MonitorEnter;
class UnsafeGet;
class UnsafePut;
class UnsafeGetAndSet;
class ProfileCall;
class ProfileReturnType;
+ class ProfileACmpTypes;
class ProfileInvoke;
class RuntimeCall;
class MemBar;
class RangeCheckPredicate;
#ifdef ASSERT
virtual void do_UnsafeGet (UnsafeGet* x) = 0;
virtual void do_UnsafePut (UnsafePut* x) = 0;
virtual void do_UnsafeGetAndSet(UnsafeGetAndSet* 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;
virtual void do_RangeCheckPredicate(RangeCheckPredicate* x) = 0;
#ifdef ASSERT
//
// Note: This hash functions affect the performance
// of ValueMap - make changes carefully!
#define HASH1(x1 ) ((intx)(x1))
- #define HASH2(x1, x2 ) ((HASH1(x1 ) << 7) ^ HASH1(x2))
- #define HASH3(x1, x2, x3 ) ((HASH2(x1, x2 ) << 7) ^ HASH1(x3))
- #define HASH4(x1, x2, x3, x4) ((HASH3(x1, x2, x3) << 7) ^ HASH1(x4))
+ #define HASH2(x1, x2 ) ((HASH1(x1 ) << 7) ^ HASH1(x2))
+ #define HASH3(x1, x2, x3 ) ((HASH2(x1, x2 ) << 7) ^ HASH1(x3))
+ #define HASH4(x1, x2, x3, x4) ((HASH3(x1, x2, x3 ) << 7) ^ HASH1(x4))
+ #define HASH5(x1, x2, x3, x4, x5) ((HASH4(x1, x2, x3, x4) << 7) ^ HASH1(x5))
// The following macros are used to implement instruction-specific hashing.
// By default, each instruction implements hash() and is_equal(Value), used
// for value numbering/common subexpression elimination. The default imple-
if (f2 != _v->f2) return false; \
if (f3 != _v->f3) return false; \
return true; \
} \
+ #define HASHING4(class_name, enabled, f1, f2, f3, f4) \
+ virtual intx hash() const { \
+ return (enabled) ? HASH5(name(), f1, f2, f3, f4) : 0; \
+ } \
+ virtual bool is_equal(Value v) const { \
+ if (!(enabled) ) return false; \
+ class_name* _v = v->as_##class_name(); \
+ if (_v == nullptr ) return false; \
+ if (f1 != _v->f1) return false; \
+ if (f2 != _v->f2) return false; \
+ if (f3 != _v->f3) return false; \
+ if (f4 != _v->f4) return false; \
+ return true; \
+ } \
+
// The mother of all instructions...
class Instruction: public CompilationResourceObj {
private:
ValueStack* _state_before; // Copy of state with input operands still on stack (or null)
ValueStack* _exception_state; // Copy of state for exception handling
XHandlers* _exception_handlers; // Flat list of exception handlers covering this instruction
friend class UseCountComputer;
+ friend class GraphBuilder;
void update_exception_state(ValueStack* state);
protected:
BlockBegin* _block; // Block that contains this instruction
static const int no_bci = -99;
enum InstructionFlag {
NeedsNullCheckFlag = 0,
+ NeverNullFlag, // For "Q" signatures
CanTrapFlag,
DirectCompareFlag,
IsEliminatedFlag,
IsSafepointFlag,
IsStaticFlag,
Instruction* subst() { return _subst == nullptr ? this : _subst->subst(); }
LIR_Opr operand() const { return _operand; }
void set_needs_null_check(bool f) { set_flag(NeedsNullCheckFlag, f); }
bool needs_null_check() const { return check_flag(NeedsNullCheckFlag); }
+ void set_null_free(bool f) { set_flag(NeverNullFlag, f); }
+ bool is_null_free() const { return check_flag(NeverNullFlag); }
bool is_linked() const { return check_flag(IsLinkedInBlockFlag); }
bool can_be_linked() { return as_Local() == nullptr && as_Phi() == nullptr; }
bool is_null_obj() { return as_Constant() != nullptr && type()->as_ObjectType()->constant_value()->is_null_object(); }
bool has_uses() const { return use_count() > 0; }
ValueStack* state_before() const { return _state_before; }
ValueStack* exception_state() const { return _exception_state; }
virtual bool needs_exception_state() const { return true; }
XHandlers* exception_handlers() const { return _exception_handlers; }
+ ciKlass* as_loaded_klass_or_null() const;
// manipulation
void pin(PinReason reason) { _pin_state |= reason; }
void pin() { _pin_state |= PinUnknown; }
// DANGEROUS: only used by EliminateStores
set_next(i);
i->set_next(n);
return _next;
}
+ bool is_loaded_flat_array() const;
+ bool maybe_flat_array();
+ bool maybe_null_free_array();
+
Instruction *insert_after_same_bci(Instruction *i) {
#ifndef PRODUCT
i->set_printable_bci(printable_bci());
#endif
return insert_after(i);
int _java_index; // the local index within the method to which the local belongs
bool _is_receiver; // if local variable holds the receiver: "this" for non-static methods
ciType* _declared_type;
public:
// creation
- Local(ciType* declared, ValueType* type, int index, bool receiver)
+ Local(ciType* declared, ValueType* type, int index, bool receiver, bool null_free)
: Instruction(type)
, _java_index(index)
, _is_receiver(receiver)
, _declared_type(declared)
{
+ set_null_free(null_free);
NOT_PRODUCT(set_printable_bci(-1));
}
// accessors
int java_index() const { return _java_index; }
LEAF(LoadField, AccessField)
public:
// creation
LoadField(Value obj, int offset, ciField* field, bool is_static,
- ValueStack* state_before, bool needs_patching)
+ ValueStack* state_before, bool needs_patching,
+ ciInlineKlass* inline_klass = nullptr, Value default_value = nullptr )
: AccessField(obj, offset, field, is_static, state_before, needs_patching)
- {}
+ {
+ set_null_free(field->is_null_free());
+ }
ciType* declared_type() const;
// generic; cannot be eliminated if needs patching or if volatile.
HASHING3(LoadField, !needs_patching() && !field()->is_volatile(), obj()->subst(), offset(), declared_type())
LEAF(StoreField, AccessField)
private:
Value _value;
+ ciField* _enclosing_field; // enclosing field (the flat one) for nested fields
public:
// creation
StoreField(Value obj, int offset, ciField* field, Value value, bool is_static,
- ValueStack* state_before, bool needs_patching)
- : AccessField(obj, offset, field, is_static, state_before, needs_patching)
- , _value(value)
- {
- set_flag(NeedsWriteBarrierFlag, as_ValueType(field_type())->is_object());
- ASSERT_VALUES
- pin();
- }
+ ValueStack* state_before, bool needs_patching);
// accessors
Value value() const { return _value; }
bool needs_write_barrier() const { return check_flag(NeedsWriteBarrierFlag); }
+ ciField* enclosing_field() const { return _enclosing_field; }
+ void set_enclosing_field(ciField* field) { _enclosing_field = field; }
// generic
virtual void input_values_do(ValueVisitor* f) { AccessField::input_values_do(f); f->visit(&_value); }
};
private:
Value _index;
Value _length;
BasicType _elt_type;
bool _mismatched;
+ ciMethod* _profiled_method;
+ int _profiled_bci;
public:
// creation
AccessIndexed(Value array, Value index, Value length, BasicType elt_type, ValueStack* state_before, bool mismatched)
: AccessArray(as_ValueType(elt_type), array, state_before)
, _index(index)
, _length(length)
, _elt_type(elt_type)
, _mismatched(mismatched)
+ , _profiled_method(nullptr), _profiled_bci(0)
{
set_flag(Instruction::NeedsRangeCheckFlag, true);
ASSERT_VALUES
}
void clear_length() { _length = nullptr; }
// perform elimination of range checks involving constants
bool compute_needs_range_check();
+ // Helpers for MethodData* profiling
+ void set_should_profile(bool value) { set_flag(ProfileMDOFlag, value); }
+ void set_profiled_method(ciMethod* method) { _profiled_method = method; }
+ void set_profiled_bci(int bci) { _profiled_bci = bci; }
+ bool should_profile() const { return check_flag(ProfileMDOFlag); }
+ ciMethod* profiled_method() const { return _profiled_method; }
+ int profiled_bci() const { return _profiled_bci; }
+
+
// generic
virtual void input_values_do(ValueVisitor* f) { AccessArray::input_values_do(f); f->visit(&_index); if (_length != nullptr) f->visit(&_length); }
};
+ class DelayedLoadIndexed;
LEAF(LoadIndexed, AccessIndexed)
private:
NullCheck* _explicit_null_check; // For explicit null check elimination
+ NewInstance* _vt;
+ DelayedLoadIndexed* _delayed;
public:
// creation
LoadIndexed(Value array, Value index, Value length, BasicType elt_type, ValueStack* state_before, bool mismatched = false)
: AccessIndexed(array, index, length, elt_type, state_before, mismatched)
- , _explicit_null_check(nullptr) {}
+ , _explicit_null_check(nullptr), _vt(nullptr), _delayed(nullptr) {}
// accessors
NullCheck* explicit_null_check() const { return _explicit_null_check; }
// setters
void set_explicit_null_check(NullCheck* check) { _explicit_null_check = check; }
ciType* exact_type() const;
ciType* declared_type() const;
+ NewInstance* vt() const { return _vt; }
+ void set_vt(NewInstance* vt) { _vt = vt; }
+
+ DelayedLoadIndexed* delayed() const { return _delayed; }
+ void set_delayed(DelayedLoadIndexed* delayed) { _delayed = delayed; }
+
// generic;
- HASHING3(LoadIndexed, true, elt_type(), array()->subst(), index()->subst())
+ HASHING4(LoadIndexed, delayed() == nullptr && !should_profile(), elt_type(), array()->subst(), index()->subst(), vt())
};
+ class DelayedLoadIndexed : public CompilationResourceObj {
+ private:
+ LoadIndexed* _load_instr;
+ ValueStack* _state_before;
+ ciField* _field;
+ int _offset;
+ public:
+ DelayedLoadIndexed(LoadIndexed* load, ValueStack* state_before)
+ : _load_instr(load)
+ , _state_before(state_before)
+ , _field(nullptr)
+ , _offset(0) { }
+
+ void update(ciField* field, int offset) {
+ _field = field;
+ _offset += offset;
+ }
+
+ LoadIndexed* load_instr() const { return _load_instr; }
+ ValueStack* state_before() const { return _state_before; }
+ ciField* field() const { return _field; }
+ int offset() const { return _offset; }
+ };
LEAF(StoreIndexed, AccessIndexed)
private:
Value _value;
- ciMethod* _profiled_method;
- int _profiled_bci;
bool _check_boolean;
public:
// creation
StoreIndexed(Value array, Value index, Value length, BasicType elt_type, Value value, ValueStack* state_before,
- bool check_boolean, bool mismatched = false)
- : AccessIndexed(array, index, length, elt_type, state_before, mismatched)
- , _value(value), _profiled_method(nullptr), _profiled_bci(0), _check_boolean(check_boolean)
- {
- set_flag(NeedsWriteBarrierFlag, (as_ValueType(elt_type)->is_object()));
- set_flag(NeedsStoreCheckFlag, (as_ValueType(elt_type)->is_object()));
- ASSERT_VALUES
- pin();
- }
+ bool check_boolean, bool mismatched = false);
// accessors
Value value() const { return _value; }
bool needs_write_barrier() const { return check_flag(NeedsWriteBarrierFlag); }
bool needs_store_check() const { return check_flag(NeedsStoreCheckFlag); }
bool check_boolean() const { return _check_boolean; }
- // Helpers for MethodData* profiling
- void set_should_profile(bool value) { set_flag(ProfileMDOFlag, value); }
- void set_profiled_method(ciMethod* method) { _profiled_method = method; }
- void set_profiled_bci(int bci) { _profiled_bci = bci; }
- bool should_profile() const { return check_flag(ProfileMDOFlag); }
- ciMethod* profiled_method() const { return _profiled_method; }
- int profiled_bci() const { return _profiled_bci; }
+
+ // Flattened array support
+ bool is_exact_flat_array_store() const;
// generic
virtual void input_values_do(ValueVisitor* f) { AccessIndexed::input_values_do(f); f->visit(&_value); }
};
LEAF(IfOp, Op2)
private:
Value _tval;
Value _fval;
+ bool _substitutability_check;
public:
// creation
- IfOp(Value x, Condition cond, Value y, Value tval, Value fval)
+ IfOp(Value x, Condition cond, Value y, Value tval, Value fval, ValueStack* state_before, bool substitutability_check)
: Op2(tval->type()->meet(fval->type()), (Bytecodes::Code)cond, x, y)
, _tval(tval)
, _fval(fval)
+ , _substitutability_check(substitutability_check)
{
ASSERT_VALUES
assert(tval->type()->tag() == fval->type()->tag(), "types must match");
+ set_state_before(state_before);
}
// accessors
virtual bool is_commutative() const;
Bytecodes::Code op() const { ShouldNotCallThis(); return Bytecodes::_illegal; }
Condition cond() const { return (Condition)Op2::op(); }
Value tval() const { return _tval; }
Value fval() const { return _fval; }
-
+ bool substitutability_check() const { return _substitutability_check; }
// generic
virtual void input_values_do(ValueVisitor* f) { Op2::input_values_do(f); f->visit(&_tval); f->visit(&_fval); }
};
LEAF(NewInstance, StateSplit)
private:
ciInstanceKlass* _klass;
bool _is_unresolved;
+ bool _needs_state_before;
public:
// creation
- NewInstance(ciInstanceKlass* klass, ValueStack* state_before, bool is_unresolved)
+ NewInstance(ciInstanceKlass* klass, ValueStack* state_before, bool is_unresolved, bool needs_state_before)
: StateSplit(instanceType, state_before)
- , _klass(klass), _is_unresolved(is_unresolved)
+ , _klass(klass), _is_unresolved(is_unresolved), _needs_state_before(needs_state_before)
{}
// accessors
ciInstanceKlass* klass() const { return _klass; }
bool is_unresolved() const { return _is_unresolved; }
+ bool needs_state_before() const { return _needs_state_before; }
virtual bool needs_exception_state() const { return false; }
// generic
virtual bool can_trap() const { return true; }
ciType* exact_type() const;
ciType* declared_type() const;
};
-
BASE(NewArray, StateSplit)
private:
Value _length;
public:
private:
ciKlass* _klass;
public:
// creation
- NewObjectArray(ciKlass* klass, Value length, ValueStack* state_before) : NewArray(length, state_before), _klass(klass) {}
+ NewObjectArray(ciKlass* klass, Value length, ValueStack* state_before)
+ : NewArray(length, state_before), _klass(klass) { }
// accessors
ciKlass* klass() const { return _klass; }
ciType* exact_type() const;
};
// get updated, and the value must not be traversed twice. Was bug
// - kbr 4/10/2001
StateSplit::input_values_do(f);
for (int i = 0; i < _dims->length(); i++) f->visit(_dims->adr_at(i));
}
+
+ ciType* exact_type() const;
};
BASE(TypeCheck, StateSplit)
private:
LEAF(CheckCast, TypeCheck)
public:
// creation
CheckCast(ciKlass* klass, Value obj, ValueStack* state_before)
- : TypeCheck(klass, obj, objectType, state_before) {}
+ : TypeCheck(klass, obj, objectType, state_before) { }
void set_incompatible_class_change_check() {
set_flag(ThrowIncompatibleClassChangeErrorFlag, true);
}
bool is_incompatible_class_change_check() const {
virtual void input_values_do(ValueVisitor* f) { StateSplit::input_values_do(f); f->visit(&_obj); }
};
LEAF(MonitorEnter, AccessMonitor)
+ bool _maybe_inlinetype;
public:
// creation
- MonitorEnter(Value obj, int monitor_no, ValueStack* state_before)
+ MonitorEnter(Value obj, int monitor_no, ValueStack* state_before, bool maybe_inlinetype)
: AccessMonitor(obj, monitor_no, state_before)
+ , _maybe_inlinetype(maybe_inlinetype)
{
ASSERT_VALUES
}
+ // accessors
+ bool maybe_inlinetype() const { return _maybe_inlinetype; }
+
// generic
virtual bool can_trap() const { return true; }
};
Value _y;
ciMethod* _profiled_method;
int _profiled_bci; // Canonicalizer may alter bci of If node
bool _swapped; // Is the order reversed with respect to the original If in the
// bytecode stream?
+ bool _substitutability_check;
public:
// creation
// unordered_is_true is valid for float/double compares only
- If(Value x, Condition cond, bool unordered_is_true, Value y, BlockBegin* tsux, BlockBegin* fsux, ValueStack* state_before, bool is_safepoint)
+ If(Value x, Condition cond, bool unordered_is_true, Value y, BlockBegin* tsux, BlockBegin* fsux, ValueStack* state_before, bool is_safepoint, bool substitutability_check=false)
: BlockEnd(illegalType, state_before, is_safepoint)
, _x(x)
, _cond(cond)
, _y(y)
, _profiled_method(nullptr)
, _profiled_bci(0)
, _swapped(false)
+ , _substitutability_check(substitutability_check)
{
ASSERT_VALUES
set_flag(UnorderedIsTrueFlag, unordered_is_true);
assert(x->type()->tag() == y->type()->tag(), "types must match");
BlockList* s = new BlockList(2);
void set_should_profile(bool value) { set_flag(ProfileMDOFlag, value); }
void set_profiled_method(ciMethod* method) { _profiled_method = method; }
void set_profiled_bci(int bci) { _profiled_bci = bci; }
void set_swapped(bool value) { _swapped = value; }
+ bool substitutability_check() const { return _substitutability_check; }
// generic
virtual void input_values_do(ValueVisitor* f) { BlockEnd::input_values_do(f); f->visit(&_x); f->visit(&_y); }
};
, _callee(callee)
, _bci_of_invoke(bci)
, _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();
}
ciMethod* method() const { return _method; }
ciMethod* callee() const { return _callee; }
f->visit(&_ret);
}
}
};
+ 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 != nullptr) {
+ f->visit(&_left);
+ }
+ if (_right != nullptr) {
+ f->visit(&_right);
+ }
+ }
+ };
+
// Call some C runtime function that doesn't safepoint,
// optionally passing the current thread as the first argument.
LEAF(RuntimeCall, Instruction)
private:
const char* _entry_name;
< prev index next >