2 Replies Latest reply on Aug 2, 2016 9:00 PM by bluegol

    Finding Superclasses and Interfaces: An Idea

    bluegol

      Hi,


      With CLASS ^ & INTERFACE ^, byteman needs to know all of the class's superclasses and the interfaces,

      including superinterfaces. But at the time byteman is in charge, i.e., at the time the class is being transformed,

      the superclasses and the interfaces may not be loaded. As far as I can tell, byteman then directly

      load superclasses' .class files using ClassLoader's getResourceAsStream method.


      Here's an idea of achieving this goal without getResourceAsStream.


      When ClassFileTransformer is called for the first time for a class, remember its direct superclass as well

      as directly implemented interfaces. Also at the same time, inject something into static initializer,

      to be explained later. According to the JVM spec, before a class is *created*, or to be precise,

      is derived from a class file representation (btw, this means after all transform calls, in my understanding),

      i) its direct superclass is resolved; ii) its direct superinterfaces are resolved. (§5.3.5)

      *Resolution* guarantees that the class/interface in question is *created*, hence

      having been through transform. (§5.4.3.1) *resolution* guarantees also that its direct superclass as well

      as its direct superinterfaces are resolved. In other words, before a class is created,

      any of its superclasses as well as any interface it or any of its superclasses implements is guaranteed to have been

      created. (A simple experiment shows a result in accordance with this speculation.)


      So it seems that all the info about ancestors and interfaces of a class is known before it is *linked*. But the chance

      for its transform is gone. Well, what if its static initializer calls redefine or retransform?


      I wonder if this actually works well in reality. Also I'm not sure whether this is any better than just

      calling getResourceAsStream. But calling getResourceAsStream during transform seems

      a bit unnatural to me.


      I'll run more experiments, and report the result back.


      Regards,

      Jahwan



        • 1. Re: Finding Superclasses and Interfaces: An Idea
          adinn

          Hi Jahwan,

           

          That's a very interesting idea. Off the top of my head I can't see any reason why delaying a potential the transform to <clinit> time is going to cause major problems. It's certainly worth investigating to see what happens.

           

          I would very much like to avoid using getResourceAsStream because there are certain class loader setups where this cheat will fail or be quite expensive. Also, I am concerned that Jigsaw may make such failures much more common.


          One caveat is that I don't just use this resource lookup trick when chasing superclasses in the Transformer. There are also occasions where the type checker needs to attempt to find a highest common superclass for two classes (when exceptions shadow other exceptions or when a local slot populated with two different subtypes in alternative paths needs to be retyped at a control flow merge point). So, even if this works to eliminate the resource lookup during super-chasing it may not remove the need for it in those other cases.


          regards,


          Andrew Dinn

          • 2. Re: Finding Superclasses and Interfaces: An Idea
            bluegol

            Hi Andrew,

             

            OK, I'll definitely run some experiments on this.

             

            One caveat is that I don't just use this resource lookup trick when chasing superclasses in the Transformer. There are also occasions where the type checker needs to attempt to find a highest common superclass for two classes (when exceptions shadow other exceptions or when a local slot populated with two different subtypes in alternative paths needs to be retyped at a control flow merge point). So, even if this works to eliminate the resource lookup during super-chasing it may not remove the need for it in those other cases.

             

            I need to think more about this. As far as I can tell, such usage in byteman is via ClassWriter's getCommonSuperClass method.

            It is required for ASM's stack map frame computation. And the reason for that is what you just explained: subtypes in one local slot.

            It all makes sense.

             

            Thanks for the "to-the-point" answer.

             

            Best,

            Jahwan