jgpc42 / insn

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

try finally #7

Closed cnuernber closed 3 years ago

cnuernber commented 3 years ago

How would you do a general try/finally pattern?

Looking at bytecode for a simple case yields:


chrisn@chrisn-lt-01:~/dev/cnuernber/dtype-next$ javap -c java/tech/v3/datatype/TryFinally.class
Compiled from "TryFinally.java"
public class tech.v3.datatype.TryFinally {
  public tech.v3.datatype.TryFinally();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static int testfn(int);
    Code:
       0: iconst_4
       1: istore_0
       2: new           #7                  // class java/lang/RuntimeException
       5: dup
       6: ldc           #9                  // String Exception
       8: invokespecial #11                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
      11: athrow
      12: astore_1
      13: iconst_5
      14: istore_0
      15: aload_1
      16: athrow
    Exception table:
       from    to  target type
           0    13    12   any
}

The exception table in this case as target type any which I guess I could use Throwable for.  The trycatch instruction is a bit confusing to me I have to admit.

Thanks for any help!
jgpc42 commented 3 years ago

From the docs:

(trycatch v start end handler etype)

Mark region between `start` and `end` labels as protected by label
`handler` against throwable `etype`.

Here's a test demonstrating :trycatch.

Please see the documentation, wiki, and/or the tests for usage information and examples. Thanks.

jgpc42 commented 3 years ago

Sorry, I misread the question. try/finally is accomplished by passing nil in place of the exception type. Unfortunately, I didn't account for this (I never had a need to use try/finally in my projects), but I just pushed a trivial fix to support this.

For the time being, you can use the latest code with something like this in a deps.edn

{:deps
 {jgpc42/insn
  {:git/url "https://github.com/jgpc42/insn" :sha "e8cee4a8c029da57dd576caa2762235eaf61b3d0"}}}

I should have a proper bugfix release by tomorrow or Saturday.

Here is a quick demonstration of using try/finally (with the new code):

(def class-data
  {:methods [{:flags [:public]
              :name "testfn"
              :emit [[:mark :TRY]
                     [:ldc 4]
                     [:istore 0]
                     [:new RuntimeException]
                     [:dup]
                     [:ldc "Exception"]
                     [:invokespecial RuntimeException :init [String :void]]
                     [:athrow]
                     [:mark :ERROR]
                     [:astore 1]
                     [:mark :END]
                     [:ldc 5]
                     [:istore 0]
                     [:aload 1]
                     [:athrow]
                     [:trycatch :TRY :END :ERROR nil]]}]})

(require '[insn.core :as insn])

(insn/write (insn/visit class-data) "/tmp/test")
javap -c /tmp/test/user/insn_type4229.class
public final class user.insn_type4229 {
  public void testfn();
    Code:
       0: iconst_4
       1: istore_0
       2: new           #8                  // class java/lang/RuntimeException
       5: dup
       6: ldc           #10                 // String Exception
       8: invokespecial #14                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
      11: athrow
      12: astore_1
      13: iconst_5
      14: istore_0
      15: aload_1
      16: athrow
    Exception table:
       from    to  target type
           0    13    12   any

  public user.insn_type4229();
    Code:
       0: aload_0
       1: invokespecial #18                 // Method java/lang/Object."<init>":()V
       4: return
}
jgpc42 commented 3 years ago

I just pushed 0.5.1. Along with the trycatch fix, I added some support for using older ASM versions (I notice you're using 7.1 in dtype-next). Let me know if you have any other issues. Thanks.

cnuernber commented 3 years ago

This is great, thanks!