changeset 56187:e1b581738b26 lworld

8226465: [lworld][c1] javac fails if C1 is enabled Reviewed-by: thartmann
author iklam
date Tue, 25 Jun 2019 09:29:15 -0700
parents 891127d31efd
children b84d71385534
files src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp src/hotspot/share/c1/c1_LIR.cpp src/hotspot/share/c1/c1_LIR.hpp src/hotspot/share/c1/c1_LIRAssembler.hpp src/hotspot/share/c1/c1_LIRGenerator.cpp src/hotspot/share/c1/c1_LIRGenerator.hpp
diffstat 8 files changed, 250 insertions(+), 81 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp	Tue Jun 25 16:01:56 2019 +0200
+++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp	Tue Jun 25 09:29:15 2019 -0700
@@ -1981,6 +1981,89 @@
   __ testb(op->tmp()->as_register(), ArrayStorageProperties::null_free_value);
 }
 
+void LIR_Assembler::emit_opSubstitutabilityCheck(LIR_OpSubstitutabilityCheck* op) {
+  Label L_oops_equal;
+  Label L_oops_not_equal;
+  Label L_end;
+
+  Register left  = op->left()->as_register();
+  Register right = op->right()->as_register();
+
+  __ cmpptr(left, right);
+  __ jcc(Assembler::equal, L_oops_equal);
+
+  // (1) Null check -- if one of the operands is null, the other must not be null (because
+  //     the two references are not equal), so they are not substitutable,
+  //     FIXME: do null check only if the operand is nullable
+  {
+    __ cmpptr(left, (int32_t)NULL_WORD);
+    __ jcc(Assembler::equal, L_oops_not_equal);
+
+    __ cmpptr(right, (int32_t)NULL_WORD);
+    __ jcc(Assembler::equal, L_oops_not_equal);
+  }
+
+  ciKlass* left_klass = op->left_klass();
+  ciKlass* right_klass = op->right_klass();
+
+  // (2) Value object check -- if either of the operands is not a value object,
+  //     they are not substitutable. We do this only if we are not sure that the
+  //     operands are value objects
+  if ((left_klass == NULL || right_klass == NULL) ||// The klass is still unloaded, or came from a Phi node.
+      !left_klass->is_valuetype() || !right_klass->is_valuetype()) {
+    Register tmp1  = op->tmp1()->as_register();
+    __ movptr(tmp1, (intptr_t)markOopDesc::always_locked_pattern);
+    __ andl(tmp1, Address(left, oopDesc::mark_offset_in_bytes()));
+    __ andl(tmp1, Address(right, oopDesc::mark_offset_in_bytes()));
+    __ cmpptr(tmp1, (intptr_t)markOopDesc::always_locked_pattern);
+    __ jcc(Assembler::notEqual, L_oops_not_equal);
+  }
+
+  // (3) Same klass check: if the operands are of different klasses, they are not substitutable.
+  if (left_klass != NULL && left_klass->is_valuetype() && left_klass == right_klass) {
+    // No need to load klass -- the operands are statically known to be the same value klass.
+    __ jmp(*op->stub()->entry());
+  } else {
+    Register left_klass_op = op->left_klass_op()->as_register();
+    Register right_klass_op = op->right_klass_op()->as_register();
+
+    if (UseCompressedOops) {
+      __ movl(left_klass_op,  Address(left,  oopDesc::klass_offset_in_bytes()));
+      __ movl(right_klass_op, Address(right, oopDesc::klass_offset_in_bytes()));
+      __ cmpl(left_klass_op, right_klass_op);
+    } else {
+      __ movptr(left_klass_op,  Address(left,  oopDesc::klass_offset_in_bytes()));
+      __ movptr(right_klass_op, Address(right, oopDesc::klass_offset_in_bytes()));
+      __ cmpptr(left_klass_op, right_klass_op);
+    }
+
+    __ jcc(Assembler::equal, *op->stub()->entry()); // same klass -> do slow check
+    // fall through to L_oops_not_equal
+  }
+
+  __ bind(L_oops_not_equal);
+  move(op->not_equal_result(), op->result_opr());
+  __ jmp(L_end);
+
+  __ bind(L_oops_equal);
+  move(op->equal_result(), op->result_opr());
+  __ jmp(L_end);
+
+  // We've returned from the stub. op->result_opr() contains 0x0 IFF the two
+  // operands are not substitutable. (Don't compare against 0x1 in case the
+  // C compiler is naughty)
+  __ bind(*op->stub()->continuation());
+  if (op->result_opr()->type() == T_LONG) {
+    __ cmpptr(op->result_opr()->as_register(), (int32_t)0);
+  } else {
+    __ cmpl(op->result_opr()->as_register(), 0);
+  }
+  __ jcc(Assembler::equal, L_oops_not_equal); // (call_stub() == 0x0) -> not_equal
+  move(op->equal_result(), op->result_opr()); // (call_stub() != 0x0) -> equal
+  // fall-through
+  __ bind(L_end);
+}
+
 void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) {
   if (LP64_ONLY(false &&) op->code() == lir_cas_long && VM_Version::supports_cx8()) {
     assert(op->cmp_value()->as_register_lo() == rax, "wrong register");
@@ -2040,6 +2123,21 @@
   }
 }
 
