diff src/share/vm/c1/c1_LIRGenerator.cpp @ 2446:13bc79b5c9c8

7033154: Improve C1 arraycopy performance Summary: better static analysis. Take advantage of array copy stubs. Reviewed-by: never
author roland
date Sun, 03 Apr 2011 12:00:54 +0200
parents 8033953d67ff
children d86923d96dca
line wrap: on
line diff
--- a/src/share/vm/c1/c1_LIRGenerator.cpp	Sat Apr 02 10:54:15 2011 -0700
+++ b/src/share/vm/c1/c1_LIRGenerator.cpp	Sun Apr 03 12:00:54 2011 +0200
@@ -706,6 +706,38 @@
   }
 }
 
+static Value maxvalue(IfOp* ifop) {
+  switch (ifop->cond()) {
+    case If::eql: return NULL;
+    case If::neq: return NULL;
+    case If::lss: // x <  y ? x : y
+    case If::leq: // x <= y ? x : y
+      if (ifop->x() == ifop->tval() &&
+          ifop->y() == ifop->fval()) return ifop->y();
+      return NULL;
+
+    case If::gtr: // x >  y ? y : x
+    case If::geq: // x >= y ? y : x
+      if (ifop->x() == ifop->tval() &&
+          ifop->y() == ifop->fval()) return ifop->y();
+      return NULL;
+
+  }
+}
+
+static ciType* phi_declared_type(Phi* phi) {
+  ciType* t = phi->operand_at(0)->declared_type();
+  if (t == NULL) {
+    return NULL;
+  }
+  for(int i = 1; i < phi->operand_count(); i++) {
+    if (t != phi->operand_at(i)->declared_type()) {
+      return NULL;
+    }
+  }
+  return t;
+}
+
 void LIRGenerator::arraycopy_helper(Intrinsic* x, int* flagsp, ciArrayKlass** expected_typep) {
   Instruction* src     = x->argument_at(0);
   Instruction* src_pos = x->argument_at(1);
@@ -715,12 +747,20 @@
 
   // first try to identify the likely type of the arrays involved
   ciArrayKlass* expected_type = NULL;
-  bool is_exact = false;
+  bool is_exact = false, src_objarray = false, dst_objarray = false;
   {
     ciArrayKlass* src_exact_type    = as_array_klass(src->exact_type());
     ciArrayKlass* src_declared_type = as_array_klass(src->declared_type());
+    Phi* phi;
+    if (src_declared_type == NULL && (phi = src->as_Phi()) != NULL) {
+      src_declared_type = as_array_klass(phi_declared_type(phi));
+    }
     ciArrayKlass* dst_exact_type    = as_array_klass(dst->exact_type());
     ciArrayKlass* dst_declared_type = as_array_klass(dst->declared_type());
+    if (dst_declared_type == NULL && (phi = dst->as_Phi()) != NULL) {
+      dst_declared_type = as_array_klass(phi_declared_type(phi));
+    }
+
     if (src_exact_type != NULL && src_exact_type == dst_exact_type) {
       // the types exactly match so the type is fully known
       is_exact = true;
@@ -744,17 +784,60 @@
     if (expected_type == NULL) expected_type = dst_exact_type;
     if (expected_type == NULL) expected_type = src_declared_type;
     if (expected_type == NULL) expected_type = dst_declared_type;
+
+    src_objarray = (src_exact_type && src_exact_type->is_obj_array_klass()) || (src_declared_type && src_declared_type->is_obj_array_klass());
+    dst_objarray = (dst_exact_type && dst_exact_type->is_obj_array_klass()) || (dst_declared_type && dst_declared_type->is_obj_array_klass());
   }
 
   // if a probable array type has been identified, figure out if any
   // of the required checks for a fast case can be elided.
   int flags = LIR_OpArrayCopy::all_flags;
+
+  if (!src_objarray)
+    flags &= ~LIR_OpArrayCopy::src_objarray;
+  if (!dst_objarray)
+    flags &= ~LIR_OpArrayCopy::dst_objarray;
+
+  if (!x->arg_needs_null_check(0))
+    flags &= ~LIR_OpArrayCopy::src_null_check;
+  if (!x->arg_needs_null_check(2))
+    flags &= ~LIR_OpArrayCopy::dst_null_check;
+
+
   if (expected_type != NULL) {
-    // try to skip null checks
-    if (src->as_NewArray() != NULL)
+    Value length_limit = NULL;
+
+    IfOp* ifop = length->as_IfOp();
+    if (ifop != NULL) {
+      // look for expressions like min(v, a.length) which ends up as
+      //   x > y ? y : x  or  x >= y ? y : x
+      if ((ifop->cond() == If::gtr || ifop->cond() == If::geq) &&
+          ifop->x() == ifop->fval() &&
+          ifop->y() == ifop->tval()) {
+        length_limit = ifop->y();
+      }
+    }
+
+    // try to skip null checks and range checks
+    NewArray* src_array = src->as_NewArray();
+    if (src_array != NULL) {
       flags &= ~LIR_OpArrayCopy::src_null_check;
-    if (dst->as_NewArray() != NULL)
+      if (length_limit != NULL &&
+          src_array->length() == length_limit &&
+          is_constant_zero(src_pos)) {
+        flags &= ~LIR_OpArrayCopy::src_range_check;
+      }
+    }
+
+    NewArray* dst_array = dst->as_NewArray();
+    if (dst_array != NULL) {
       flags &= ~LIR_OpArrayCopy::dst_null_check;
+      if (length_limit != NULL &&
+          dst_array->length() == length_limit &&
+          is_constant_zero(dst_pos)) {
+        flags &= ~LIR_OpArrayCopy::dst_range_check;
+      }
+    }
 
     // check from incoming constant values
     if (positive_constant(src_pos))
@@ -788,6 +871,28 @@
     }
   }
 
+  IntConstant* src_int = src_pos->type()->as_IntConstant();
+  IntConstant* dst_int = dst_pos->type()->as_IntConstant();
+  if (src_int && dst_int) {
+    int s_offs = src_int->value();
+    int d_offs = dst_int->value();
+    if (src_int->value() >= dst_int->value()) {
+      flags &= ~LIR_OpArrayCopy::overlapping;
+    }
+    if (expected_type != NULL) {
+      BasicType t = expected_type->element_type()->basic_type();
+      int element_size = type2aelembytes(t);
+      if (((arrayOopDesc::base_offset_in_bytes(t) + s_offs * element_size) % HeapWordSize == 0) &&
+          ((arrayOopDesc::base_offset_in_bytes(t) + d_offs * element_size) % HeapWordSize == 0)) {
+        flags &= ~LIR_OpArrayCopy::unaligned;
+      }
+    }
+  } else if (src_pos == dst_pos || is_constant_zero(dst_pos)) {
+    // src and dest positions are the same, or dst is zero so assume
+    // nonoverlapping copy.
+    flags &= ~LIR_OpArrayCopy::overlapping;
+  }
+
   if (src == dst) {
     // moving within a single array so no type checks are needed
     if (flags & LIR_OpArrayCopy::type_check) {