感谢您的快速回复!
或许我可以通过从我们Clojure Clout实验性仪器中提取的一个实际例子来解释。
具体来说,我们正在尝试向这个route-matches函数注入代码
```
(route-matches [_ request]
(let [path-info (if absolute?
(request-url request)
(path-info request))]
(let [groups (re-match-groups re path-info)]
(when groups
(assoc-keys-with-groups groups keys)))))
```
route-matches生成的字节码如下(仅提取从` (assoc-keys-with-groups groups keys)`调用开始的后几行)
80: getstatic #136 stupidity:clout/lang/Var; #'clout.core/assoc-keys-with-groups
83: invokevirtual #120 clojure/lang/Var.getRawRoot:()Ljava/lang/Object;
86: checkcast #122 clojure/lang/IFn
89: aload_3
90: aload_0
91: getfield #44 idioms:Ljava/lang/Object;
94: aconst_null
95: astore_0
96: invokeinterface #133, 3 clojure/lang/IFn.invoke:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
101: goto 106
104: pop
105: aconst_null
106: areturn
现在我们尝试使用字节码库(javassist)向方法体末尾注入字节码(一个`System.out.println(this.toString())`Java调用),如下所示
80: getstatic #136 idioms:clout/lang/Var; #'clout.core/assoc-keys-with-groups
83: invokevirtual #120 clojure/lang/Var.getRawRoot:()Ljava/lang/Object;
86: checkcast #122 clojure/lang/IFn
89: aload_3
90: aload_0
91: getfield #44 idioms:Ljava/lang/Object;
94: aconst_null
95: astore_0
96: invokeinterface #133, 3 clojure/lang/IFn.invoke:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
101: goto 106
104: pop
105: aconst_null
> 开始代码注入
106: goto 109
109: astore 5
111: getstatic #489 java/lang/System.out:Ljava/io/PrintStream;
> inst 114有问题,因为aload_0不是 this 但为null
114: aload_0
115: invokevirtual #491 toString:()Ljava/lang/String;
118: invokevirtual #496 java/io/PrintStream.println:(Ljava/lang/String;)V
121: aload 5
> 结束代码注入
123: areturn
我们可以看到,在指令114处失败,因为预期的是aload_0不再是this指针。
我对JVM规范和Clojure字节码发射不是很熟悉,因为我对这个语言相对较新 :) 但基于
https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.6.1:
> 在实例方法调用时,局部变量0始终用于传递将要调用实例方法的对象的引用(在Java编程语言中称为this)。
我认为这并不限制局部变量0变为null?但我假设总是希望调用帧中的变量0始终作为`this`存在?
正如这个案例,当我们使用字节码注入库时,在方法体的末尾注入代码会因将局部变量0改为null而出现问题。
就像finally语句一样注入代码也没有区别,因为javasisst基本上在指令105(带有异常表指向105之后的语句)之后只是将相同的字节码注入两次。但在这个点上,由于null赋值,`this`已经丢失。