< prev index next >

src/hotspot/share/c1/c1_Instruction.hpp

Print this page
@@ -70,14 +70,16 @@
  class   OsrEntry;
  class   ExceptionObject;
  class   StateSplit;
  class     Invoke;
  class     NewInstance;
+ class     NewInlineTypeInstance;
  class     NewArray;
  class       NewTypeArray;
  class       NewObjectArray;
  class       NewMultiArray;
+ class     Deoptimize;
  class     TypeCheck;
  class       CheckCast;
  class       InstanceOf;
  class     AccessMonitor;
  class       MonitorEnter;

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

@@ -170,13 +173,15 @@
    virtual void do_Convert        (Convert*         x) = 0;
    virtual void do_NullCheck      (NullCheck*       x) = 0;
    virtual void do_TypeCast       (TypeCast*        x) = 0;
    virtual void do_Invoke         (Invoke*          x) = 0;
    virtual void do_NewInstance    (NewInstance*     x) = 0;
+   virtual void do_NewInlineTypeInstance(NewInlineTypeInstance* x) = 0;
    virtual void do_NewTypeArray   (NewTypeArray*    x) = 0;
    virtual void do_NewObjectArray (NewObjectArray*  x) = 0;
    virtual void do_NewMultiArray  (NewMultiArray*   x) = 0;
+   virtual void do_Deoptimize     (Deoptimize*      x) = 0;
    virtual void do_CheckCast      (CheckCast*       x) = 0;
    virtual void do_InstanceOf     (InstanceOf*      x) = 0;
    virtual void do_MonitorEnter   (MonitorEnter*    x) = 0;
    virtual void do_MonitorExit    (MonitorExit*     x) = 0;
    virtual void do_Intrinsic      (Intrinsic*       x) = 0;

@@ -194,10 +199,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

@@ -210,13 +216,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-

@@ -271,10 +278,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 == NULL  ) 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:

@@ -293,10 +315,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

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

@@ -437,20 +461,23 @@
    Instruction* subst()                           { return _subst == NULL ? 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() == NULL && as_Phi() == NULL; }
  
    bool is_null_obj()                             { return as_Constant() != NULL && 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

@@ -491,10 +518,14 @@
      set_next(i);
      i->set_next(n);
      return _next;
    }
  
+   bool is_loaded_flattened_array() const;
+   bool maybe_flattened_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);

@@ -538,14 +569,16 @@
    virtual NullCheck*        as_NullCheck()       { return NULL; }
    virtual OsrEntry*         as_OsrEntry()        { return NULL; }
    virtual StateSplit*       as_StateSplit()      { return NULL; }
    virtual Invoke*           as_Invoke()          { return NULL; }
    virtual NewInstance*      as_NewInstance()     { return NULL; }
+   virtual NewInlineTypeInstance* as_NewInlineTypeInstance() { return NULL; }
    virtual NewArray*         as_NewArray()        { return NULL; }
    virtual NewTypeArray*     as_NewTypeArray()    { return NULL; }
    virtual NewObjectArray*   as_NewObjectArray()  { return NULL; }
    virtual NewMultiArray*    as_NewMultiArray()   { return NULL; }
+   virtual Deoptimize*       as_Deoptimize()      { return NULL; }
    virtual TypeCheck*        as_TypeCheck()       { return NULL; }
    virtual CheckCast*        as_CheckCast()       { return NULL; }
    virtual InstanceOf*       as_InstanceOf()      { return NULL; }
    virtual TypeCast*         as_TypeCast()        { return NULL; }
    virtual AccessMonitor*    as_AccessMonitor()   { return NULL; }

@@ -690,16 +723,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 +849,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 = NULL, Value default_value = NULL )
    : 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 +866,22 @@
  
  
  LEAF(StoreField, AccessField)
   private:
    Value _value;
+   ciField* _enclosing_field;   // enclosing field (the flattened 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 +935,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(NULL), _profiled_bci(0)
    {
      set_flag(Instruction::NeedsRangeCheckFlag, true);
      ASSERT_VALUES
    }
  

@@ -926,24 +962,36 @@
  
    void clear_length()                            { _length = NULL; }
    // perform elimination of range checks involving constants
    bool compute_needs_range_check();
  
-   // generic
+   // 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 != NULL) f->visit(&_length); }
  };
  
+ class DelayedLoadIndexed;
  
  LEAF(LoadIndexed, AccessIndexed)
   private:
    NullCheck*  _explicit_null_check;              // For explicit null check elimination
+   NewInlineTypeInstance* _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(NULL) {}
+   , _explicit_null_check(NULL), _vt(NULL), _delayed(NULL) {}
  
    // accessors
    NullCheck* explicit_null_check() const         { return _explicit_null_check; }
  
    // setters

@@ -951,48 +999,63 @@
    void set_explicit_null_check(NullCheck* check) { _explicit_null_check = check; }
  
    ciType* exact_type() const;
    ciType* declared_type() const;
  
