More on: Small static method marked not entrant, inlining reversed?

Rémi Forax forax at univ-mlv.fr
Wed Sep 22 02:30:39 PDT 2010


Le 21/09/2010 21:48, Tom Rodriguez a écrit :
> Thanks for the test case.  The reason it works well for C1 is that we have an explicit check for single implementor interfaces and insert an extra checkcast to confirm that the type really is the type we expect.  The extra check is needed since interface types aren't actually checked by the verifier.  In your example the extra check isn't actually needed since all array stores are actually type checked so any type loaded from the array must actually implement the interface.  C2 generally relies on type profiling to get cases like this but since type profiling is tracking the type of the receiver instead of the actual method being invoked it doesn't handle this case that well.  It's not hard to do something better for this case.  I filed 6986483 for this.
>
> tom
>    

Thanks Tom,
I know since a long time that the verifier doesn't check interface but
I have discovered recently the runtime implication.

I wonder if the fix can improve performance of benchmarks that use 
java.util collection,
because this API uses a similar class hierarchy scheme.

Rémi

> On Sep 18, 2010, at 11:25 AM, Rémi Forax wrote:
>
>    
>> I take a little time to create a simple test case to reproduce a bug
>> found by Charles Nutter with c2.
>> see http://groups.google.com/group/jvm-languages/browse_thread/thread/6c9e05ecd28fdcd4#
>>
>> Here is the test case,
>> There is 3 classes A, B, C that inherit from AbstractFoo that implements Foo.
>> The method test do a virtual call to check() and because
>> check() is implemented in AbstractFoo we expect that this call should be
>> de-virtualized then inlined.
>>
>> c2 fails, foo.check() is compiled as a virtual call :(
>> With c1, there is no problem, CHA works correctly.
>>
>> Rémi
>>
>> ------------------------------------------------------------------------------------------------
>>
>> public class InlineTest {
>>   interface Foo {
>>     public boolean check(int generation);
>>   }
>>
>>   static class AbstractFoo implements Foo {
>>     private final int value;
>>
>>     protected AbstractFoo(int value) {
>>       this.value = value;
>>     }
>>
>>     public boolean check(int generation) {
>>       return this.getClass().hashCode() - value == generation;
>>     }
>>   }
>>
>>   static class A extends AbstractFoo {
>>     public A(int value) {
>>       super(value);
>>     }
>>   }
>>   static class B extends AbstractFoo {
>>     public B(int value) {
>>       super(value);
>>     }
>>   }
>>   static class C extends AbstractFoo {
>>     public C(int value) {
>>       super(value);
>>     }
>>   }
>>
>>   private static final int CONST = A.class.hashCode();
>>
>>   private static int count;
>>
>>   private static void test(Foo foo) {
>>     if (foo.check(0)) {
>>         count += 2;
>>         //System.out.println("foo");
>>     } else {
>>         count += 1;
>>         //System.out.println("bar");
>>     }
>>   }
>>
>>   public static void main(String[] args) {
>>     Foo[] array = new Foo[100000];
>>     int threshold = 20000;
>>     for(int i=0; i<threshold; i++) {
>>       array[i] = new A(CONST);
>>     }
>>
>>     for(int i=threshold; i<array.length; i++) {
>>       array[i] = (i%2 == 0)? new B(0): new C(CONST);
>>     }
>>
>>     for(int i=0; i<array.length; i++) {
>>       test(array[i]);
>>     }
>>
>>     System.out.println(count);
>>   }
>> }
>>      
>    



More information about the hotspot-compiler-dev mailing list