6894807: problem with interfaces in C2 type system

Vladimir Kozlov Vladimir.Kozlov at Sun.COM
Fri Oct 23 21:50:51 PDT 2009


I am investigating 6894807: No ClassCastException for HashAttributeSet constructors if run with -Xcomp

Because of Escape Analysis is on by default all constructors are inlined
in the test case and object scalar replaced. But due to, I think,
the problem in C2 type system the result is incorrect.

We should check if interface is exact before replacing
it with j.l.O in TypeOopPtr::filter() for the case
(exact interface)->filter(j.l.O).

Vladimir

----------------------------------------------------------------
Test code expects ClassCastException exception:

import javax.print.attribute.Attribute;
import javax.print.attribute.AttributeSet;
import javax.print.attribute.DocAttribute;
import javax.print.attribute.HashAttributeSet;
import javax.print.attribute.standard.JobState;

         try {
             new MyHashAttributeSet(JobState.CANCELED, DocAttribute.class);
             System.out.println("No ClassCastException in t2!");
         } catch (ClassCastException _) {
         }

EA forces to inline all constructors for MyHashAttributeSet:

class MyHashAttributeSet extends HashAttributeSet{
     MyHashAttributeSet(Attribute attribute,
                            Class interfaceName){
         super(attribute, interfaceName);
     }

then

     protected HashAttributeSet(Attribute attribute, Class<?> interfaceName) {
         if (interfaceName == null) {
             throw new NullPointerException("null interface");
         }
         myInterface = interfaceName;
         add (attribute);
     }

add() is inlined also:

     public boolean add(Attribute attribute) {
         Object oldAttribute =
             attrMap.put(attribute.getCategory(),
                         AttributeSetUtilities.
                         verifyAttributeValue(attribute, myInterface));
         return (!attribute.equals(oldAttribute));
     }

and verifyAttributeValue(attribute, myInterface) is inlined as well:

     public static Attribute
         verifyAttributeValue(Object object, Class<?> interfaceName) {

         if (object == null) {
             throw new NullPointerException();
         }
         else if (interfaceName.isInstance (object)) {
             return (Attribute) object;
         } else {
             throw new ClassCastException();
         }
     }

object is JobState.CANCELED which is

     public static final JobState CANCELED = new JobState (7);

and interfaceName is DocAttribute.class where

public interface DocAttribute extends Attribute {}

----------------------------------------------------------------
So we end up with

(DocAttribute.class).isInstance(JobState.CANCELED)

We have intrinsic for isInstance() for which we generated

   // Now load the mirror's klass metaobject, and null-check it.
   // Side-effects region with the control path if the klass is null.
   Node* kls = load_klass_from_mirror(mirror, never_see_null, nargs,
                                      region, _prim_path);

   case vmIntrinsics::_isInstance:
     // nothing is an instance of a primitive type
     query_value = gen_instanceof(obj, kls);

where due to NULL check we have next CastPP for DocAttribute.class:
[t at 19 l at 19]: print kls->dump(1)
  390    LoadKlass       === _  7  389  [[ 391  396 ]]  @rawptr:BotPTR, idx=Raw; # *  Klass: * !jvms: AttributeSetUtilities::verifyAttributeValue @ bci:14 HashAttributeSet::add @ bci:15 HashAttributeSet::<init> @ bci:36 MyHashAttributeSet::<init> @ bci:3 InstanceCheck::t2 @ bci:10
  395    IfTrue  ===  393  [[ 370  396 ]] #1 !jvms: AttributeSetUtilities::verifyAttributeValue @ bci:14 HashAttributeSet::add @ bci:15 HashAttributeSet::<init> @ bci:36 MyHashAttributeSet::<init> @ bci:3 InstanceCheck::t2 @ bci:10
  396    CastPP  ===  395  390  [[ 409  409  413  432  427 ]]  #klass java/lang/Object: 0x0811c7e0 *  Klass:klass java/lang/Object: 0x0811c7e0 * !jvms: AttributeSetUtilities::verifyAttributeValue @ bci:14 HashAttributeSet::add @ bci:15 HashAttributeSet::<init> @ bci:36 MyHashAttributeSet::<init> @ 
bci:3 InstanceCheck::t2 @ bci:10

During IGVN LoadKlass(390) transformed to constant klass which is interface:

  702    ConP    ===  0  [[ 396  391 ]]  #precise klass javax/print/attribute/DocAttribute: 0x08407298:Constant:exact *  Interface:precise klass javax/print/attribute/DocAttribute: 0x08407298:Constant:exact *
  396    CastPP  ===  395  702  [[ 409  409  413  432  427 ]]  #klass java/lang/Object: 0x0811c7e0 *  Klass:klass java/lang/Object: 0x0811c7e0 * !jvms: AttributeSetUtilities::verifyAttributeValue @ bci:14 HashAttributeSet::add @ bci:15 HashAttributeSet::<init> @ bci:36 MyHashAttributeSet::<init> @ 
bci:3 InstanceCheck::t2 @ bci:10

ConstraintCastNode::Value() calls TypeOopPtr::filter() method
which, I think, returns incorrect result:

[t at 19 l at 19]: print ft->dump()
precise klass javax/print/attribute/DocAttribute: 0x08407298:Constant:exact *

[t at 19 l at 19]: print ftkp->klass()->print()
<ciInstanceKlass name=javax/print/attribute/DocAttribute loader=0x0 loaded=true initialized=false finalized=false subklass=false size=9 flags=public,interface,abstract mirror=PRESENT ident=655 PERM address=0x8407298>

[t at 19 l at 19]: print ktkp->klass()->print()
<ciInstanceKlass name=java/lang/Object loader=0x0 loaded=true initialized=true finalized=false subklass=true size=8 flags=public,super mirror=PRESENT ident=558 PERM address=0x811c7e0>ktkp->klass()->print() = (void)

because of this code:

   // If we have an interface-typed Phi or cast and we narrow to a class type,
   // the join should report back the class.  However, if we have a J/L/Object
   // class-typed Phi and an interface flows in, it's possible that the meet &
   // join report an interface back out.  This isn't possible but happens
   // because the type system doesn't interact well with interfaces.

   if (ftkp != NULL && ktkp != NULL &&
       ftkp->is_loaded() &&  ftkp->klass()->is_interface() &&
       ktkp->is_loaded() && !ktkp->klass()->is_interface()) {
     // Happens in a CTW of rt.jar, 320-341, no extra flags
     return ktkp->cast_to_ptr_type(ftkp->ptr());
   }

the result is

precise klass java/lang/Object: 0x0811c7e0:Constant:exact *

which leads to incorrect result from CmpP node:

  703    ConP    ===  0  [[ 704  432  704 ]]  #precise klass java/lang/Object: 0x0811c7e0:Constant:exact *  Klass:precise klass java/lang/Object: 0x0811c7e0:Constant:exact *
  704    CmpP    === _  703  703  [[ 705 ]]  !orig=[413] !jvms: AttributeSetUtilities::verifyAttributeValue @ bci:14 HashAttributeSet::add @ bci:15 HashAttributeSet::<init> @ bci:36 MyHashAttributeSet::<init> @ bci:3 InstanceCheck::t2 @ bci:10



More information about the hotspot-compiler-dev mailing list