Skip to content

fix(runtime): class subclass + async-method + definition test262 tail#4853

Merged
proggeramlug merged 3 commits into
mainfrom
wt-clm-parity
Jun 9, 2026
Merged

fix(runtime): class subclass + async-method + definition test262 tail#4853
proggeramlug merged 3 commits into
mainfrom
wt-clm-parity

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Summary

Fixes the class test262 tail across subclass / async-method / definition / syntax. Target suite (15 dirs) 662 → 685 pass (+23), parity 84.8% → 87.7%, zero regressions (verified via --shard 0/12 over built-ins language + isolated re-runs of every concurrent-shard flaky diff).

Root causes & fixes

  1. Methods/getters/setters/bound functions had a prototype own property. ordinary_function_prototype_value_for_read synthesized .prototype for any non-arrow callable incl. bound-method values (C.prototype.m, c.m, fn.bind()). Added closure_is_bound_method and suppress it. (definition/methods, numeric-property-names)
  2. Derived super(message) into a built-in Error set message enumerable. Spec uses DefinePropertyOrThrow {enumerable:false}. Added js_object_set_field_by_name_nonenum, routed all 3 Error-init codegen sites through it. (NativeError/*-message, Error/message-property-assignment)
  3. Static gen/async method .length over-counted. New CLASS_STATIC_METHOD_BIND_LENGTHS table (distinct from instance table) + codegen registration with default-aware spec length. (*-method-static dflt-params-trailing-comma)
  4. class X extends <non-constructor> didn't throw TypeError. New extends_target_must_throw (null OK; primitive/arrow/async/generator/async-gen/non-constructable-builtin/bound-method throw; bound-function + proxy recurse) in js_register_class_parent_dynamic. Also registered async function(){} expression closures as async (they weren't) and made duplicate-named classes re-run the IsConstructor check (test262 reuses class C across blocks). (superclass-arrow/async/generator/async-generator-function)
  5. getOwnPropertyDescriptor(C,'prototype') returned undefined. Added the non-writable/non-enum/non-config prototype data-descriptor arm. (prototype-property)
  6. call_static_method capped at 4 argsconst ref=C.m; ref(a..f) for a static async/gen method dropped args ≥4. Extended to 8 positional params. (*-method-static dflt-params-arg-val-not-undefined)
  7. super.x=v in a class with no extends threw "read only". When super is Object.prototype the fallback now ordinary-[[Set]]s on the receiver. (syntax/class-body-method-definition-super-property)

Before → after (per dir, target suite)

  • language/statements: 400 → 419 pass; language/expressions: 262 → 266 pass.
  • subclass +4, definition +~5, async/gen/async-gen-method-static +~8, syntax +1, gen-method-static +1.

Files

  • runtime: closure/{registry,mod}.rs, object/{class_registry,field_set_by_name,descriptors}.rs, proxy.rs
  • hir: lower_decl/body_stmt.rs
  • codegen: expr/{closure,this_super_call}.rs, lower_call/new.rs, codegen/string_pool.rs, runtime_decls/{objects,stdlib_ffi}.rs

Validation

  • Target suite 662 → 685 (+23), 0 regressions.
  • --shard 0/12 over built-ins language (2645 judged): 249 rt-fail vs baseline 251 — 0 regressions / 2 fixed.
  • Shards 3/12 & 7/12 surfaced 17 apparent diffs; all re-ran clean in isolation (concurrent-shard contention, mostly Temporal).

Deferred (larger separate work)

async-gen yield* return/throw delegation (~34); subclass-of-builtins exotics; derived-ctor this-TDZ / return-override + null-proto; class accessor descriptor callable get/set; symbol-keyed method retrieval; named-class-expression name leaking to outer scope.

@proggeramlug proggeramlug merged commit e8c7abe into main Jun 9, 2026
12 of 13 checks passed
@proggeramlug proggeramlug deleted the wt-clm-parity branch June 9, 2026 18:59
proggeramlug added a commit that referenced this pull request Jun 9, 2026
…+ body_stmt.rs file-size split) (#4855)

* style: cargo fmt --all after #4853 (unblocks lint on every PR)

#4853 merged with formatting that the current stable rustfmt
(1.9.0 / rustc 1.96.0, what CI's dtolnay/rust-toolchain@stable
installs) rejects, so the required 'lint' check now fails on every
PR's merge ref regardless of its content (first seen on wt-clm-parity
at 18:51Z, then worktree-fix-4851/#4854). Formatting-only change,
no code edits.

* refactor(hir): split for-await target-detection helpers out of body_stmt.rs (file-size gate)

body_stmt.rs hit 2038 lines on main (limit 2000), so the lint job's
file-size gate fails every PR even after the fmt fix. Move the
self-contained for-await/for-of head-expression detection predicates
(ReadableStream / Node Readable / readline / fs.Dir) plus the
IteratorClose helpers into body_stmt/detect.rs, following the existing
body_stmt/for_await.rs split pattern. Pure code motion, no behavior
change; body_stmt.rs is now 1826 lines.

---------

Co-authored-by: Ralph Küpper <ralph@skelpo.com>
proggeramlug pushed a commit that referenced this pull request Jun 9, 2026
Release Packages v0.5.1150 failed on 5 of 19 build jobs and main's lint
gate went red after #4853 merged with an admin bypass. This PR makes the
next release tag green across all platforms:

- perry-ui-android drag_drop.rs: E0597 `jstr` does not live long enough
  (broke both aarch64- and x86_64-linux-android). The
  `env.get_string(&jstr)` Result temporary outlived `jstr` as an if-let
  tail expression; bind the converted String first. Verified via
  `cargo check -p perry-ui-android --target aarch64-linux-android`
  with NDK r30.
- rustfmt: format the four files #4853 merged unformatted
  (lint job was red on main).
- file-size gate: body_stmt.rs hit 2038 lines (limit 2000); extract the
  for-await target-detection + iterator-close helpers into
  body_stmt/iter_helpers.rs (1819 lines now), no behavior change.
- binary-size baseline: refresh to v0.5.1150 measured sizes following
  the v0.5.1122 precedent. libperry_runtime grew +34.8% over the 5-day
  v0.5.1122 → v0.5.1150 parity push (317 commits, 198 touching
  perry-runtime, +30.6k LOC) — verified broad organic growth, not a
  single pathological commit.

Not fixed here (already on main): perry-ui-windows windows_core E0433
was fixed by #4837 two hours after the v0.5.1150 tag. The
perry-cross-aarch64-apple-darwin upload failure was a transient GitHub
API outage; the build itself succeeded.
proggeramlug added a commit that referenced this pull request Jun 9, 2026
* fix(ci): unbreak release platform builds + lint gates

Release Packages v0.5.1150 failed on 5 of 19 build jobs and main's lint
gate went red after #4853 merged with an admin bypass. This PR makes the
next release tag green across all platforms:

- perry-ui-android drag_drop.rs: E0597 `jstr` does not live long enough
  (broke both aarch64- and x86_64-linux-android). The
  `env.get_string(&jstr)` Result temporary outlived `jstr` as an if-let
  tail expression; bind the converted String first. Verified via
  `cargo check -p perry-ui-android --target aarch64-linux-android`
  with NDK r30.
- rustfmt: format the four files #4853 merged unformatted
  (lint job was red on main).
- file-size gate: body_stmt.rs hit 2038 lines (limit 2000); extract the
  for-await target-detection + iterator-close helpers into
  body_stmt/iter_helpers.rs (1819 lines now), no behavior change.
- binary-size baseline: refresh to v0.5.1150 measured sizes following
  the v0.5.1122 precedent. libperry_runtime grew +34.8% over the 5-day
  v0.5.1122 → v0.5.1150 parity push (317 commits, 198 touching
  perry-runtime, +30.6k LOC) — verified broad organic growth, not a
  single pathological commit.

Not fixed here (already on main): perry-ui-windows windows_core E0433
was fixed by #4837 two hours after the v0.5.1150 tag. The
perry-cross-aarch64-apple-darwin upload failure was a transient GitHub
API outage; the build itself succeeded.

* fix(runtime,ci): array sequential growth stays dense + un-vacuum the perf regression gate

Two intertwined Regression Check failures:

1. 03_array_write hang (every perf run cancelled at the 6h job timeout
   since v0.5.1129): #4648 introduced MAX_DENSE_ARRAY_GROW_LENGTH=1M as
   an absolute cap, so a sequential 10M-element fill routed 9M writes
   through string-keyed sparse properties — a linear-scan Vec per
   insert, i.e. quadratic. Sparse storage is now gated on the GAP the
   write creates (index - length > 1024) in addition to the absolute
   size, matching engine dictionary-mode heuristics: sequential growth
   (gap 0) stays dense at any size, far jumps (a[2**32-2] on a small
   array) stay sparse. Verified: 10M-element 03_array_write goes from
   hung (killed at 45s+, was 6h in CI) to ~3.3s, matching the last
   green run; both #4648 node-suite tests stay byte-identical to Node;
   new unit test pins the dense path.

2. The performance gate has been vacuous since at least v0.5.1122:
   compare.sh resolves --json-out after cd'ing into benchmarks/suite,
   so .bench-results/current.json was never written, the comparison
   crashed with FileNotFoundError, and the `| tee` pipeline (no
   pipefail in the default runner shell) swallowed the exit. Every
   release-mode "hard-fail" perf gate passed without comparing
   anything. Fixed: --json-out resolved to an absolute path up front,
   pipefail set in the workflow step, timeout-minutes: 100 on the job
   (healthy runs take ~20min), and benchmarks/baseline.json refreshed
   from the last green Regression Check run (27001035612, 2026-06-05)
   — the April c89b3ad numbers (array_write 3ms vs 3.1-3.4s measured
   on every June run) would hard-fail every release the moment the
   gate started working again.

* perf(runtime): consult sparse array storage only past capacity on reads

#4648 put the sparse-index consult ahead of the dense bounds check in
js_array_get_f64 / js_array_get_f64_unchecked, so every in-capacity read
paid a non-inlined helper call (incl. a second clean_arr_ptr). The
helper returns None below capacity by definition, so gating it on
index >= capacity is exactly behavior-preserving and keeps the dense
hot path call-free. Boundary node-suite test stays byte-identical to
Node.

---------

Co-authored-by: Ralph Küpper <ralph@skelpo.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant