Skip to content

v0.1.2

Choose a tag to compare

@github-actions github-actions released this 15 Sep 07:19
· 18 commits to main since this release
v0.1.2
f3c45cb

更新内容

语料规模语法校验:1,671 → 1 个语法错误文件。 用 48,251 个第三方 .class(CFR 各 javac 版本回归套件、fernflower/ASM 测试数据、完整 JDK 26 镜像含源码、java-class-rs 边角用例)做「反编译 → javac 回编译」全量校验,逐类修复解析级错误:

  • 目录输入的类池索引:原先按「输入相对路径」而非 class 自身内部名索引,凡目录树不是以包根为根(如 cfr/java_8/…、jdk26/jdk26/class/<module>/…)就导致按内部名查找全部落空——匿名类无法内联、输出非法的 Outer.1。现按 this_class 索引(不可解析的文件保留路径键),重复名的解析顺序也确定化了。这一类占原错误的约 1,300 个文件。
  • 被丢弃的值合法化:a.a;、Outer.this;、(Object[]) foo.clone(); 都不是合法语句表达式——强转剥到有副作用的核心,可能抛 NPE 的读取物化进合成局部变量(保留原语义)。
  • $ 名字渲染:字面 $ 名(DolTest2$$dollah$$)与 javac 局部类编码(Outer$1Name)在点号化后无法解析时一律保留 $。
  • 数组下标加括号:(new int[1][0])[0] = …(裸写会被重解析成三维数组创建)。
  • try-with-resources 残留形态:资源被改写为赋值时先输出赋值再普通 try;无资源且无 catch/finally 时退化为语句块(裸 try { 无法编译)。
  • Java 21+ 模式 switch 还原:enumSwitch 常量标签(含 EnumDesc 条件常量解码)、typeSwitch 整数标签——修复 JDK 26 PackageBuilder/DocLint 一类的方法。
  • 匿名类作为构造参数:内联后继续下钻参数,new Outer(new Inner(null) {…}) {…} 正确还原;常量监视器(synchronized (null))物化为局部变量。

唯一剩余文件是 ASM 的 Artificial$()$Structures——类名含 (),任何 Java 源码都无法拼写(CFR 输出同样非法),属不可还原输入。

验证:features 语义套件 56/56;rt.jar 全量 12,609 文件零 panic;语料保真度 A/B 与改动前完全一致(fail_files 集合、6/6 族可重编译)。

性能基准更新:加入 JetBrains fernflower 对照;第二个负载换成完整 JDK 26 模块镜像(JDK 9+ 已无 rt.jar,boot classpath 变为 lib/modules)。18 核 M5 Pro:rt.jar 6.8s / 599MB(fernflower 196.8s,Vineflower 26.2s,CFR 59.4s,Procyon 113.1s);JDK 26 镜像 11.9s / 801MB(CFR 175.8s,fernflower 513.1s,Procyon 789.4s;Vineflower 跑不完该负载——8g/16g 堆耗尽,32g 封顶 40 分钟仍 0 输出)。

新增 scripts/jclassd_syntax_check.py(语料语法校验脚本)与 “Built with ZCode” 徽章。

What's changed (English)

Corpus-scale syntax sweep: 1,671 → 1 files with parse errors, measured by decompiling a 48,251-class third-party corpus and feeding every emitted source back through javac:

  • Pool indexing for directory inputs now keys classes by their own this_class instead of the input-relative path — any tree that is not a package tree rooted at the input dir made every internal-name lookup miss, killing family/anonymous enumeration and emitting illegal Outer.1 references (~1,300 files).
  • Discarded-value legalization: a.a;, Outer.this;, (Object[]) foo.clone(); are not statement expressions — casts strip to their side-effecting core, trapping reads materialize into a synthetic local (NPE semantics preserved).
  • $-name rendering keeps $ when dotting cannot parse (literal-$ names, javac's Outer$1Name local-class encoding).
  • Array indexing parenthesizes its base: (new int[1][0])[0] = ….
  • Vestigial try-with-resources: hoisted resources print before a plain try; a resource-less try with no catch/finally becomes a block.
  • Java 21+ pattern switches restored, including enumSwitch constant labels and EnumDesc conditional-constant decoding (fixes JDK 26 PackageBuilder/DocLint-style methods).
  • Anonymous classes as constructor arguments are now inlined; constant monitors (synchronized (null)) materialize into a local.

The one remaining file is ASM's Artificial$()$Structures — a class name containing () that no Java source can spell (CFR emits the identical invalid form).

Verification: features battery 56/56; rt.jar smoke 12,609 files, no panics; corpus fidelity A/B byte-identical to the pre-change baseline. Benchmarks updated with JetBrains fernflower and a second workload: the full JDK 26 module image (JDK 9+ has no rt.jar) — jcdc 11.9 s / 801 MB vs CFR 175.8 s, fernflower 513.1 s, Procyon 789.4 s; Vineflower cannot finish it.

Full Changelog: v0.1.1...v0.1.2