+void LIR_Assembler::move(LIR_Opr src, LIR_Opr dst) {
+  assert(dst->is_cpu_register(), "must be");
+  assert(dst->type() == src->type(), "must be");
+
+  if (src->is_cpu_register()) {
+    reg2reg(src, dst);
+  } else if (src->is_stack()) {
+    stack2reg(src, dst, dst->type());
+  } else if (src->is_constant()) {
+    const2reg(src, dst, lir_patch_none, NULL);
+  } else {
+    ShouldNotReachHere();
+  }
+}
+
 void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) {
   Assembler::Condition acond, ncond;
   switch (condition) {
--- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp	Tue Jun 25 16:01:56 2019 +0200
+++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp	Tue Jun 25 09:29:15 2019 -0700
@@ -55,7 +55,8 @@
     _deopt_handler_size = NOT_LP64(10) LP64_ONLY(17)
   };
 
-void arraycopy_valuetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest);
+  void arraycopy_valuetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest);
+  void move(LIR_Opr src, LIR_Opr dst);
 
 public:
 
--- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp	Tue Jun 25 16:01:56 2019 +0200
+++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp	Tue Jun 25 09:29:15 2019 -0700
@@ -112,6 +112,19 @@
 }
 
 
+void LIRGenerator::init_temps_for_substitutability_check(LIR_Opr& tmp1, LIR_Opr& tmp2) {
+  // We just need one 32-bit temp register for x86/x64, to check whether both
+  // oops have markOopDesc::always_locked_pattern. See LIR_Assembler::emit_opSubstitutabilityCheck().
+  // @temp = %r10d
+  // mov $0x405, %r10d
+  // and (%left), %r10d   /* if need to check left */
+  // and (%right), %r10d  /* if need to check right */
+  // cmp $0x405, $r10d
+  // jne L_oops_not_equal
+  tmp1 = new_register(T_INT);
+  tmp2 = LIR_OprFact::illegalOpr;
+}
+
 //--------- loading items into registers --------------------------------
 
 
--- a/src/hotspot/share/c1/c1_LIR.cpp	Tue Jun 25 16:01:56 2019 +0200
+++ b/src/hotspot/share/c1/c1_LIR.cpp	Tue Jun 25 09:29:15 2019 -0700
@@ -382,6 +382,24 @@
   , _tmp(tmp) {}
 
 
