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

欢迎!请参阅关于页面以了解更多该功能的信息。

0投票
编译器

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

这阻止了CCW在某些环境(Rational)中工作,因为生成的函数的静态初始化超过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是正确的,替换thunk-fail.core的整个主体为(:foo {})就足够了。

看起来问题出在AOT( 재)编译顶级关键字查找站点,我猜这个补丁阻止了正确生成__init静态初始化器。

0投票

评论者:bronsa

我仍然对lein compile在做什么完全没有头绪,但我解决了这个问题。
更新补丁绑定(在eval中)适当的变量仅在它们已经绑定时。

0投票

评论者:alexmiller

现在在绑定映射中使用transients是否值得?

0投票

评论者:bronsa

有道理,更新补丁使用临时的映射

0投票

评论者:michaelblume

我们可以添加一个测试,使之在v2补丁存在的情况下失败吗?最好是与CLJ-1544补丁无关的测试?我可以尝试自己编写一个,但是我并不熟悉Clojure编译器的内部架构。

0投票

评论者:bronsa

我必须考虑一种重现该错误的方法,这是一个不容易重现的场景。
这涉及到从一个评估的上下文中编译一个命名空间。

0投票

评论者:laurentpetit

还有机会让这个问题进入1.7版本吗?

0投票

评论者:alexmiller

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

0投票

评论者:laurentpetit

影响是我需要为CCW使用修复过的Clojure版本。
尽管目前跟踪 clojure 的主分支并进行常规的变基或重新应用补丁还不是那么困难,但这仍然是一种浪费时间的行为。

0投票
by

评论者:alexmiller

在达到预发布 (RC) 之前,我将与 Rich 商量是否可以在 1.7 中进行筛选。

0投票
by

评论者:alexmiller

类似于 v4 补丁,只是有更多的 diff 上下文。

0投票
by

评论者:laurentpetit

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

0投票
by

评论者:alexmiller

哪一个是呢?

0投票
by

评论者:laurentpetit

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

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

0投票
by

评论者:alexmiller

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

...