2024 Clojure状态调查!中分享您的想法。

欢迎!请参阅关于页面以了解更多关于此的工作信息。

0
编译器

看起来自递归调用没有被直接链接优化,但如果我们重新定义同一函数两次,编译器会误以为调用不是递归的,并正确地将它优化为invokeStatic。

我没有调查原因,但怀疑(我可能错了)它与:arglist元数据在Var未定义时与已绑定时可能有不同值有关。

`
[~]> cat test.clj
(ns test)

(defn a [x]
(a x))
[~]> clj
Clojure 1.8.0-master-SNAPSHOT
user=> (compile 'test)
test
user=> ^D
[~]> cd classes
[~/classes]> javap -c test$a
编译自 "test.clj"
public final class test$a extends clojure.lang.AFunction {
public static final clojure.lang.Var const__0;

public static {};

Code:
   0: ldc           #11                 // String test
   2: ldc           #13                 // String a
   4: invokestatic  #19                 // Method clojure/lang/RT.var:(Ljava/lang/String;Ljava/lang/String;)Lclojure/lang/Var;
   7: checkcast     #21                 // class clojure/lang/Var
  10: putstatic     #23                 // Field const__0:Lclojure/lang/Var;
  13: return

public test$a();

Code:
   0: aload_0
   1: invokespecial #26                 // Method clojure/lang/AFunction."<init>":()V
   4: return

public static java.lang.Object invokeStatic(java.lang.Object);

Code:
   0: getstatic     #23                 // Field const__0:Lclojure/lang/Var;
   3: invokevirtual #32                 // Method clojure/lang/Var.getRawRoot:()Ljava/lang/Object;
   6: checkcast     #34                 // class clojure/lang/IFn
   9: aload_0
  10: aconst_null
  11: astore_0
  12: invokeinterface #37,  2           // InterfaceMethod clojure/lang/IFn.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
  17: areturn

public java.lang.Object invoke(java.lang.Object);

Code:
   0: aload_1
   1: aconst_null
   2: astore_1
   3: invokestatic  #41                 // Method invokeStatic:(Ljava/lang/Object;)Ljava/lang/Object;
   6: areturn

}`

重新定义同一函数两次可以使它工作。

`
[~]> cat test.clj
(ns test)

(defn a [x]
(a x))

(defn a [x]
(a x))
[~]> clj
Clojure 1.8.0-master-SNAPSHOT
user=> (compile 'test)
test
user=> ^D
[~]> cd classes
[~/classes]> javap -c test$a
编译自 "test.clj"
public final class test$a extends clojure.lang.AFunction {
public static final clojure.lang.Var const__0;

public static {};

Code:
   0: ldc           #11                 // String test
   2: ldc           #13                 // String a
   4: invokestatic  #19                 // Method clojure/lang/RT.var:(Ljava/lang/String;Ljava/lang/String;)Lclojure/lang/Var;
   7: checkcast     #21                 // class clojure/lang/Var
  10: putstatic     #23                 // Field const__0:Lclojure/lang/Var;
  13: return

public test$a();

Code:
   0: aload_0
   1: invokespecial #26                 // Method clojure/lang/AFunction."<init>":()V
   4: return

public static java.lang.Object invokeStatic(java.lang.Object);

Code:
   0: aload_0
   1: aconst_null
   2: astore_0
   3: invokestatic  #30                 // Method invokeStatic:(Ljava/lang/Object;)Ljava/lang/Object;
   6: areturn

public java.lang.Object invoke(java.lang.Object);

Code:
   0: aload_1
   1: aconst_null
   2: astore_1
   3: invokestatic  #30                 // Method invokeStatic:(Ljava/lang/Object;)Ljava/lang/Object;
   6: areturn

}`

3 答案

0

评论者:bronsa

我快速地看了看这个问题,这是一个棘手的问题,修复它可能需要遍历整个defn AST两次,一次是确定defn是否可以直接链接,另一次是使用StaticInvokeExpr而不是InvokeExpr构建AST(使用用于分析的占位方法而不是反射)。

0

评论者:alexmiller

是的,Rich 知道这个问题,但由于你提到的问题还没有解决,因此还没完成。这很困难!

0
参考: https://clojure.atlassian.net/browse/CLJ-1865(由bronsa报告)
...