Request for review (M): 7171890: C1: add Class.isInstance intrinsic
Christian Thalinger
christian.thalinger at oracle.com
Thu May 31 15:05:51 PDT 2012
On May 31, 2012, at 6:26 AM, Krystal Mok wrote:
> On Thu, May 31, 2012 at 3:10 PM, John Rose <john.r.rose at oracle.com> wrote:
> On May 30, 2012, at 7:55 PM, Krystal Mok wrote:
>
>> Yes, it's doable. I'll just take the same approach for clazz1.isAssignableFrom(clazz2).
>
> It's trickier, since you can't just repurpose the C1 InstanceOf node. It looks like you'll have to refactor machine-dependent code to cut in the new logic.
>
> Yes, I have noticed that already. It's not the same as the Class.isInstance(). The (quick-n-dirty) plan was to fold the case where both clazz1 and clazz2 are constants, and emit a leaf runtime call for non-constant cases. Since Class.isAssignableFrom() only throws NPE if any of clazz1 or clazz2 is null, it should be okay to make a leaf call after null-checking them.
>
> The complete solution, as you suggested, would have to involve changes to platform-dependent code.
>
> For a comparison, see inline_native_subtype_check in C2, versus the "_isInstance" cases of inline_native_Class_query. The intrinsic for Class.isAssignableFrom is surprisingly more complex and specialized than the intrinsic for Class.isInstance.
>
> (For C2-ish reasons, the intrinsic logic in library_call.cpp is machine-independent, so it's easier to do than in C1.)
>
> I did notice this from the start, too. It's so tempting to add finer-grain IR to C1 so that it can do more optimizations; but that feels against the theme of C1.
>
> Unless you find a simple way to manage the C1 changes, you might want to stick with isInstance only, this time around.
>
> Yes, I agree. I wouldn't mind making a more complete solution for C1 Class intrinsics in future changes.
>
> In any case, we'll try what you have done already; I am confident it will do good things for our dynamic language codes.
>
> Thanks, really looking forward to the numbers :-)
The numbers are okay; it shaves off about 9% of run time:
cthaling at intelsdv03.us.oracle.com:~/mlvm/jruby$ jruby -J-client -J-showversion -X+C bench/bench_red_black.rb
Picked up _JAVA_OPTIONS: -XX:+UnlockExperimentalVMOptions -XX:-AllowChainedMethodHandles -XX:+AllowLambdaForms -Xverify:all -esa -Xbootclasspath/p:/home/cthaling/mlvm/jdk/classes/
java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b40)
Java HotSpot(TM) Client VM (build 24.0-b08-internal, mixed mode)
17.479
GC.count = 46
10.25
GC.count = 54
9.732
GC.count = 61
9.633
GC.count = 68
9.568
GC.count = 74
9.499
GC.count = 81
9.634
GC.count = 87
9.787
GC.count = 94
9.739
GC.count = 101
9.702
GC.count = 107
Flat profile of 114.73 secs (10532 total ticks): main
Interpreted + native Method
2.6% 0 + 277 java.io.FileOutputStream.open
2.1% 0 + 221 java.io.FileOutputStream.close0
0.8% 87 + 0 bench.bench_red_black.method__27$RUBY$insert_helper
0.6% 65 + 0 bench.bench_red_black.method__16$RUBY$minimum
0.1% 0 + 15 java.lang.Class.forName0
0.1% 0 + 12 sun.misc.Unsafe.defineAnonymousClass
0.1% 1 + 11 org.jruby.Ruby.initCore
0.1% 10 + 0 bench.bench_red_black.method__25$RUBY$left_rotate
0.1% 7 + 0 bench.bench_red_black.method__14$RUBY$insert
0.1% 3 + 3 java.lang.Class.getDeclaredConstructors0
0.1% 0 + 6 org.jruby.parser.Ruby19Parser.<clinit>
0.0% 0 + 5 java.io.UnixFileSystem.getBooleanAttributes0
0.0% 2 + 3 java.lang.ClassLoader.defineClass1
0.0% 1 + 2 java.security.AccessController.doPrivileged
0.0% 3 + 0 org.objectweb.asm.Label.a
0.0% 3 + 0 java.lang.invoke.Invokers.lookupInvoker
0.0% 3 + 0 com.sun.xml.internal.ws.org.objectweb.asm.ClassWriter.<init>
0.0% 0 + 2 java.io.FileInputStream.open
0.0% 0 + 2 java.lang.invoke.MethodHandleNatives.resolve
0.0% 0 + 2 java.lang.Throwable.fillInStackTrace
0.0% 0 + 2 java.lang.ClassLoader.findBootstrapClass
0.0% 0 + 2 org.jruby.parser.Ruby19Parser.<init>
0.0% 2 + 0 org.jruby.util.ByteList.bytes
0.0% 2 + 0 org.jruby.internal.runtime.methods.InvocationMethodFactory.invokeCallConfigPost
0.0% 2 + 0 org.objectweb.asm.Frame.d
8.4% 277 + 606 Total interpreted (including elided)
Compiled + native Method
2.8% 1 + 295 bench.bench_red_black.method__16$RUBY$minimum
2.5% 3 + 261 bench.bench_red_black.method__27$RUBY$insert_helper
1.5% 0 + 163 bench.bench_red_black.method__25$RUBY$left_rotate
1.0% 0 + 109 bench.bench_red_black.method__14$RUBY$insert
0.0% 0 + 1 java.io.FilterInputStream.read
0.0% 1 + 0 org.jruby.runtime.CompiledBlockLight19.pre
0.0% 0 + 1 org.jruby.internal.runtime.methods.CompiledMethod.call
0.0% 1 + 0 org.jruby.runtime.invokedynamic.InvocationLinker.testRealClass
0.0% 1 + 0 org.jruby.RubyBasicObject.op_not_equal
0.0% 0 + 1 org.jruby.internal.runtime.methods.DynamicMethod.call
0.0% 1 + 0 org.jruby.runtime.scope.ManyVarsDynamicScope.getValueOrNil
0.0% 1 + 0 java.lang.invoke.LambdaForm$LFI39.invoke
0.0% 1 + 0 org.jruby.ast.executable.RuntimeCache.isCachedFrom
0.0% 0 + 1 org.jruby.javasupport.util.RuntimeHelpers.restructureBlockArgs19
0.0% 1 + 0 org.objectweb.asm.ClassWriter.toByteArray
0.0% 0 + 1 bench.bench_red_black.method__17$RUBY$maximum
0.0% 0 + 1 java.lang.String.replace
0.0% 1 + 0 bench.bench_red_black.method__2$RUBY$initialize
0.0% 1 + 0 bench.bench_red_black.method__26$RUBY$right_rotate
8.0% 13 + 834 Total compiled
Stub + native Method
80.6% 0 + 8494 java.lang.Class.isInstance
0.8% 1 + 87 java.io.FileOutputStream.open
0.8% 0 + 85 java.io.FileOutputStream.close0
0.3% 0 + 29 java.lang.Class.isPrimitive
0.1% 0 + 15 sun.misc.Unsafe.ensureClassInitialized
0.1% 0 + 9 java.lang.String.intern
0.1% 0 + 8 java.lang.Class.isArray
0.1% 0 + 7 java.lang.invoke.MethodHandleNatives.resolve
0.0% 2 + 3 java.security.AccessController.doPrivileged
0.0% 0 + 5 java.lang.System.arraycopy
0.0% 0 + 4 java.lang.Class.isInterface
0.0% 0 + 3 java.lang.Thread.currentThread
0.0% 0 + 3 java.lang.Throwable.fillInStackTrace
0.0% 0 + 3 sun.misc.Unsafe.defineAnonymousClass
0.0% 0 + 2 java.lang.Object.getClass
0.0% 0 + 2 java.lang.Class.getComponentType
0.0% 0 + 2 java.lang.ClassLoader.findLoadedClass0
0.0% 0 + 2 java.io.FileOutputStream.writeBytes
0.0% 0 + 1 java.lang.Thread.holdsLock
0.0% 0 + 1 sun.reflect.Reflection.getCallerClass
0.0% 0 + 1 java.lang.Class.getEnclosingMethod0
0.0% 0 + 1 java.lang.Object.clone
0.0% 0 + 1 java.lang.reflect.Array.newArray
0.0% 0 + 1 java.lang.invoke.MethodHandleNatives.setCallSiteTargetNormal
0.0% 0 + 1 sun.misc.Unsafe.compareAndSwapInt
83.3% 3 + 8771 Total stub (including elided)
cthaling at intelsdv03.us.oracle.com:~/mlvm/jruby$ jruby -J-client -J-showversion -X+C bench/bench_red_black.rb
Picked up _JAVA_OPTIONS: -XX:+UnlockExperimentalVMOptions -XX:-AllowChainedMethodHandles -XX:+AllowLambdaForms -Xverify:all -esa -Xbootclasspath/p:/home/cthaling/mlvm/jdk/classes/
java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b40)
Java HotSpot(TM) Client VM (build 24.0-b08-internal, mixed mode)
15.966
GC.count = 46
9.629
GC.count = 54
9.135
GC.count = 61
8.905
GC.count = 68
8.775
GC.count = 74
8.851
GC.count = 80
8.782
GC.count = 87
8.78
GC.count = 93
8.794
GC.count = 100
8.81
GC.count = 106
Flat profile of 108.49 secs (9711 total ticks): main
Interpreted + native Method
14.3% 1387 + 0 bench.bench_red_black.method__27$RUBY$insert_helper
13.3% 1294 + 0 bench.bench_red_black.method__16$RUBY$minimum
3.1% 0 + 303 java.io.FileOutputStream.open
2.2% 0 + 210 java.io.FileOutputStream.close0
1.8% 170 + 0 bench.bench_red_black.method__14$RUBY$insert
0.1% 0 + 13 java.lang.Class.forName0
0.1% 0 + 12 sun.misc.Unsafe.defineAnonymousClass
0.1% 2 + 10 org.jruby.Ruby.initCore
0.1% 0 + 8 java.io.UnixFileSystem.getBooleanAttributes0
0.1% 1 + 6 org.jruby.parser.Ruby19Parser.<clinit>
0.1% 7 + 0 bench.bench_red_black.method__28$RUBY$delete_fixup
0.1% 4 + 2 java.lang.Class.getDeclaredConstructors0
0.1% 2 + 4 java.lang.ClassLoader.defineClass1
0.1% 6 + 0 org.jruby.internal.runtime.methods.DynamicMethod.call
0.1% 5 + 0 org.jruby.RubyArray.eachCommon
0.1% 5 + 0 org.jruby.RubyArray.realloc
0.0% 0 + 4 java.lang.ClassLoader.findBootstrapClass
0.0% 0 + 4 java.io.FileOutputStream.writeBytes
0.0% 0 + 3 java.lang.invoke.MethodHandleNatives.resolve
0.0% 3 + 0 bench.bench_red_black.method__25$RUBY$left_rotate
0.0% 0 + 3 org.jruby.Ruby.initRoot
0.0% 0 + 2 java.lang.Throwable.fillInStackTrace
0.0% 2 + 0 org.jruby.compiler.impl.BaseBodyCompiler.invokeUtilityMethod
0.0% 2 + 0 org.jruby.runtime.opto.OptoFactory.newInvocationCompiler
0.0% 2 + 0 org.jruby.compiler.impl.InvokeDynamicCacheCompiler.cacheClosure19
37.6% 3024 + 623 Total interpreted (including elided)
Compiled + native Method
19.7% 321 + 1592 bench.bench_red_black.method__27$RUBY$insert_helper
17.1% 79 + 1586 bench.bench_red_black.method__25$RUBY$left_rotate
5.4% 147 + 374 bench.bench_red_black.method__14$RUBY$insert
4.5% 27 + 409 bench.bench_red_black.method__16$RUBY$minimum
3.8% 371 + 0 bench.bench_red_black.method__22$RUBY$search
1.4% 133 + 0 bench.bench_red_black.method__17$RUBY$maximum
1.1% 102 + 0 org.jruby.RubyBasicObject.op_not_equal
0.9% 90 + 0 org.jruby.RubyBasicObject.setVariable
0.6% 56 + 0 org.jruby.ast.executable.RuntimeCache.isCachedFrom
0.5% 53 + 0 org.jruby.runtime.CompiledBlockLight19.pre
0.5% 49 + 0 org.jruby.runtime.CompiledBlock19.yield
0.3% 28 + 0 org.jruby.runtime.ThreadContext.pushCallFrame
0.3% 25 + 0 org.jruby.runtime.scope.ManyVarsDynamicScope.getValueOrNil
0.2% 24 + 0 org.jruby.MetaClass.getRealClass
0.2% 21 + 0 bench.bench_red_black.method__18$RUBY$successor
0.2% 16 + 0 org.jruby.RubyFixnum.op_plus_one
0.2% 16 + 0 bench.bench_red_black.method__19$RUBY$predecessor
0.1% 14 + 0 bench.bench_red_black.method__2$RUBY$initialize
0.1% 13 + 0 org.jruby.RubyObject$1.allocate
0.1% 13 + 0 bench$bench_red_black$method__13$RUBY$add.call
0.1% 13 + 0 bench.bench_red_black.method__28$RUBY$delete_fixup
0.1% 11 + 0 org.jruby.RubyRandom.randCommon19
0.1% 10 + 0 java.util.concurrent.atomic.AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl.compareAndSet
0.1% 9 + 1 org.jruby.RubyFixnum.times
0.1% 10 + 0 bench.bench_red_black.method__20$RUBY$inorder_walk
59.5% 1801 + 3974 Total compiled (including elided)
Stub + native Method
0.9% 0 + 86 java.io.FileOutputStream.open
0.7% 0 + 71 java.io.FileOutputStream.close0
0.2% 0 + 22 java.lang.Class.isPrimitive
0.2% 0 + 15 sun.misc.Unsafe.ensureClassInitialized
0.1% 0 + 12 java.lang.Class.isArray
0.1% 0 + 7 java.lang.invoke.MethodHandleNatives.resolve
0.1% 0 + 5 java.lang.String.intern
0.1% 0 + 5 java.lang.Class.isInterface
0.0% 0 + 4 java.lang.Class.getComponentType
0.0% 0 + 4 java.lang.Object.clone
0.0% 1 + 3 java.security.AccessController.doPrivileged
0.0% 0 + 4 sun.misc.Unsafe.defineAnonymousClass
0.0% 0 + 3 java.lang.System.arraycopy
0.0% 0 + 2 java.lang.ClassLoader.findLoadedClass0
0.0% 0 + 2 java.util.zip.Inflater.inflateBytes
0.0% 0 + 1 java.lang.Object.getClass
0.0% 0 + 1 java.lang.Class.getDeclaringClass
0.0% 0 + 1 java.lang.Class.isAssignableFrom
0.0% 0 + 1 java.lang.Throwable.fillInStackTrace
0.0% 0 + 1 java.security.AccessController.doPrivileged
0.0% 0 + 1 sun.misc.Unsafe.getObjectVolatile
0.0% 0 + 1 sun.misc.Unsafe.getInt
0.0% 0 + 1 java.io.FileOutputStream.writeBytes
2.6% 1 + 253 Total stub
The problem why we don't see a much bigger improvement is that most of the time (I'd say 99% of the time) Class.cast isn't inlined in C1 because it's too big, e.g.:
@ 33 java.lang.invoke.LambdaForm$LFI67/25137260::invoke (32 bytes)
@ 15 java.lang.invoke.LambdaForm$LFI1/13330648::invoke (31 bytes)
@ 27 sun.invoke.util.ValueConversions::castReference (6 bytes)
@ 2 java.lang.Class::cast (27 bytes) callee is too large
@ 28 org.jruby.RubyBasicObject::op_not (20 bytes)
@ 1 org.jruby.runtime.ThreadContext::getRuntime (5 bytes)
@ 5 org.jruby.RubyBasicObject::isTrue (15 bytes)
@ 16 org.jruby.Ruby::newBoolean (16 bytes)
and we have to go the out-of-line route.
-- Chris
>
> Thanks,
> Kris
>
> Thanks,
> — John
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/attachments/20120531/7e663666/attachment-0001.html
More information about the hotspot-compiler-dev
mailing list