-   // generic;
-   HASHING3(LoadIndexed, true, type()->tag(), array()->subst(), index()->subst())
+   NewInlineTypeInstance* vt() const { return _vt; }
+   void set_vt(NewInlineTypeInstance* vt) { _vt = vt; }
+ 
+   DelayedLoadIndexed* delayed() const { return _delayed; }
+   void set_delayed(DelayedLoadIndexed* delayed) { _delayed = delayed; }
+ 
+   // generic
+   HASHING4(LoadIndexed, delayed() == NULL && !should_profile(), type()->tag(), 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(NULL)
+   , _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(NULL), _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_flattened_array_store() const;
    // generic
    virtual void input_values_do(ValueVisitor* f)   { AccessIndexed::input_values_do(f); f->visit(&_value); }
  };
  
  

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

@@ -1236,11 +1302,11 @@
    ciMethod*       _target;
  
   public:
    // creation
    Invoke(Bytecodes::Code code, ValueType* result_type, Value recv, Values* args,
-          ciMethod* target, ValueStack* state_before);
+          ciMethod* target, ValueStack* state_before, bool null_free);
  
    // accessors
    Bytecodes::Code code() const                   { return _code; }
    Value receiver() const                         { return _recv; }
    bool has_receiver() const                      { return receiver() != NULL; }

@@ -1294,10 +1360,58 @@
    virtual bool can_trap() const                  { return true; }
    ciType* exact_type() const;
    ciType* declared_type() const;
  };
  
+ LEAF(NewInlineTypeInstance, StateSplit)
+   ciInlineKlass* _klass;
+   bool _in_larval_state;
+   int _first_local_index;
+   int _on_stack_count;
+ public:
+ 
+   // Default creation, always allocated for now
+   NewInlineTypeInstance(ciInlineKlass* klass, ValueStack* state_before)
+   : StateSplit(instanceType, state_before)
+    , _klass(klass)
+    , _in_larval_state(true)
+    , _first_local_index(-1)
+    , _on_stack_count(1)
+   {
+     set_null_free(true);
+   }
+ 
+   // accessors
+   ciInlineKlass* klass() const { return _klass; }
+   virtual bool needs_exception_state() const     { return false; }
+ 
+   // generic
+   virtual bool can_trap() const                  { return true; }
+   ciType* exact_type() const;
+   ciType* declared_type() const;
+ 
+   // Only done in LIR Generator -> map everything to object
+   void set_to_object_type() { set_type(instanceType); }
+ 
+   void set_local_index(int index) {
+     decrement_on_stack_count();
+     if (_first_local_index != index) {
+       if (_first_local_index == -1) {
+         _first_local_index = index;
+       } else {
+         set_not_larva_anymore();
+       }
+     }
+   }
+ 
+   bool in_larval_state() const { return _in_larval_state; }
+   void set_not_larva_anymore() { _in_larval_state = false; }
+ 
+   int on_stack_count() const { return _on_stack_count; }
+   void increment_on_stack_count() { _on_stack_count++; }
+   void decrement_on_stack_count() { _on_stack_count--; }
+ };
  
  BASE(NewArray, StateSplit)
   private:
    Value       _length;
  

@@ -1345,11 +1459,14 @@
   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, bool null_free)
+   : NewArray(length, state_before), _klass(klass) {
+     set_null_free(null_free);
+   }
  
    // accessors
    ciKlass* klass() const                         { return _klass; }
    ciType* exact_type() const;
  };

@@ -1380,12 +1497,25 @@
      // 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;
  };
  
+ LEAF(Deoptimize, StateSplit)
+ private:
+   ciKlass*    _klass;
+ 
+  public:
+   Deoptimize(ciKlass* klass, ValueStack* state_before)
+   : StateSplit(objectType, state_before), _klass(klass) {}
+ 
+   // accessors
+   ciKlass* klass() const                         { return _klass; }
+ };
  
  BASE(TypeCheck, StateSplit)
   private:
    ciKlass*    _klass;
    Value       _obj;

@@ -1426,12 +1556,14 @@
  
  
  LEAF(CheckCast, TypeCheck)
   public:
    // creation
-   CheckCast(ciKlass* klass, Value obj, ValueStack* state_before)
-   : TypeCheck(klass, obj, objectType, state_before) {}
+   CheckCast(ciKlass* klass, Value obj, ValueStack* state_before, bool null_free = false)
+   : TypeCheck(klass, obj, objectType, state_before) {
+     set_null_free(null_free);
+   }
  
    void set_incompatible_class_change_check() {
      set_flag(ThrowIncompatibleClassChangeErrorFlag, true);
    }
    bool is_incompatible_class_change_check() const {

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

@@ -1957,29 +2094,35 @@
    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(NULL)
    , _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);
      s->append(tsux);
      s->append(fsux);
      set_sux(s);
+     if (!_substitutability_check) {
+       assert(x->as_NewInlineTypeInstance() == NULL || y->type() == objectNull, "Sanity check");
+       assert(y->as_NewInlineTypeInstance() == NULL || x->type() == objectNull, "Sanity check");
+     }
    }
  
    // accessors
    Value x() const                                { return _x; }
    Condition cond() const                         { return _cond; }

@@ -2010,10 +2153,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); }
  };
  
  

@@ -2344,11 +2488,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; }

@@ -2360,10 +2504,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 != 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)
   private:
    const char* _entry_name;
< prev index next >