6 Replies Latest reply on Dec 4, 2012 8:40 AM by belaban

    METHOD and generics

    belaban

      I need to intercept a generic method add():

       

      public class BoundedList<T> {

          public boolean add(T element) {...}

      }

       

       

      The rule I use is:

      RULE dummy

      CLASS BoundedList

      METHOD add

      ...

      ENDRULE

       

      This works, but I'd like to narrow the type of the argument of add() to Message, e.g.

      METHOD add(org.jgroups.Message).

       

      This doesn't work, and the rule is not fired.

       

      I read elsewhere that generics are not supported in Byteman, so if this is the answer I'll be ok.

       

      However, what I don't understand is that in INVOKE, apparently generics *are* supported, ie. the rule below works:

       

      RULE MessageReception

      CLASS NAKACK2

      METHOD up

      AFTER INVOKE BoundedList.add(Message) ALL

      BIND len=$msg.getLength();

           is_server=$0.is_server;

      IF len > 0

         DO System.out.println("--> " + $0.local_addr + ": received message " + $msg.printHeaders() + ", added to queue, is_server=" + is_server);

         rendezvous("rv");

      ENDRULE

       

      INVOKE BoundedList.add(Message) allows me to treat the argument to add() as a Message, therefore I won't get any ClasCastExceptions when determining the length of the message in the BIND clause (len).

       

      I'd like to do the same with METHOD. Is there a way to do this ?

       

      If not, would it make sense to allow for the  'instanceof' keyword in an expression ?

      Cheers,

      Bela

        • 1. Re: METHOD and generics
          belaban

          Correction: the INVOKE method triggers an exception:

          unsatisfiable local variable binding $msg checking method up(Lorg/jgroups/Event;)Ljava/lang/Object;

          • 2. Re: METHOD and generics
            belaban

            Hmm, what puzzles me is that the following rule:

             

            RULE dummy2

            CLASS NAKACK2

            METHOD up(Event)

            BIND msg:Message=$1.getArg();

                 clazz=msg.getClass();

            #     len=msg.getLength();

            AT READ is_server ALL

            IF TRUE

               DO System.out.println("******** $1=" + msg + ", clazz=" + clazz);

            ENDRULE

             

            prints out clazz=org.jgroups.Message, so it *has* the correct type of msg. After all, I thought that BIND msg:*Message*=$1.getArg(), would force Byteman to recognize msg as of being of type Message, *not* Object !

             

            However, if I uncomment the binding of len, then it seems that Byteman does still see msg as Object:

             

            Rule.ensureTypeCheckedCompiled : error type checking rule dummy2

            org.jboss.byteman.rule.exception.TypeException: MethodExpression.typeCheck : invalid method getLength for target class java.lang.Object

             

            Thoughts ?

            • 3. Re: METHOD and generics
              adinn

              Hi Bela,

               

              Apologies for not attending to teh details fo this earlier -- been very busy getting the ARM64 OpenJDK interpreter port tpo pass the TCK (almost there :-)

               

              Bela Ban wrote:

               

              Hmm, what puzzles me is that the following rule:

               

              RULE dummy2

              CLASS NAKACK2

              METHOD up(Event)

              BIND msg:Message=$1.getArg();

                   clazz=msg.getClass();

              #     len=msg.getLength();

              AT READ is_server ALL

              IF TRUE

                 DO System.out.println("******** $1=" + msg + ", clazz=" + clazz);

              ENDRULE

               

              prints out clazz=org.jgroups.Message, so it *has* the correct type of msg. After all, I thought that BIND msg:*Message*=$1.getArg(), would force Byteman to recognize msg as of being of type Message, *not* Object !

               

              However, if I uncomment the binding of len, then it seems that Byteman does still see msg as Object:

               

              Rule.ensureTypeCheckedCompiled : error type checking rule dummy2

              org.jboss.byteman.rule.exception.TypeException: MethodExpression.typeCheck : invalid method getLength for target class java.lang.Object

               

              Thoughts ?

               

              I'm quite surprised that this works as you describe it above. The type checker should recognise that $1.getArg() has type Object and flag the initialisation of msg:Message as invalid because it involves a cast down from Object to Msg.

               

              I would very much like to be able to support casting down and have been thinking of how to add it for quite some time now but I didn't expect it already to work :-)

               

              Anyway, the main problem you are facing is that Byteman cannot deal with generics. Of course, it only has limited information about the type bindings employed in the original source since most such information is erased from the bytecode (not all though). So, you can sometimes know what type of datum you have at the point of use. So, in fact, you can probably identify from the bytecode that the argument passed AT INVOKE BoundedMessage.add() is indeed a Message. The real problem is that inside the generic code itself you don't know what parameter types you are delaing with.

               

              Your initial example highlights the problem. You really want to inject the rule into BoundedList<Message>.add(). But in the JVM there is only one generic implementation method BoundedList.add(). How do you know when to trigger the rule? If the list contains any elements you could type test them and determine whether it is de facto a list of Message instances. But actually the type might have been constructed and passed around as  a List<Streamable>. Does this matter? Well, using the dynamic type will allow you to avoid type errors but it may also lead to unintended triggerings. For example, any empty list will pass the dynamic test which might lead to your rule firing in many more circumstances than those you originally envisaged. I don't really see any way to deal with this issue which is why I have not yet implemented any support for using what little generic type info there is in the bytecode in your Byteman rules. I'm stil open to ideas but I don't really know what would be useful.

              • 4. Re: METHOD and generics
                belaban

                OK, I understand that type erasure makes your life harder :-)

                 

                But, what I don't understand is why

                 

                BIND msg:Message=$1.getArg();

                 

                doesn't *force* byteman to narrow Object to a Message. I thought that's the point of being able to specify the type of a variable, e.g. msg:TYPE=xxx.

                 

                I mean I know what I'm doing here and don't mind a CCE if it turns out that I specified the wrong type for msg.

                Cheers,

                • 5. Re: METHOD and generics
                  adinn

                  Hi Bela,

                  Bela Ban wrote:

                   

                  OK, I understand that type erasure makes your life harder :-)

                   

                  But, what I don't understand is why

                   

                  BIND msg:Message=$1.getArg();

                   

                  doesn't *force* byteman to narrow Object to a Message. I thought that's the point of being able to specify the type of a variable, e.g. msg:TYPE=xxx.

                   

                  I mean I know what I'm doing here and don't mind a CCE if it turns out that I specified the wrong type for msg.

                  Cheers,

                   

                  Well, no . . . the point of the type declaration was to ensure you could state what type you expected rather than just get the type you got. However, I take your point that a downcast in bindings should be quite workable and would be very useful. Indeed, I am looking at implementing this right now. I think this will make it into the release I am currently preparing this week.

                   

                  I think I will need to provide a backwards compatiility setting to disallow downcasts though e.g. settign a System variable like org.jboss.byteman.disallow.downcast. In part this is to allow you to ensure that downcasts are notified if you don't intend to use them. However, it also serves to retain backwards compatibility in one unlikely but possible special case. Allowing downcasting disallows use of the declared type to infer the type of the expression on the right of the equals sign. That may mean that some rules which currenltly type check because the expression type is known in advance may fail to check wit this new feature.

                  • 6. Re: METHOD and generics
                    belaban

                    Re your point as to express the expected type: I do think this should potentially involve a downcast (if necessary). Would be very helpful for handling generic collections, which AIUI contain only Objects from a byteman perspective.

                     

                    If you have to add a system property, then I'd vote for opting out: ie. if no system property is defined, downcasts are allowed ! :-)

                    Thanks for the very quick turnaround !

                    Cheers,