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

欢迎!请查看关于页面以获取更多关于此工作方式的信息。

0
编译器

编译引用未加载(或未初始化)类的函数会触发其初始化静态代码。当初始化静态代码加载Clojure代码时,某些常量(我想是源代码)会泄露到正在编译的函数的常量池中。

这导致在某些环境(如Rational)中CCW无法工作,因为生成的函数的静态初始化超过了64K。

重现步骤

加载leak.main命名空间,并运行注释中的代码:第一个函数尽管与第二个函数相同,但有15个额外的字段。

`
(ns leak.main)

(defn first-to-load []
leak.Klass/foo)

(defn second-to-load []
leak.Klass/foo)

(comment
=> (map (comp count #(.getFields %) class) [first-to-load second-to-load])
(16 1)
)
`

`
package leak;

import clojure.lang.IFn;
import clojure.lang.RT;
import clojure.lang.Symbol;

public class Klass {
static {

RT.var("clojure.core", "require").invoke(Symbol.intern("leak.leaky"));

}
public static IFn foo = RT.var("leak.leaky", "foo");
}
`

`
(ns leak.leaky)

(defn foo
"Some doc"
[]
"hello")

(def unrelated 42)
`

https://gist.github.com/cgrand/5dcb6fe5b269aecc6a5b#file-main-clj-L10

修复: clj-1620-v5.patch

33 答案

0

评论者:bronsa

实际上,Ghadi是对的,用(:foo {})替换thunk-fail.core的全部主体就足够了。

这似乎与AOT(重)编译顶级关键字查找位置有关,我的猜测是这个补丁阻止了正确生成__init静态初始化器。

0

评论者:bronsa

我对lein compile正在做什么完全没有任何头绪,但我解决了问题。
更新的补丁仅在已经绑定的情况下绑定(在eval)适当的变量。

0

评论者:alexmiller

现在使用绑定地图的临时项是否有意义?

0

评论者:bronsa

听起来有道理,我已更新补丁以使用临时地图

0

评论者:michaelblume

我们可以添加一个测试,测试在v2补丁存在的情况下会失败吗?最好与CLJ-1544补丁独立?我可以尝试自己写一个,但我不太熟悉Clojure编译器的内部机制。

0

评论者:bronsa

我必须考虑如何重现该错误,这是一个不容易重现的场景。
它涉及到从已评估的环境中编译一个命名空间。

0

评论者:laurentpetit

还有机会使该问题出现在1.7版本中吗?

0

评论者:alexmiller

我并没有计划这样做 - 对您有什么影响吗?

0

评论者:laurentpetit

影响是我需要为CCW使用Clojure的补丁版本。
虽然目前跟踪clojure的主分支并定期rebase或重新应用补丁并不难,但这仍然是一种浪费时间的方法。

0

评论者:alexmiller

在我们达到RC之前,我会向Rich确认是否可以在1.7版本前进行筛选。

0

评论者:alexmiller

与v4补丁相同,但具有更多的diff上下文。

0

评论者:laurentpetit

在我看来,补丁字段中提到的文件不是正确的文件。

0

评论者:alexmiller

是哪一个?

0

评论者:laurentpetit

我认为您之前的评论与clj-1620-v5.patch有关,但在描述的末尾有如下一行

补丁:0001-CLJ-1620-avoid-constants-leak-in-static-initalizer-v4.patch

0

评论者:alexmiller

这些补丁在引入的更改方面等效;它们只是diff上下文有所不同。

...