+LIR_OpSubstitutabilityCheck::LIR_OpSubstitutabilityCheck(LIR_Opr result, LIR_Opr left, LIR_Opr right, LIR_Opr equal_result, LIR_Opr not_equal_result,
+                                                         LIR_Opr tmp1, LIR_Opr tmp2,
+                                                         ciKlass* left_klass, ciKlass* right_klass, LIR_Opr left_klass_op, LIR_Opr right_klass_op,
+                                                         CodeEmitInfo* info, CodeStub* stub)
+  : LIR_Op(lir_substitutability_check, result, info)
+  , _left(left)
+  , _right(right)
+  , _equal_result(equal_result)
+  , _not_equal_result(not_equal_result)
+  , _tmp1(tmp1)
+  , _tmp2(tmp2)
+  , _left_klass(left_klass)
+  , _right_klass(right_klass)
+  , _left_klass_op(left_klass_op)
+  , _right_klass_op(right_klass_op)
+  , _stub(stub) {}
+
+
 LIR_OpArrayCopy::LIR_OpArrayCopy(LIR_Opr src, LIR_Opr src_pos, LIR_Opr dst, LIR_Opr dst_pos, LIR_Opr length,
                                  LIR_Opr tmp, ciArrayKlass* expected_type, int flags, CodeEmitInfo* info)
   : LIR_Op(lir_arraycopy, LIR_OprFact::illegalOpr, info)
@@ -895,6 +913,28 @@
       break;
     }
 
+// LIR_OpSubstitutabilityCheck
+    case lir_substitutability_check: {
+      assert(op->as_OpSubstitutabilityCheck() != NULL, "must be");
+      LIR_OpSubstitutabilityCheck* opSubstitutabilityCheck = (LIR_OpSubstitutabilityCheck*)op;
+                                                                do_input(opSubstitutabilityCheck->_left);
+                                                                do_temp (opSubstitutabilityCheck->_left);
+                                                                do_input(opSubstitutabilityCheck->_right);
+                                                                do_temp (opSubstitutabilityCheck->_right);
+                                                                do_input(opSubstitutabilityCheck->_equal_result);
+                                                                do_temp (opSubstitutabilityCheck->_equal_result);
+                                                                do_input(opSubstitutabilityCheck->_not_equal_result);
+                                                                do_temp (opSubstitutabilityCheck->_not_equal_result);
+      if (opSubstitutabilityCheck->_tmp1->is_valid())           do_temp(opSubstitutabilityCheck->_tmp1);
+      if (opSubstitutabilityCheck->_tmp2->is_valid())           do_temp(opSubstitutabilityCheck->_tmp2);
+      if (opSubstitutabilityCheck->_left_klass_op->is_valid())  do_temp(opSubstitutabilityCheck->_left_klass_op);
+      if (opSubstitutabilityCheck->_right_klass_op->is_valid()) do_temp(opSubstitutabilityCheck->_right_klass_op);
+      if (opSubstitutabilityCheck->_result->is_valid())         do_output(opSubstitutabilityCheck->_result);
+                                                                do_info(opSubstitutabilityCheck->_info);
+                                                                do_stub(opSubstitutabilityCheck->_stub);
+      break;
+    }
+
 // LIR_OpCompareAndSwap
     case lir_cas_long:
     case lir_cas_obj:
@@ -1115,6 +1155,13 @@
   masm->emit_opNullFreeArrayCheck(this);
 }
 
+void LIR_OpSubstitutabilityCheck::emit_code(LIR_Assembler* masm) {
+  masm->emit_opSubstitutabilityCheck(this);
+  if (stub() != NULL) {
+    masm->append_code_stub(stub());
+  }
+}
+
 void LIR_OpCompareAndSwap::emit_code(LIR_Assembler* masm) {
   masm->emit_compare_and_swap(this);
 }
@@ -1526,6 +1573,17 @@
   append(c);
 }
 
