insn icon indicating copy to clipboard operation
insn copied to clipboard

Static invocation inside if branch, possible issue or just doing wrong?

Open edipofederle opened this issue 1 year ago • 4 comments

Hi,

First of all, thanks for your work on this library!

I'm facing some issues when trying to invoke static inside a if branch, here be example:

(def test-data
  {:name "my.pkg.Test.Test",
   :flags [:public],
   :fields [],
   :methods
   [{:flags #{:public},
     :name "invoke",
     :desc [java.lang.Long :void],
     :emit
     [[:aload 1]
      [:invokevirtual java.lang.Long "longValue" [:long]]
      [:ldc2 100]
      [:lcmp]
      [:ifle "MARK1"]
      [:new "my.pkg.Test.Println"]
      [:dup]
      [:invokespecial "my.pkg.Test.Println" :init [:void]]
      [:astore 2]
      [:aload 2]
      [:aload 1]
      [:invokevirtual "my.pkg.Test.Println" "invoke" [java.lang.Object Object]]
      [:mark "MARK1"]
      [:return]]}]})
;;; Trying it: 

  (-> (insn/define test-data) .newInstance (.invoke 1000))

This is the Exception:

1. Unhandled java.lang.ArrayIndexOutOfBoundsException
   Index 0 out of bounds for length 0

                Frame.java: 1268  org.objectweb.asm.Frame/merge
                Frame.java: 1244  org.objectweb.asm.Frame/merge
         MethodWriter.java: 1611  org.objectweb.asm.MethodWriter/computeAllFrames
         MethodWriter.java: 1547  org.objectweb.asm.MethodWriter/visitMaxs
                  core.clj:  246  insn.core/visit-method
                  core.clj:  215  insn.core/visit-method
                  core.clj:  196  insn.core/visit/fn
                  core.clj:  191  insn.core/visit
                  core.clj:   42  insn.core/visit
                  core.clj:  266  insn.core/ensure-visited
                  core.clj:  265  insn.core/ensure-visited
                  core.clj:  279  insn.core/define
                  core.clj:  274  insn.core/define
                  core.clj:  277  insn.core/define
                  core.clj:  274  insn.core/define

I have basically this code in Java and the byte code looks like this, and works as expected:

   
  0: aload_1
       1: invokevirtual #7                  // Method java/lang/Long.longValue:()J
       4: ldc2_w        #13                 // long 100l
       7: lcmp
       8: ifle          24
      11: new           #15                 // class Println
      14: dup
      15: invokespecial #17                 // Method Println."<init>":()V
      18: astore_2
      19: aload_2
      20: aload_1
      21: invokevirtual #18                 // Method Println.invoke:(Ljava/lang/Object;)V
      24: return

I'm not not sure if I'm doing some thing wrong on the the Clojure code, or if maybe there is some bug in the library. Maybe someone can provide some direction here?

Thanks!

edipofederle avatar Feb 20 '24 19:02 edipofederle

First of all, I think the exception is likely a bug in ASM, but I'm not sure.

Anyway, on this line:

[:invokevirtual "my.pkg.Test.Println" "invoke" [java.lang.Object Object]]

Did you mean that to be returning :void?

21: invokevirtual #18                 // Method Println.invoke:(Ljava/lang/Object;)V

E.g.,

user=> (require '[insn.util :as util])
nil
user=> (util/method-desc [java.lang.Object Object])
"(Ljava/lang/Object;)Ljava/lang/Object;"
user=> (util/method-desc [java.lang.Object :void])
"(Ljava/lang/Object;)V"

jgpc42 avatar Feb 22 '24 16:02 jgpc42

First of all, I think the exception is likely a bug in ASM, but I'm not sure.

Anyway, on this line:

[:invokevirtual "my.pkg.Test.Println" "invoke" [java.lang.Object Object]]

Did you mean that to be returning :void?

Yes, correct.

edipofederle avatar Feb 26 '24 11:02 edipofederle

So, does it work now, or are you still getting the error?

jgpc42 avatar Feb 26 '24 17:02 jgpc42

Maybe you misunderstood me. It is currently returning Object. If you intended it to return :void, you need to change it to the following:

[:invokevirtual "my.pkg.Test.Println" "invoke" [java.lang.Object :void]]  ;; <-- changed

jgpc42 avatar Feb 26 '24 21:02 jgpc42