2525import java .io .FileOutputStream ;
2626import java .io .IOException ;
2727import java .lang .classfile .*;
28- import java .lang .classfile .constantpool .ClassEntry ;
2928import java .lang .constant .ClassDesc ;
3029import java .lang .constant .ConstantDescs ;
3130import java .lang .constant .MethodTypeDesc ;
32- import java .lang .invoke .*;
3331import java .security .SecureClassLoader ;
34- import java .util .Arrays ;
3532import java .util .List ;
36- import java .util .Random ;
3733import java .util .concurrent .TimeUnit ;
38- import java .util .concurrent .atomic .AtomicReference ;
3934import java .util .function .Function ;
40- import java .util .stream .Stream ;
4135import org .openjdk .jmh .annotations .*;
4236import org .openjdk .jmh .infra .*;
4337
4438import static java .lang .classfile .ClassFile .*;
45- import static java .lang .invoke .MethodType .methodType ;
4639
4740
4841@ BenchmarkMode (Mode .AverageTime )
@@ -228,10 +221,10 @@ public Class<?>[] genClasses(Class<?>[] interfaces, int length) {
228221 return klasses ;
229222 }
230223
231- private static void genClassBody (ClassBuilder clb , List <ClassDesc > interfaceDesc ) {
224+ private static void genClassBody (ClassBuilder clb , List <ClassDesc > interfaceDescriptors ) {
232225 clb = clb .withFlags (ACC_PUBLIC );
233226 var cpool = clb .constantPool ();
234- var interfaceEntries = interfaceDesc .stream ().map (cpool ::classEntry ).toList ();
227+ var interfaceEntries = interfaceDescriptors .stream ().map (cpool ::classEntry ).toList ();
235228 var CD_AClass = ClassDesc .of (AClass .class .getName ());
236229 clb .withSuperclass (CD_AClass )
237230 .withInterfaces (interfaceEntries )
@@ -268,12 +261,21 @@ private static void genClassBody(ClassBuilder clb, List<ClassDesc> interfaceDesc
268261 .aload (1 )
269262 .instanceOf (ClassDesc .of ("J" ))
270263 .ireturn ()
264+ ))
265+ .withMethod ("checkCast" ,
266+ MethodTypeDesc .of (ConstantDescs .CD_Object ,
267+ ConstantDescs .CD_Object ),
268+ ACC_PUBLIC ,
269+ mb -> mb .withCode (cob -> cob
270+ .aload (1 )
271+ .checkcast (interfaceEntries .get (interfaceEntries .size () - 1 ))
272+ .areturn ()
271273 ));
272274 }
273275
274- private Class <?> genClass (List <ClassDesc > interfaceDesc , String name ) {
276+ private Class <?> genClass (List <ClassDesc > interfaceDescriptors , String name ) {
275277 byte [] bytes = ClassFile .of ()
276- .build (ClassDesc .of (name ), clb -> genClassBody (clb , interfaceDesc ));
278+ .build (ClassDesc .of (name ), clb -> genClassBody (clb , interfaceDescriptors ));
277279 return LOADER .defineClass (name , bytes );
278280 }
279281
@@ -284,13 +286,11 @@ private Class<?> genClass(Class<?>[] interfaces, String name) {
284286
285287 AClass testInstance ;
286288 Object [] testInstances ;
289+ public final static int TESTINSTANCES =10 ;
287290 Class <?> targetInterface ;
288291
289292 Class testInterface ;
290293
291- static MethodHandles .Lookup lookup = MethodHandles .lookup ();
292- static MethodType mt = MethodType .methodType (boolean .class , Object .class );
293-
294294 @ Setup
295295 public void init () throws Exception {
296296 LOADER = new MyLoader (AClass .class .getClassLoader ());
@@ -304,12 +304,22 @@ public void init() throws Exception {
304304 Class <?> barf = genClass (interfaces , "Humongous" );
305305 testInstance = (AClass )(barf .getConstructor ().newInstance ());
306306
307- testInstances = new Object [20 ];
307+ testInstances = new Object [TESTINSTANCES ];
308308 for (int i = 0 ; i < testInstances .length ; i ++) {
309309 testInstances [i ] = genClass (interfaces , String .format ("Humongous%02d" , i ))
310310 .getConstructor ().newInstance ();
311311 }
312312
313+ System .out .println ("testInstance = " + testInstance );
314+ }
315+
316+ private static void test (Object obj , Class <?> cls , boolean expected ) {
317+ if (cls .isInstance (obj ) != expected ) {
318+ throw new InternalError (obj .getClass () + " " + cls + " " + expected );
319+ }
320+ }
321+
322+ @ Warmup public void warmup () {
313323 for (int i = 0 ; i < 20_000 ; i ++) {
314324 testInterface = interfaces [i % interfaces .length ];
315325 Class <?> s = getSuper (i );
@@ -322,30 +332,9 @@ public void init() throws Exception {
322332 test (obj07 , s , s .isInstance (obj07 ));
323333 test (obj08 , s , s .isInstance (obj08 ));
324334 test (obj09 , s , s .isInstance (obj09 ));
325- // testPositiveN();
326335 }
327-
328- System .out .println ("testInstance = " + testInstance );
329336 }
330337
331- private static void test (Object obj , Class <?> cls , boolean expected ) {
332- if (cls .isInstance (obj ) != expected ) {
333- throw new InternalError (obj .getClass () + " " + cls + " " + expected );
334- }
335- }
336-
337- @ Benchmark
338- public void instanceOfPositive (Blackhole bh ) {
339- for (Object obj : testInstances ) {
340- bh .consume (testInstance .instanceOfPositive (obj ));
341- }
342- }
343- @ Benchmark
344- public void instanceOfNegative (Blackhole bh ) {
345- for (Object obj : testInstances ) {
346- bh .consume (testInstance .instanceOfNegative (obj ));
347- }
348- }
349338 @ Benchmark
350339 public void testPositive01 () {
351340 test (obj01 , I01 .class , true );
@@ -487,11 +476,37 @@ public void testPositive01() {
487476 test (obj64 , J .class , false );
488477 }
489478
479+ // Arbitrary-sized tests.
490480 @ Benchmark public void testPositiveN () {
491481 test (testInstance , interfaces [interfaces .length - 1 ], true );
492482 }
493483 @ Benchmark public void testNegativeN () {
494484 test (testInstance , J .class , false );
495485 }
496486
487+ // These invoke obj instanceof T. We use an array of testInstances
488+ // instead of a single instance to prevent C2 from removing our
489+ // lookup.
490+ @ Benchmark
491+ @ OperationsPerInvocation (TESTINSTANCES )
492+ public void checkCast (Blackhole bh ) {
493+ for (Object obj : testInstances ) {
494+ bh .consume (testInstance .checkCast (obj ));
495+ }
496+ }
497+ @ Benchmark
498+ @ OperationsPerInvocation (TESTINSTANCES )
499+ public void instanceOfPositive (Blackhole bh ) {
500+ for (Object obj : testInstances ) {
501+ bh .consume (testInstance .instanceOfPositive (obj ));
502+ }
503+ }
504+ @ Benchmark
505+ @ OperationsPerInvocation (TESTINSTANCES )
506+ public void instanceOfNegative (Blackhole bh ) {
507+ for (Object obj : testInstances ) {
508+ bh .consume (testInstance .instanceOfNegative (obj ));
509+ }
510+ }
511+
497512}
0 commit comments