< prev index next >

src/hotspot/share/c1/c1_Instruction.hpp

Print this page
@@ -72,10 +72,11 @@
  class     NewInstance;
  class     NewArray;
  class       NewTypeArray;
  class       NewObjectArray;
  class       NewMultiArray;
+ class     Deoptimize;
  class     TypeCheck;
  class       CheckCast;
  class       InstanceOf;
  class     AccessMonitor;
  class       MonitorEnter;

@@ -96,10 +97,11 @@
  class     UnsafeGet;
  class     UnsafePut;
  class     UnsafeGetAndSet;
  class   ProfileCall;
  class   ProfileReturnType;
+ class   ProfileACmpTypes;
  class   ProfileInvoke;
  class   RuntimeCall;
  class   MemBar;
  class   RangeCheckPredicate;
  #ifdef ASSERT

@@ -191,10 +193,11 @@
    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

@@ -207,13 +210,14 @@
  //
  // 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-

@@ -268,10 +272,25 @@
      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:

@@ -290,10 +309,11 @@
    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

@@ -342,10 +362,11 @@
  
    static const int no_bci = -99;
  
    enum InstructionFlag {
      NeedsNullCheckFlag = 0,
+     NeverNullFlag,          // For "Q" signatures
      CanTrapFlag,
      DirectCompareFlag,
      IsEliminatedFlag,
      IsSafepointFlag,
      IsStaticFlag,

@@ -435,20 +456,23 @@
    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

@@ -489,10 +513,14 @@
      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);

@@ -688,16 +716,17 @@
    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; }

@@ -815,13 +844,16 @@
  
  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())

@@ -829,26 +861,22 @@
  
  
  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); }
  };
  

@@ -902,19 +930,22 @@
   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
    }
  

@@ -926,24 +957,36 @@
  
    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

@@ -951,48 +994,63 @@
    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); }
  };
  
  

@@ -1099,29 +1157,32 @@
  
  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); }
  };
  
  

@@ -1274,31 +1335,32 @@
  
  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:

@@ -1345,11 +1407,12 @@
   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;
  };

@@ -1380,10 +1443,12 @@
      // 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:

@@ -1427,11 +1492,11 @@
  
  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 {

@@ -1485,18 +1550,23 @@
    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; }
  };
  
  

@@ -1952,21 +2022,23 @@
    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);

@@ -1997,10 +2069,11 @@
  
    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); }
  };
  
  

@@ -2331,11 +2404,11 @@
      , _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; }

@@ -2347,10 +2420,52 @@
        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 >