jgpc42 / insn

Functional JVM bytecode generation for Clojure.
Eclipse Public License 1.0
198 stars 5 forks source link

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

Closed edipofederle closed 5 months ago

edipofederle commented 6 months ago

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!

jgpc42 commented 6 months ago

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"
edipofederle commented 6 months ago

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.

jgpc42 commented 6 months ago

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

jgpc42 commented 6 months ago

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