+void LIR_List::substitutability_check(LIR_Opr result, LIR_Opr left, LIR_Opr right, LIR_Opr equal_result, LIR_Opr not_equal_result,
+                                      LIR_Opr tmp1, LIR_Opr tmp2,
+                                      ciKlass* left_klass, ciKlass* right_klass, LIR_Opr left_klass_op, LIR_Opr right_klass_op,
+                                      CodeEmitInfo* info, CodeStub* stub) {
+  LIR_OpSubstitutabilityCheck* c = new LIR_OpSubstitutabilityCheck(result, left, right, equal_result, not_equal_result,
+                                                                   tmp1, tmp2,
+                                                                   left_klass, right_klass, left_klass_op, right_klass_op,
+                                                                   info, stub);
+  append(c);
+}
+
 void LIR_List::cas_long(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value,
                         LIR_Opr t1, LIR_Opr t2, LIR_Opr result) {
   append(new LIR_OpCompareAndSwap(lir_cas_long, addr, cmp_value, new_value, t1, t2, result));
@@ -1822,6 +1880,8 @@
      case lir_flattened_array_check: s = "flattened_array_check"; break;
      // LIR_OpNullFreeArrayCheck
      case lir_null_free_array_check: s = "null_free_array_check"; break;
+     // LIR_OpSubstitutabilityCheck
+     case lir_substitutability_check: s = "substitutability_check"; break;
      // LIR_OpCompareAndSwap
      case lir_cas_long:              s = "cas_long";      break;
      case lir_cas_obj:               s = "cas_obj";      break;
@@ -2081,6 +2141,23 @@
   tmp()->print(out);                     out->print(" ");
 }
 
+void LIR_OpSubstitutabilityCheck::print_instr(outputStream* out) const {
+  result_opr()->print(out);              out->print(" ");
+  left()->print(out);                    out->print(" ");
+  right()->print(out);                   out->print(" ");
+  equal_result()->print(out);            out->print(" ");
+  not_equal_result()->print(out);        out->print(" ");
+  tmp1()->print(out);                    out->print(" ");
+  tmp2()->print(out);                    out->print(" ");
+  left_klass()->print(out);              out->print(" ");
+  right_klass()->print(out);             out->print(" ");
+  left_klass_op()->print(out);           out->print(" ");
+  right_klass_op()->print(out);          out->print(" ");
+  if (stub() != NULL) {
+    out->print("[label:" INTPTR_FORMAT "]", p2i(stub()->entry()));
+  }
+}
+
 // LIR_Op3
 void LIR_Op3::print_instr(outputStream* out) const {
   in_opr1()->print(out);    out->print(" ");
--- a/src/hotspot/share/c1/c1_LIR.hpp	Tue Jun 25 16:01:56 2019 +0200
+++ b/src/hotspot/share/c1/c1_LIR.hpp	Tue Jun 25 09:29:15 2019 -0700
@@ -875,6 +875,7 @@
 class    LIR_OpTypeCheck;
 class    LIR_OpFlattenedArrayCheck;
 class    LIR_OpNullFreeArrayCheck;
+class    LIR_OpSubstitutabilityCheck;
 class    LIR_OpCompareAndSwap;
 class    LIR_OpProfileCall;
 class    LIR_OpProfileType;
@@ -995,6 +996,9 @@
   , begin_opNullFreeArrayCheck
     , lir_null_free_array_check
   , end_opNullFreeArrayCheck
+  , begin_opSubstitutabilityCheck
+    , lir_substitutability_check
+  , end_opSubstitutabilityCheck
   , begin_opCompareAndSwap
     , lir_cas_long
     , lir_cas_obj
@@ -1147,6 +1151,7 @@
   virtual LIR_OpTypeCheck* as_OpTypeCheck() { return NULL; }
   virtual LIR_OpFlattenedArrayCheck* as_OpFlattenedArrayCheck() { return NULL; }
   virtual LIR_OpNullFreeArrayCheck* as_OpNullFreeArrayCheck() { return NULL; }
+  virtual LIR_OpSubstitutabilityCheck* as_OpSubstitutabilityCheck() { return NULL; }
   virtual LIR_OpCompareAndSwap* as_OpCompareAndSwap() { return NULL; }
   virtual LIR_OpProfileCall* as_OpProfileCall() { return NULL; }
   virtual LIR_OpProfileType* as_OpProfileType() { return NULL; }
@@ -1648,6 +1653,44 @@
   virtual void print_instr(outputStream* out) const PRODUCT_RETURN;
 };
 
