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