Skip to content

fix(runtime,hir): built-ins/Function test262 parity (v2) — 67.4% → 93.7%#4868

Merged
proggeramlug merged 4 commits into
mainfrom
function-v2-parity
Jun 10, 2026
Merged

fix(runtime,hir): built-ins/Function test262 parity (v2) — 67.4% → 93.7%#4868
proggeramlug merged 4 commits into
mainfrom
function-v2-parity

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Summary

built-ins/Function test262: 308 → 428 / 457 (67.4% → 93.7%, +120 tests), judged against the node v26 oracle via scripts/test262_subset.py on the 48-core box.

Zero regressions: broad shard 0/12 over built-ins language (2645 judged) — base 2358 pass (89.1%) → branch 2388 pass (90.3%), 30 tests fixed outside Function, 0 regressions (failure-set diff, suspicious entries re-verified isolated). Unit tests green: perry-hir, perry-codegen, perry-runtime (1006 passed, RUST_TEST_THREADS=1).

Root causes fixed

1. new Function / Function(...) const-prop (fn_ctor_env.rs, new) — beyond direct literals, arguments now resolve through: single-assignment module vars (shadow-aware whole-module write scan — a harness for (var i...) inside a function no longer disqualifies a module-level counter), object literals with constant toString bodies (incl. "arg" + (++i) counters, leading p = 1 side effects replayed at runtime, throw-propagation in spec ToString order), Object(<lit>) wrappers, arg-level constant expressions (p + "," + p), Function.call/apply(thisArg, ...), and AsyncFunction/GeneratorFunction/AsyncGeneratorFunction obtained via <fn literal>.constructor (var- or decl-declared). The fold assembles the exact spec source function anonymous(P\n) {\nbody\n} (comment-in-params safe), registers it for toString, names the function anonymous, and raises strict-mode early errors (dup/eval/arguments params under a "use strict" body) plus stray-private-name SyntaxErrors. This converted all 20 compile-refusals into spec behavior.

2. Module top-level this (Expr::ModuleTopThis) — the oracle runs assembled cases as CJS where top-level this is module.exports, not globalThis. Top-level this now lowers to a fresh per-thread exports-like object. Single biggest win (+32 in-dir, plus prop-desc.js-style fixes across Object/String/Array/NativeErrors in the broad shard).

3. OrdinaryCallBindThis — codegen emits js_register_closure_strict_function per strict function (mirrors the arrow registry); call/apply/bind box a primitive thisArg once for sloppy user callees (writes through this persist: Function("this.touched=true;return this").apply(1)), while strict callees observe the raw primitive (fun.call("") strict tests).

4. Proxy-of-callabletypeof is "function" (registry check before the heap floor — proxy ids are small pointers); Function.prototype.toString, String(), concat and ToPrimitive yield the NativeFunction form (fixes a "" + proxy segfault); js_proxy_get reifies call/apply/bind value reads with the proxy as receiver so invocation routes the apply trap.

5. Function.prototype & reflectionFunction.prototype is callable (returns undefined), [object Function], new Function.prototype throws; reified call/apply/bind carry spec .length (1/2/1) and are non-constructors (new (f.apply) throws); user expandos on Function.prototype (data + accessors) resolve through any closure; class accessors reflect in getOwnPropertyDescriptor (prototype + static, via vtable→callable trampolines); class refs stringify as function C() { [native code] } instead of their numeric id.

6. bind — brand-check TypeError on non-callables; .length honors an own length override with ToIntegerOrInfinity (NaN→0, Infinity, >int32); bound name/length attrs non-enumerable.

7. Poison pills & misccaller/arguments get and set throw on every closure (both set paths incl. PutValue); fn.length() throws (non-callable doubles no longer reinterpreted as raw pointers in js_native_call_value); fn.apply(this, arguments) works (raw-pointer argArray + arguments-object unpacking; CreateListFromArrayLike TypeError for primitives); unresolved identifier reads consult globalThis before the ReferenceError (runtime-created globals).

