v0.68.0
v0.68.0
Lockstep release of @loopdive/js2 and the js2wasm proxy: 0.67.0 → 0.68.0.
A conformance release, focused on the standalone (pure-Wasm, no JS host) lane's
own-property and descriptor model. All numbers below are measured against the
standalone test262 lane with denominators, and every fix carries a kill-switch
receipt — a fix is credited only when the same corpus is measured with the
change removed.
Conformance
Two independent lanes, never summed — they measure different targets:
| Lane | v0.67.0 | v0.68.0 | Change |
|---|---|---|---|
JS-host (gc target, host imports allowed) |
29,856 / 43,099 (69.3 %) | 30,982 / 43,505 (71.2 %) | +1,126 passes, +1.9 pp |
Standalone (--no-host-imports, pure Wasm) |
not published | 27,339 / 43,505 (62.8 %) | — |
Two caveats on those numbers, because they change what the delta means:
- The corpus grew between releases (43,099 → 43,505 tests, +406). The
+1,126 host passes are therefore against a larger denominator, not a fixed
one — the percentage-point change is the sounder of the two figures. - No standalone delta is given because there is nothing honest to compare
against. The committed standalone summary
(benchmarks/results/test262-standalone-current.json) did not exist at
v0.67.0, so a change figure would have to be sourced from a different
artifact measured under different conditions. From v0.69.0 onward both lanes
will have a like-for-like predecessor.
Most of this release's work targets the standalone lane; the host lane
moves largely as a side effect.
Features
typeofon reified builtin constructors (#4120). A builtin captured into
a value (const C = Array) reported"object", because the standalone
carrier is a plain$Objectsingleton while thetypeofnatives classify by
closure-wrapper shape. Now carried on two internal-slot bits, so callable and
constructible are distinguished (isNaNis callable but not constructible)
andMath/JSON/Reflectcorrectly stay"object".
+16 files, 0 regressions across a 66-file control set.Object.prototype.toStringin standalone (#4119 arm 1). A runtime
§20.1.3.6 classifier replaces a blanket refusal. The 76 target rows go
0/76 → 75/76; the refusal bucket goes 76 → 0, with 0 regressions across an
82-row sweep. Receivers the classifier cannot yet tag correctly —$Proxy
(which subtypes$Object, so a revoked proxy must still throw), primitive
wrapper objects, and a few exotics — keep the loud refusal rather than
falling through to a default[object Object].- Own-property visibility over the unified store (#4010 S3).
hasOwnProperty,
in,getOwnPropertyDescriptorandObject.keysnow see properties held in
the carrier bag. +4 files, 0 regressions, validated against the complete
729-file at-risk stratum (built-ins/**/{name,length}.js), not a sample. - Deletability on class instances (#4098 stage 1).
delete o[k]is now real
on a user-declared class instance, via a per-instance tombstone store. This is
substrate: it flips no test262 files on its own (the property-descriptor
verifier is all-or-nothing and needs the remaining stages), and shipping it
alone is deliberate — the alternative partial reproduces a known 684-file
regression.
Fixes
Object.createsilently dropped every accessor descriptor (#4061). Its
static expansion set the accessor flag but never compiled the getter, so
Object.create({}, {p: {get: () => 9}}).pevaluated to0— a wrong answer
with no error, on the legal path. Accessor-bearing descriptors now route to
the dynamic applier.- Descriptor-argument validation per §8.10.5 (#4061).
Object.createand
Object.definePropertiesnow reject non-object descriptors, non-callable
get/set, and data+accessor conflicts. 16/17 target files, 0 regressions
across a 182-file sweep. - Non-writable builtin properties were silently writable into the closure
bag (#4010). A write to a builtin's non-writablename/lengthwas
deposited invisibly, which madeconfigurable: trueassertions fail across
roughly 700 files whenever own-property queries widened. Fixed at the source
(§10.1.9OrdinarySetis a no-op over a non-writable own data property)
rather than at the query.
Other
- Pre-commit fast lane. The full pre-commit chain exceeded tooling timeouts,
which drove wholesale--no-verifyand disarmed the cheap format/lint gate
along with it.SKIP_SLOW_PRECOMMIT=1now skips only the slow checks; the
formatter always runs. CI is unchanged. - Issues filed with reduced repros and measurement-backed acceptance criteria:
#4143, #4146, #4147, #4148, #4151.
Known gaps
Object.prototype.toStringonDate/Error/RegExp/class instances,
$Proxy, and Symbol/BigInt wrappers still refuses loudly (#4119 arm 2 and
successors). A refusal is deliberate here: a wrong tag would be worse.Array.prototypemethods other thanslice/toStringstill refuse when used
as values (#4119, #3571).- Class instance fields remain invisible to
getOwnPropertyDescriptorand
Object.keys(#4098 stages 2–4); only deletability landed in this release.