Repository navigation
v0.1.2
更新内容
语料规模语法校验: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 26PackageBuilder/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_classinstead 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 illegalOuter.1references (~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'sOuter$1Namelocal-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-lesstrywith no catch/finally becomes a block. - Java 21+ pattern switches restored, including
enumSwitchconstant labels andEnumDescconditional-constant decoding (fixes JDK 26PackageBuilder/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