8. Latent Linux crash fixes (pre-existing, exposed during verification)js_is_symbol dereferenced registry-handle "pointers" below the heap floor; is_registered_set probed the GC header before the registry; Object.seal(TypedArray) read keys_array off a TA header. All three segfaulted on Linux only (mimalloc on macOS retains pages). Also #[used] keepalives for the new generated-code-only entry points, and proxy.rs split (proxy/reflect_misc.rs) for the 2000-line gate.

Remaining in-dir failures (29)

15.3.5.4_2-*gs need V8's real sloppy .caller tracking (node returns the live caller); 3× bound-construct new.target; Function.prototype.bind.apply(Date, …) construct; 2× internals/Construct (revoked-proxy ctor, derived-return-val); S15.3.4_A4 (Object.prototype inheritance-for-reads gap, #4789-deferred); abrupt array-like getters in apply; toString source-exactness for unicode escapes / computed method names; Function.call(this, "return planet;") matching node's global-scope semantics (known deviation, traded for 2 wins).

Validation

  • built-ins/Function: 457 judged, 428 pass / 29 runtime-fail / 0 compile-fail / 0 diff
  • shard 0/12 built-ins language: 2645 judged, base 2358 → branch 2388, 0 regressions
  • cargo test (hir, codegen, runtime), cargo fmt --check, scripts/check_file_size.sh all green
  • No version/CHANGELOG edits (maintainer folds metadata at merge)

Ralph Küpper added 4 commits June 10, 2026 05:42
- const-prop for Function(...)/new Function(...): single-assignment module
  vars, toString-bearing object literals (incl counters + poison side
  effects), Object() wrappers, throw-propagation in ToString order,
  spec-assembled 'function anonymous(...)' source + name, strict-mode
  early errors, stray-private-name SyntaxError, Function.call/apply
  folding, AsyncFunction/GeneratorFunction via fn-literal .constructor
- OrdinaryCallBindThis: strict-function registry (codegen-emitted);
  call/apply/bind box primitive thisArg once for sloppy user callees
- reified call/apply/bind: spec .length, non-constructor
- proxy-of-callable: typeof 'function', toString/ToString/ToPrimitive
  NativeFunction form (fixes '' + proxy segfault)
- Function.prototype: callable (returns undefined), [object Function],
  new Function.prototype throws, expando proto-walk from closures
- bind: brand-check TypeError, length via own-prop ToIntegerOrInfinity
  (NaN/Infinity/>int32), name/length attrs non-enumerable
- class accessors reflect in getOwnPropertyDescriptor (proto + static);
  class-ref toString/String/concat → native form, not class id
- fn.length()/fn.name() calls throw; caller/arguments writes poison all
  closures; fn.apply(this, arguments) raw-pointer argArray
- module top-level 'this' = fresh CJS-style exports object (matches the
  node oracle); unresolved ident reads consult globalThis before
  ReferenceError
…rimitive + js_is_symbol floor, apply(this,arguments) raw argArray + arguments-object unpack, arg-expression const-eval, fn-decl .constructor kinds, PutValue caller poison, class-ref stringification
…imitive + js_is_symbol floor, apply(this,arguments) raw argArray + arguments-object unpack, arg-expression const-eval (p+","+p), fn-decl .constructor kinds, PutValue caller poison, class-ref stringification
- js_proxy_get: call/apply/bind value reads on callable-wrapping proxies
  reify with the PROXY as receiver so later invocation routes the apply
  trap (built-ins/Proxy/apply/*); fn-proto expando fallback restricted to
  user expandos only (numeric keys excluded)
- Object.seal(TypedArray): skip mark_all_keys (TA headers have no
  keys_array — garbage deref segfaulted on Linux); is_registered_set
  checks the registry before dereferencing the GC header (same latent
  Linux crash class)
- hasOwnProperty('prototype') is predicate-only (materializing locked the
  slot before a later defineProperty — TypedArrayConstructors custom-proto)
- proxy.rs split (reflect_misc.rs) for the 2000-line gate; #[used]
  keepalives for the new generated-code-only runtime entry points
@proggeramlug proggeramlug merged commit ec30493 into main Jun 10, 2026
13 checks passed
@proggeramlug proggeramlug deleted the function-v2-parity branch June 10, 2026 03:59
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