7171890: C1: add Class.isInstance intrinsic
authorroland
Tue, 05 Jun 2012 10:15:27 +0200
changeset 12949 e125ba4c16bd
parent 12948 51a31186c84f
child 12950 ab4f4afb3988
7171890: C1: add Class.isInstance intrinsic Summary: Class.cast which calls Class.isInstance is heavily used by the new JSR 292 implementation Reviewed-by: roland Contributed-by: Krystal Mok <rednaxelafx@gmail.com>
hotspot/src/share/vm/c1/c1_Canonicalizer.cpp
hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
hotspot/src/share/vm/c1/c1_LIRGenerator.cpp
hotspot/src/share/vm/c1/c1_LIRGenerator.hpp
hotspot/src/share/vm/c1/c1_Runtime1.cpp
hotspot/src/share/vm/c1/c1_Runtime1.hpp
--- a/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp	Fri Jun 01 11:25:12 2012 -0700
+++ b/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp	Tue Jun 05 10:15:27 2012 +0200
@@ -456,6 +456,28 @@
     }
     break;
   }
+  case vmIntrinsics::_isInstance          : {
+    assert(x->number_of_arguments() == 2, "wrong type");
+
+    InstanceConstant* c = x->argument_at(0)->type()->as_InstanceConstant();
+    if (c != NULL && !c->value()->is_null_object()) {
+      // ciInstance::java_mirror_type() returns non-NULL only for Java mirrors
+      ciType* t = c->value()->as_instance()->java_mirror_type();
+      if (t->is_klass()) {
+        // substitute cls.isInstance(obj) of a constant Class into
+        // an InstantOf instruction
+        InstanceOf* i = new InstanceOf(t->as_klass(), x->argument_at(1), x->state());
+        set_canonical(i);
+        // and try to canonicalize even further
+        do_InstanceOf(i);
+      } else {
+        assert(t->is_primitive_type(), "should be a primitive type");
+        // cls.isInstance(obj) always returns false for primitive classes
+        set_constant(0);
+      }
+    }
+    break;
+  }
   }
 }
 
--- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp	Fri Jun 01 11:25:12 2012 -0700
+++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp	Tue Jun 05 10:15:27 2012 +0200
@@ -3170,6 +3170,7 @@
       break;
 
     case vmIntrinsics::_getClass      :
+    case vmIntrinsics::_isInstance    :
       if (!InlineClassNatives) return false;
       preserves_state = true;
       break;
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp	Fri Jun 01 11:25:12 2012 -0700
+++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp	Tue Jun 05 10:15:27 2012 +0200
@@ -1242,6 +1242,36 @@
               NULL   /* info */);
 }
 
+// Example: clazz.isInstance(object)
+void LIRGenerator::do_isInstance(Intrinsic* x) {
+  assert(x->number_of_arguments() == 2, "wrong type");
+
+  // TODO could try to substitute this node with an equivalent InstanceOf
+  // if clazz is known to be a constant Class. This will pick up newly found
+  // constants after HIR construction. I'll leave this to a future change.
+
+  // as a first cut, make a simple leaf call to runtime to stay platform independent.
+  // could follow the aastore example in a future change.
+
+  LIRItem clazz(x->argument_at(0), this);
+  LIRItem object(x->argument_at(1), this);
+  clazz.load_item();
+  object.load_item();
+  LIR_Opr result = rlock_result(x);
+
+  // need to perform null check on clazz
+  if (x->needs_null_check()) {
+    CodeEmitInfo* info = state_for(x);
+    __ null_check(clazz.result(), info);
+  }
+
+  LIR_Opr call_result = call_runtime(clazz.value(), object.value(),
+                                     CAST_FROM_FN_PTR(address, Runtime1::is_instance_of),
+                                     x->type(),
+                                     NULL); // NULL CodeEmitInfo results in a leaf call
+  __ move(call_result, result);
+}
+
 // Example: object.getClass ()
 void LIRGenerator::do_getClass(Intrinsic* x) {
   assert(x->number_of_arguments() == 1, "wrong type");
@@ -2951,6 +2981,7 @@
     break;
 
   case vmIntrinsics::_Object_init:    do_RegisterFinalizer(x); break;
+  case vmIntrinsics::_isInstance:     do_isInstance(x);    break;
   case vmIntrinsics::_getClass:       do_getClass(x);      break;
   case vmIntrinsics::_currentThread:  do_currentThread(x); break;
 
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp	Fri Jun 01 11:25:12 2012 -0700
+++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp	Tue Jun 05 10:15:27 2012 +0200
@@ -238,6 +238,7 @@
   LIR_Opr getThreadPointer();
 
   void do_RegisterFinalizer(Intrinsic* x);
+  void do_isInstance(Intrinsic* x);
   void do_getClass(Intrinsic* x);
   void do_currentThread(Intrinsic* x);
   void do_MathIntrinsic(Intrinsic* x);
--- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp	Fri Jun 01 11:25:12 2012 -0700
+++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp	Tue Jun 05 10:15:27 2012 +0200
@@ -294,6 +294,7 @@
   FUNCTION_CASE(entry, SharedRuntime::lrem);
   FUNCTION_CASE(entry, SharedRuntime::dtrace_method_entry);
   FUNCTION_CASE(entry, SharedRuntime::dtrace_method_exit);
+  FUNCTION_CASE(entry, is_instance_of);
   FUNCTION_CASE(entry, trace_block_entry);
 #ifdef TRACE_HAVE_INTRINSICS
   FUNCTION_CASE(entry, TRACE_TIME_METHOD);
@@ -1270,6 +1271,19 @@
 JRT_END
 
 
+JRT_LEAF(int, Runtime1::is_instance_of(oopDesc* mirror, oopDesc* obj))
+  // had to return int instead of bool, otherwise there may be a mismatch
+  // between the C calling convention and the Java one.
+  // e.g., on x86, GCC may clear only %al when returning a bool false, but
+  // JVM takes the whole %eax as the return value, which may misinterpret
+  // the return value as a boolean true.
+
+  assert(mirror != NULL, "should null-check on mirror before calling");
+  klassOop k = java_lang_Class::as_klassOop(mirror);
+  return (k != NULL && obj != NULL && obj->is_a(k)) ? 1 : 0;
+JRT_END
+
+
 #ifndef PRODUCT
 void Runtime1::print_statistics() {
   tty->print_cr("C1 Runtime statistics:");
--- a/hotspot/src/share/vm/c1/c1_Runtime1.hpp	Fri Jun 01 11:25:12 2012 -0700
+++ b/hotspot/src/share/vm/c1/c1_Runtime1.hpp	Tue Jun 05 10:15:27 2012 +0200
@@ -186,6 +186,7 @@
   static int  arraycopy(oopDesc* src, int src_pos, oopDesc* dst, int dst_pos, int length);
   static void primitive_arraycopy(HeapWord* src, HeapWord* dst, int length);
   static void oop_arraycopy(HeapWord* src, HeapWord* dst, int length);
+  static int  is_instance_of(oopDesc* mirror, oopDesc* obj);
 
   static void print_statistics()                 PRODUCT_RETURN;
 };