v0.1.5
A correctness and gate-integrity release. No new artifact support — this one fixes a bug v0.1.4 shipped and closes the hole that let it ship.
Fixed: string literals folded into arithmetic
A pool string literal was carried as a pending value and substituted into later expressions, so an address computation rendered as
rbx = mem((" fib(20)=") + rdx*8 + 0x17); // String + int → argument_type_not_assignableThe register holds the address of the pool slot; the literal is what lives at that address. Substituting one for the other is a category error in every context, not just arithmetic — Dart merely happened to reject this one. Literals are now left alone when the operand text contains arithmetic; they still appear on the line that loads them (which is where they belong), and non-arithmetic uses still substitute.
This was the corpus's only dart analyze error, and it was a regression introduced in v0.1.4 by the Function layout fix: the same sample scored 0 errors before that change. The full corpus is back to 0 errors across 26 artifacts / 291 files / 24,253 functions, with file and function counts unchanged — nothing was suppressed to get there.
Fixed: the gate that should have caught it
full_scorecard ran every artifact in the corpus and then only printed the total. So the summary line read dart analyze 错误 1 while the suite stayed green — dart_valid's asserted corpus is three samples, and this test was #[ignore]d and informational. "The output compiles" is the claim this project leads with, so the test that actually measures it now asserts it:
- total
dart analyzeerrors must be 0 - at least 20 samples must be present, so a missing or moved artifacts directory cannot score a vacuous zero
- every sample that produced output must recover ≥ 400 functions. A drifted parse collapses to
libraries=1 / classes=1while still analysing cleanly, so "0 errors" alone does not prove health.hello_2.12.4at 1,212 andhello_2.18.1at 27 are an order of magnitude apart, so the floor cannot misfire. - a sample that produces no
.dartat all must be listed inSCORECARD_NO_ADDRESS_LAYER— an explicit registry, not afiles == 0escape, because the latter would let a future collapse-to-nothing pass silently. It holdshello_2.7.2andhello_2.10.4, which have no instruction table by design.
Negative-tested: raising the floor to 2,000 fails on hello_2.12.4 with the reason printed.
Docs re-measured, not carried over
- Decompiler scorecard synced to a fresh full run.
hello_2.19.6goes from 2 files / 229 functions to 15 / 1,240 now that its layout is right.hello_2.18.1stays in the table at 27 functions with a pointer to the collapse registry — hiding it is what let it sit unnoticed. - Comparison vs aotopsy: Lark and Weibo move from "open" to their real numbers, so all five Android builds now match aotopsy's instructions-table entry counts exactly (57,960 / 79,327 / 30,782 / 19,752 / 22,623), and their decompile results are listed. The naming-agreement figure is corrected 90.6% → 89.4% with the reason stated: the ground-truth corpus grew from three samples to six, and
hello_2.19.6alone went from 558 to 1,081 agreeing names. The 2026-09-26 "before the fix" table is kept as history. - Profile spec gains a section on fields whose presence depends on the version (
TypeParameter,Function,SubtypeTestCache,FfiTrampolineData,Type— with the boundary version for each), plus the twodatastream.hencoding rules that are easy to invert and cost hours:Write<T>is a varint unlesssizeof(T) == 1, andWriteUnsignedmarks the terminator, not the continuation bytes (the inverse of ULEB128). - README tagline and Features now mention the decompiler and mobile support; the decompiler had a section but no feature bullet. Repo description and topics updated to match (
android,decompiler,compressed-pointers), andCargo.toml's description likewise — that one reaches crates.io with this release.
Adjudicated: Dart 2.18.1
Both candidate Function layouts were measured against .symtab, and neither is healthy: 1 trailing varint gives libraries=1 / classes=1 / 63 functions, 2 gives libraries=1 / classes=2 / 629 functions, against ~15 / ~320 / ~1,300 for a working sample. The source is unambiguous — 2.18.1's WriteFill diffs empty against 2.19.6, whose 1-varint layout is confirmed by both .symtab and aotopsy's entry count — so the source-correct layout stays and 2.18.1's second error remains unlocated. Keeping the 2-varint variant would freeze a compensating mistake into the profile and misdirect whoever finds the real one. The measurement is recorded in the registry so nobody has to redo it.
2.18.1 should be treated as unsupported. 2.15 / 2.16 / 2.17 and 2.19+ are fine.
Verified
47 tests under DAE_REQUIRE_GATES=1 · full scorecard 26 artifacts / 0 errors · regress_all 25/25 byte-identical · check_profiles 47/47 · clippy 0 · all five real-device Android artifacts still at their exact entry counts with 0 warnings.
Install
cargo install dae-rs # crate name is dae-rs; the binary is `dae`
brew install ejfkdev/tap/dae
scoop bucket add ejfkdev https://github.com/ejfkdev/scoop-bucket; scoop install daeOr grab a binary for Linux / macOS / Windows (x64 and arm64) below.