< prev index next >

src/hotspot/share/opto/compile.cpp

Print this page

        

@@ -4505,10 +4505,65 @@
     igvn.check_no_speculative_types();
 #endif
   }
 }
 
+Node* Compile::load_is_value_bit(PhaseGVN* phase, Node* oop) {
+  // Load the klass pointer and check if it's odd, i.e., if it defines a value type
+  // is_value = (klass & oop_metadata_odd_mask) >> LogKlassAlignmentInBytes
+  Node* k_adr = phase->transform(new AddPNode(oop, oop, phase->MakeConX(oopDesc::klass_offset_in_bytes())));
+  Node* klass = NULL;
+  if (UseCompressedClassPointers) {
+    klass = phase->transform(new LoadNKlassNode(NULL, immutable_memory(), k_adr, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT->make_narrowklass(), MemNode::unordered));
+  } else {
+    klass = phase->transform(new LoadKlassNode(NULL, immutable_memory(), k_adr, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT, MemNode::unordered));
+  }
+  const int mask = Universe::oop_metadata_odd_mask();
+  Node* is_value = phase->transform(new CastP2XNode(NULL, klass));
+  is_value = phase->transform(new AndXNode(is_value, phase->MakeConX(mask)));
+  // Check if a shift is required for perturbation to affect aligned bits of oop
+  if (mask == KlassPtrEvenOddMask && ObjectAlignmentInBytes <= KlassAlignmentInBytes) {
+    assert((mask >> LogKlassAlignmentInBytes) == 1, "invalid shift");
+    is_value = phase->transform(new URShiftXNode(is_value, phase->intcon(LogKlassAlignmentInBytes)));
+  } else {
+    assert(mask < ObjectAlignmentInBytes, "invalid mask");
+  }
+  return is_value;
+}
+
+Node* Compile::optimize_acmp(PhaseGVN* phase, Node* a, Node* b) {
+  const TypeInstPtr* ta = phase->type(a)->isa_instptr();
+  const TypeInstPtr* tb = phase->type(b)->isa_instptr();
+  if (!UseNewAcmp || phase->type(a)->is_zero_type() || phase->type(b)->is_zero_type()) {
+    // Use old acmp if new acmp is disabled or degraded to a null check
+    if (Verbose && phase->is_IterGVN()) { tty->print_cr("\n# NULL CHECK"); }
+    return new CmpPNode(a, b);
+  } else if ((ta != NULL && ta->is_value_based()) || (tb != NULL && tb->is_value_based())) {
+    // We statically know that one operand is a value. Therefore,
+    // new acmp will only return true if both operands are NULL.
+    if ((ta != NULL && !TypePtr::NULL_PTR->higher_equal(ta)) ||
+        (tb != NULL && !TypePtr::NULL_PTR->higher_equal(tb))) {
+      // One operand is never NULL, fold to constant false
+      if (Verbose && !phase->is_IterGVN()) { tty->print_cr("\n# CONSTANT FALSE (parse time)"); } else if(Verbose) { tty->print_cr("\n# CONSTANT FALSE"); }
+      return new CmpINode(phase->intcon(0), phase->intcon(1));
+    } else {
+      // Check if both operands are null by or'ing the oops
+      a = phase->transform(new CastP2XNode(NULL, a));
+      b = phase->transform(new CastP2XNode(NULL, b));
+      a = phase->transform(new OrXNode(a, b));
+      if (Verbose && !phase->is_IterGVN()) { tty->print_cr("\n# DOUBLE NULL CHECK (parse time)"); } else if (Verbose) { tty->print_cr("\n# DOUBLE NULL CHECK"); }
+      return new CmpXNode(a, phase->MakeConX(0));
+    }
+  } else if (ta == NULL || !ta->can_be_value_based() || tb == NULL || !tb->can_be_value_based()) {
+    // Use old acmp
+    if (Verbose && phase->is_IterGVN()) { tty->print_cr("\n# OLD ACMP "); }
+    return new CmpPNode(a, b);
+  }
+  // Use new acmp
+  return NULL;
+}
+
 // Auxiliary method to support randomized stressing/fuzzing.
 //
 // This method can be called the arbitrary number of times, with current count
 // as the argument. The logic allows selecting a single candidate from the
 // running list of candidates as follows:
< prev index next >