# HG changeset patch # User roland # Date 1338884127 -7200 # Node ID e125ba4c16bdfce972cb9dce83e21c9d7aa2a915 # Parent 51a31186c84f948f59c362f43f9dc38dd8bc224b 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 diff -r 51a31186c84f -r e125ba4c16bd hotspot/src/share/vm/c1/c1_Canonicalizer.cpp --- 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; + } } } diff -r 51a31186c84f -r e125ba4c16bd hotspot/src/share/vm/c1/c1_GraphBuilder.cpp --- 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; diff -r 51a31186c84f -r e125ba4c16bd hotspot/src/share/vm/c1/c1_LIRGenerator.cpp --- 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; diff -r 51a31186c84f -r e125ba4c16bd hotspot/src/share/vm/c1/c1_LIRGenerator.hpp --- 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); diff -r 51a31186c84f -r e125ba4c16bd hotspot/src/share/vm/c1/c1_Runtime1.cpp --- 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:"); diff -r 51a31186c84f -r e125ba4c16bd hotspot/src/share/vm/c1/c1_Runtime1.hpp --- 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; };