+class LIR_OpSubstitutabilityCheck: public LIR_Op {
+ friend class LIR_OpVisitState;
+
+ private:
+  LIR_Opr       _left;
+  LIR_Opr       _right;
+  LIR_Opr       _equal_result;
+  LIR_Opr       _not_equal_result;
+  LIR_Opr       _tmp1;
+  LIR_Opr       _tmp2;
+  ciKlass*      _left_klass;
+  ciKlass*      _right_klass;
+  LIR_Opr       _left_klass_op;
+  LIR_Opr       _right_klass_op;
+  CodeStub*     _stub;
+public:
+  LIR_OpSubstitutabilityCheck(LIR_Opr result, LIR_Opr left, LIR_Opr right, LIR_Opr equal_result, LIR_Opr not_equal_result,
+                              LIR_Opr tmp1, LIR_Opr tmp2,
+                              ciKlass* left_klass, ciKlass* right_klass, LIR_Opr left_klass_op, LIR_Opr right_klass_op,
+                              CodeEmitInfo* info, CodeStub* stub);
+
+  LIR_Opr left() const             { return _left; }
+  LIR_Opr right() const            { return _right; }
+  LIR_Opr equal_result() const     { return _equal_result; }
+  LIR_Opr not_equal_result() const { return _not_equal_result; }
+  LIR_Opr tmp1() const             { return _tmp1; }
+  LIR_Opr tmp2() const             { return _tmp2; }
+  ciKlass* left_klass() const      { return _left_klass; }
+  ciKlass* right_klass() const     { return _right_klass; }
+  LIR_Opr left_klass_op() const    { return _left_klass_op; }
+  LIR_Opr right_klass_op() const   { return _right_klass_op; }
+  CodeStub* stub() const           { return _stub; }
+
+  virtual void emit_code(LIR_Assembler* masm);
+  virtual LIR_OpSubstitutabilityCheck* as_OpSubstitutabilityCheck() { return this; }
+  virtual void print_instr(outputStream* out) const PRODUCT_RETURN;
+};
+
 // LIR_Op2
 class LIR_Op2: public LIR_Op {
  friend class LIR_OpVisitState;
@@ -2307,6 +2350,10 @@
   void store_check(LIR_Opr object, LIR_Opr array, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, CodeEmitInfo* info_for_exception, ciMethod* profiled_method, int profiled_bci);
   void check_flattened_array(LIR_Opr array, LIR_Opr value, LIR_Opr tmp, CodeStub* stub);
   void check_null_free_array(LIR_Opr array, LIR_Opr tmp);
+  void substitutability_check(LIR_Opr result, LIR_Opr left, LIR_Opr right, LIR_Opr equal_result, LIR_Opr not_equal_result,
+                              LIR_Opr tmp1, LIR_Opr tmp2,
+                              ciKlass* left_klass, ciKlass* right_klass, LIR_Opr left_klass_op, LIR_Opr right_klass_op,
+                              CodeEmitInfo* info, CodeStub* stub);
 
   void checkcast (LIR_Opr result, LIR_Opr object, ciKlass* klass,
                   LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check,
--- a/src/hotspot/share/c1/c1_LIRAssembler.hpp	Tue Jun 25 16:01:56 2019 +0200
+++ b/src/hotspot/share/c1/c1_LIRAssembler.hpp	Tue Jun 25 09:29:15 2019 -0700
@@ -209,6 +209,7 @@
   void emit_opTypeCheck(LIR_OpTypeCheck* op);
   void emit_opFlattenedArrayCheck(LIR_OpFlattenedArrayCheck* op);
   void emit_opNullFreeArrayCheck(LIR_OpNullFreeArrayCheck* op);
+  void emit_opSubstitutabilityCheck(LIR_OpSubstitutabilityCheck* op);
   void emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, Label* failure, Label* obj_is_null);
   void emit_compare_and_swap(LIR_OpCompareAndSwap* op);
   void emit_lock(LIR_OpLock* op);
--- a/src/hotspot/share/c1/c1_LIRGenerator.cpp	Tue Jun 25 16:01:56 2019 +0200
+++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp	Tue Jun 25 09:29:15 2019 -0700
@@ -3237,105 +3237,36 @@
 void LIRGenerator::substitutability_check(IfOp* x, LIRItem& left, LIRItem& right, LIRItem& t_val, LIRItem& f_val) {
   assert(x->cond() == If::eql || x->cond() == If::neq, "must be");
   bool is_acmpeq = (x->cond() == If::eql);
-  LIR_Opr reg = rlock_result(x);
   LIR_Opr equal_result     = is_acmpeq ? t_val.result() : f_val.result();
   LIR_Opr not_equal_result = is_acmpeq ? f_val.result() : t_val.result();
 
-  LabelObj* L_oops_equal = new LabelObj();
-  LabelObj* L_oops_not_equal = new LabelObj();
-  LabelObj* L_do_slow_subst_check = new LabelObj();
-  LabelObj* L_end = new LabelObj();
-
-  __ cmp(lir_cond_equal, left.result(), right.result());
-  __ branch(lir_cond_equal, T_ILLEGAL, L_oops_equal->label());
-
-  // The two operands are not the same reference. Do a more costly substitutability check.
+  LIR_Opr tmp1 = LIR_OprFact::illegalOpr;
+  LIR_Opr tmp2 = LIR_OprFact::illegalOpr;
+  LIR_Opr left_klass_op = LIR_OprFact::illegalOpr;
+  LIR_Opr right_klass_op = LIR_OprFact::illegalOpr;
 
   ciKlass* left_klass = x->x()->as_loaded_klass_or_null();
   ciKlass* right_klass = x->y()->as_loaded_klass_or_null();
 
-  // (1) Null check -- if one of the operands is null, the other must not be null (because
-  //     the two references are not equal), so they are not substitutable,
-  //     FIXME: do null check only if the operand is nullable
-  {
-    __ cmp(lir_cond_equal, left.result(), LIR_OprFact::oopConst(NULL));
-    __ branch(lir_cond_equal, T_ILLEGAL, L_oops_not_equal->label());
-
-    __ cmp(lir_cond_equal, right.result(), LIR_OprFact::oopConst(NULL));
-    __ branch(lir_cond_equal, T_ILLEGAL, L_oops_not_equal->label());
-  }
-
-  // (2) Value object check -- if either of the operands is not a value object,
-  //     they are not substitutable. We do this only if we are not sure that the
-  //     operands are value objects
   if ((left_klass == NULL || right_klass == NULL) ||// The klass is still unloaded, or came from a Phi node.
       !left_klass->is_valuetype() || !right_klass->is_valuetype()) {
-    // FIXME: on x64, this can be optimized as:
-    // mov $0x405,%r10d
-    // and (%left), %r10d   /* if need to check left */
-    // and (%right), %r10d  /* if need to check right */
-    // cmp $0x405, $r10d
-    // jne L_oops_not_equal
-
-    LIR_Opr mark = new_register(T_LONG);
-    LIR_Opr always_locked_pattern = new_register(T_LONG);
-    __ move(LIR_OprFact::longConst(markOopDesc::always_locked_pattern), always_locked_pattern);
-
-    if (left_klass == NULL || !left_klass->is_valuetype()) {
-      __ move(new LIR_Address(left.result(), oopDesc::mark_offset_in_bytes(), T_LONG), mark);
-      __ logical_and(mark, always_locked_pattern, mark);
-      __ cmp(lir_cond_notEqual, mark, always_locked_pattern);
-      __ branch(lir_cond_notEqual, T_ILLEGAL, L_oops_not_equal->label());
-    }
-
-    if (right_klass == NULL || !right_klass->is_valuetype()) {
-      __ move(new LIR_Address(right.result(), oopDesc::mark_offset_in_bytes(), T_LONG), mark);
-      __ logical_and(mark, always_locked_pattern, mark);
-      __ cmp(lir_cond_notEqual, mark, always_locked_pattern);
-      __ branch(lir_cond_notEqual, T_ILLEGAL, L_oops_not_equal->label());
-    }
+    init_temps_for_substitutability_check(tmp1, tmp2);
   }
 
-  // (3) Same klass check: if the operands are of different klasses, they are not substitutable.
   if (left_klass != NULL && left_klass->is_valuetype() && left_klass == right_klass) {
     // No need to load klass -- the operands are statically known to be the same value klass.
-    __ branch(lir_cond_always, T_ILLEGAL, L_do_slow_subst_check->label());
   } else {
     BasicType t_klass = UseCompressedOops ? T_INT : T_METADATA;
-    BasicType t_addr  = UseCompressedOops ? T_INT : T_ADDRESS;
-
-    LIR_Opr left_klass = new_register(t_klass);
-    LIR_Opr right_klass = new_register(t_klass);
-    __ move(new LIR_Address(left.result(),  oopDesc::klass_offset_in_bytes(), t_addr), left_klass);
-    __ move(new LIR_Address(right.result(), oopDesc::klass_offset_in_bytes(), t_addr), right_klass);
-    __ cmp(lir_cond_equal, left_klass, right_klass);
-    __ branch(lir_cond_equal, T_ILLEGAL, L_do_slow_subst_check->label());
-
-    // fall through to L_oops_not_equal
+    left_klass_op = new_register(t_klass);
+    right_klass_op = new_register(t_klass);
   }
 
-  __ branch_destination(L_oops_not_equal->label());
-  __ move(not_equal_result, reg);
-  __ branch(lir_cond_always, T_ILLEGAL, L_end->label());
-
-  // FIXME -- for simple case (no non-flattened value fields), do a per-field comparison
-
-  __ branch_destination(L_do_slow_subst_check->label());
-
-  const LIR_Opr result = result_register_for(x->type());
+  LIR_Opr result = rlock_result(x);
   CodeEmitInfo* info = state_for(x, x->state_before());
   CodeStub* slow_path = new SubstitutabilityCheckStub(left.result(), right.result(), result, info);
-  __ branch(lir_cond_always, T_ILLEGAL, slow_path);
-  __ branch_destination(slow_path->continuation());
-
-  __ cmp(lir_cond_notEqual, result, LIR_OprFact::intConst(1));
-  __ move(not_equal_result, reg);
-  __ branch(lir_cond_notEqual, T_ILLEGAL, L_end->label());
-
-  __ branch_destination(L_oops_equal->label());
-  __ move(equal_result, reg);
-
-  __ branch_destination(L_end->label());
+  __ substitutability_check(result, left.result(), right.result(), equal_result, not_equal_result,
+                            tmp1, tmp2,
+                            left_klass, right_klass, left_klass_op, right_klass_op, info, slow_path);
 }
 
 #ifdef JFR_HAVE_INTRINSICS
--- a/src/hotspot/share/c1/c1_LIRGenerator.hpp	Tue Jun 25 16:01:56 2019 +0200
+++ b/src/hotspot/share/c1/c1_LIRGenerator.hpp	Tue Jun 25 09:29:15 2019 -0700
@@ -273,6 +273,7 @@
   bool needs_null_free_array_store_check(StoreIndexed* x);
   void check_null_free_array(LIRItem& array, LIRItem& value,  CodeEmitInfo* info);
   void substitutability_check(IfOp* x, LIRItem& left, LIRItem& right, LIRItem& t_val, LIRItem& f_val);
+  void init_temps_for_substitutability_check(LIR_Opr& tmp1, LIR_Opr& tmp2);
 
  public:
   LIR_Opr call_runtime(BasicTypeArray* signature, LIRItemList* args, address entry, ValueType* result_type, CodeEmitInfo* info);