Tue, 05 Jun 2012 10:15:27 +0200
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>
1.1 --- a/src/share/vm/c1/c1_Canonicalizer.cpp Fri Jun 01 11:25:12 2012 -0700 1.2 +++ b/src/share/vm/c1/c1_Canonicalizer.cpp Tue Jun 05 10:15:27 2012 +0200 1.3 @@ -456,6 +456,28 @@ 1.4 } 1.5 break; 1.6 } 1.7 + case vmIntrinsics::_isInstance : { 1.8 + assert(x->number_of_arguments() == 2, "wrong type"); 1.9 + 1.10 + InstanceConstant* c = x->argument_at(0)->type()->as_InstanceConstant(); 1.11 + if (c != NULL && !c->value()->is_null_object()) { 1.12 + // ciInstance::java_mirror_type() returns non-NULL only for Java mirrors 1.13 + ciType* t = c->value()->as_instance()->java_mirror_type(); 1.14 + if (t->is_klass()) { 1.15 + // substitute cls.isInstance(obj) of a constant Class into 1.16 + // an InstantOf instruction 1.17 + InstanceOf* i = new InstanceOf(t->as_klass(), x->argument_at(1), x->state()); 1.18 + set_canonical(i); 1.19 + // and try to canonicalize even further 1.20 + do_InstanceOf(i); 1.21 + } else { 1.22 + assert(t->is_primitive_type(), "should be a primitive type"); 1.23 + // cls.isInstance(obj) always returns false for primitive classes 1.24 + set_constant(0); 1.25 + } 1.26 + } 1.27 + break; 1.28 + } 1.29 } 1.30 } 1.31
2.1 --- a/src/share/vm/c1/c1_GraphBuilder.cpp Fri Jun 01 11:25:12 2012 -0700 2.2 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Tue Jun 05 10:15:27 2012 +0200 2.3 @@ -3170,6 +3170,7 @@ 2.4 break; 2.5 2.6 case vmIntrinsics::_getClass : 2.7 + case vmIntrinsics::_isInstance : 2.8 if (!InlineClassNatives) return false; 2.9 preserves_state = true; 2.10 break;
3.1 --- a/src/share/vm/c1/c1_LIRGenerator.cpp Fri Jun 01 11:25:12 2012 -0700 3.2 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Tue Jun 05 10:15:27 2012 +0200 3.3 @@ -1242,6 +1242,36 @@ 3.4 NULL /* info */); 3.5 } 3.6 3.7 +// Example: clazz.isInstance(object) 3.8 +void LIRGenerator::do_isInstance(Intrinsic* x) { 3.9 + assert(x->number_of_arguments() == 2, "wrong type"); 3.10 + 3.11 + // TODO could try to substitute this node with an equivalent InstanceOf 3.12 + // if clazz is known to be a constant Class. This will pick up newly found 3.13 + // constants after HIR construction. I'll leave this to a future change. 3.14 + 3.15 + // as a first cut, make a simple leaf call to runtime to stay platform independent. 3.16 + // could follow the aastore example in a future change. 3.17 + 3.18 + LIRItem clazz(x->argument_at(0), this); 3.19 + LIRItem object(x->argument_at(1), this); 3.20 + clazz.load_item(); 3.21 + object.load_item(); 3.22 + LIR_Opr result = rlock_result(x); 3.23 + 3.24 + // need to perform null check on clazz 3.25 + if (x->needs_null_check()) { 3.26 + CodeEmitInfo* info = state_for(x); 3.27 + __ null_check(clazz.result(), info); 3.28 + } 3.29 + 3.30 + LIR_Opr call_result = call_runtime(clazz.value(), object.value(), 3.31 + CAST_FROM_FN_PTR(address, Runtime1::is_instance_of), 3.32 + x->type(), 3.33 + NULL); // NULL CodeEmitInfo results in a leaf call 3.34 + __ move(call_result, result); 3.35 +} 3.36 + 3.37 // Example: object.getClass () 3.38 void LIRGenerator::do_getClass(Intrinsic* x) { 3.39 assert(x->number_of_arguments() == 1, "wrong type"); 3.40 @@ -2951,6 +2981,7 @@ 3.41 break; 3.42 3.43 case vmIntrinsics::_Object_init: do_RegisterFinalizer(x); break; 3.44 + case vmIntrinsics::_isInstance: do_isInstance(x); break; 3.45 case vmIntrinsics::_getClass: do_getClass(x); break; 3.46 case vmIntrinsics::_currentThread: do_currentThread(x); break; 3.47
4.1 --- a/src/share/vm/c1/c1_LIRGenerator.hpp Fri Jun 01 11:25:12 2012 -0700 4.2 +++ b/src/share/vm/c1/c1_LIRGenerator.hpp Tue Jun 05 10:15:27 2012 +0200 4.3 @@ -238,6 +238,7 @@ 4.4 LIR_Opr getThreadPointer(); 4.5 4.6 void do_RegisterFinalizer(Intrinsic* x); 4.7 + void do_isInstance(Intrinsic* x); 4.8 void do_getClass(Intrinsic* x); 4.9 void do_currentThread(Intrinsic* x); 4.10 void do_MathIntrinsic(Intrinsic* x);
5.1 --- a/src/share/vm/c1/c1_Runtime1.cpp Fri Jun 01 11:25:12 2012 -0700 5.2 +++ b/src/share/vm/c1/c1_Runtime1.cpp Tue Jun 05 10:15:27 2012 +0200 5.3 @@ -294,6 +294,7 @@ 5.4 FUNCTION_CASE(entry, SharedRuntime::lrem); 5.5 FUNCTION_CASE(entry, SharedRuntime::dtrace_method_entry); 5.6 FUNCTION_CASE(entry, SharedRuntime::dtrace_method_exit); 5.7 + FUNCTION_CASE(entry, is_instance_of); 5.8 FUNCTION_CASE(entry, trace_block_entry); 5.9 #ifdef TRACE_HAVE_INTRINSICS 5.10 FUNCTION_CASE(entry, TRACE_TIME_METHOD); 5.11 @@ -1270,6 +1271,19 @@ 5.12 JRT_END 5.13 5.14 5.15 +JRT_LEAF(int, Runtime1::is_instance_of(oopDesc* mirror, oopDesc* obj)) 5.16 + // had to return int instead of bool, otherwise there may be a mismatch 5.17 + // between the C calling convention and the Java one. 5.18 + // e.g., on x86, GCC may clear only %al when returning a bool false, but 5.19 + // JVM takes the whole %eax as the return value, which may misinterpret 5.20 + // the return value as a boolean true. 5.21 + 5.22 + assert(mirror != NULL, "should null-check on mirror before calling"); 5.23 + klassOop k = java_lang_Class::as_klassOop(mirror); 5.24 + return (k != NULL && obj != NULL && obj->is_a(k)) ? 1 : 0; 5.25 +JRT_END 5.26 + 5.27 + 5.28 #ifndef PRODUCT 5.29 void Runtime1::print_statistics() { 5.30 tty->print_cr("C1 Runtime statistics:");
6.1 --- a/src/share/vm/c1/c1_Runtime1.hpp Fri Jun 01 11:25:12 2012 -0700 6.2 +++ b/src/share/vm/c1/c1_Runtime1.hpp Tue Jun 05 10:15:27 2012 +0200 6.3 @@ -186,6 +186,7 @@ 6.4 static int arraycopy(oopDesc* src, int src_pos, oopDesc* dst, int dst_pos, int length); 6.5 static void primitive_arraycopy(HeapWord* src, HeapWord* dst, int length); 6.6 static void oop_arraycopy(HeapWord* src, HeapWord* dst, int length); 6.7 + static int is_instance_of(oopDesc* mirror, oopDesc* obj); 6.8 6.9 static void print_statistics() PRODUCT_RETURN; 6.10 };