Skip to content

fix: revert the #5874 payload swept onto main — restore 322 test262 regressions#6015

Merged
proggeramlug merged 1 commit into
mainfrom
fix/revert-5874-payload-rebased
Jul 5, 2026
Merged

fix: revert the #5874 payload swept onto main — restore 322 test262 regressions#6015
proggeramlug merged 1 commit into
mainfrom
fix/revert-5874-payload-rebased

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Fixes #6013.

Culprit (independently bisected)

A test262 sweep of main at the #6008 tip (76cc2b996) regressed vs the #5979 tip: parity 96.5% → 95.8%, Temporal self-validated 99.1% → 96.7%, 322 tests newly failing.

git bisect (good 28948ea44 .. bad 76cc2b996, witness slice = Boolean/Number/Temporal.Duration parity) lands unambiguously on 849f297a8 — "Improve Zod compatibility support" (#5874):

commit witness parity Boolean Temporal.Duration self-validated
4f5bc6adb (#5981, parent-2) 98.3% 89% 100% 100%
849f297a8 (#5874) — first bad 93.9% 67% 95% 95.1%
76cc2b996 (main tip) 93.9% 67% 95% 95.1%

(532853f4a, the commit between 4f5bc6adb and 849f297a8, is a metadata-only version chore.)

#5874 was a 156-file monolithic squash that, alongside the intended Zod work, swept in unreviewed codegen/runtime WIP, ~30 stray tests/*.sh, and two 5.1MB binaries (constv, direct) at the repo root. Two of the swept-in changes are the dominant regressors:

  • crates/perry-codegen/src/lower_call/property_get/number_string.rs gated the universal .toString() interception on is_numeric_expr || is_bigint_expr. Boxed built-in receivers (new String(), new Number(), new Date()) with a user-assigned built-in method (s.toString = Boolean.prototype.toString; s.toString()) then bypassed the receiver brand-check and no longer threw TypeError — the "method is not a function" / SameValue clusters. (property_get.rs reclassified trim/case-conversion methods the same way.)
  • The runtime prototype-identity / class-registry / instanceof rewrite regressed Temporal subclass prototype resolution (Object.getPrototypeOf(result) === construct.prototype), producing the Temporal 159 cluster and (no output) crashes.

Fix

Inverse-patch of the #5874 payload against current main, restoring every unintended path to its last-good (532853f4a / v0.5.1238) state and deleting the constv / direct binaries. The legitimate later PRs that built on these files — notably #5991 (class X extends Promise) — are preserved (their additions to this_super_call.rs, lower_call/new*.rs, and value/dynamic_arith.rs, plus #5999's js_dynamic_mod fmod-sign fix, are kept). The intended #5983 stdlib change (external-http-client-pump dropped from full) is untouched and links green.

The swept-in work remains in history at 849f297a8 for its author to re-land through review in reviewable pieces.

Verification (built + run on an internal Linux sweep host)

Witness slice (Boolean/Number/Temporal.Duration.compare/from) returns to the last-good numbers:

bad main (76cc2b996) this revert
built-ins/Boolean 67% 89%
built-ins/Number 96% 98%
built-ins/Temporal.Duration 95% 100%
slice parity 93.9% 98.3%
self-validated 95.1% 100%

Broad re-sweep (built-ins/Temporal, Boolean, Number, language/expressions, Proxy, Function) confirms net-positive with zero new regressions. Direct repros: the boxed-receiver brand-check case now throws TypeError as Node does, and Temporal.Duration.from(...).apply(...) + prototype identity work.

cargo fmt --all -- --check clean.

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 153 files, which is 3 over the limit of 150.

To get a review, narrow the scope:
• coderabbit review --type committed # exclude uncommitted changes
• coderabbit review --dir # limit to a subdirectory
• coderabbit review --base # compare against a closer base

Upgrade to a paid plan to raise the limit.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 017a0ed9-e2ea-4c88-99a3-82cec7437bc5

📥 Commits

Reviewing files that changed from the base of the PR and between 76cc2b9 and 76b2573.

⛔ Files ignored due to path filters (3)
  • node_trace.1.log is excluded by !**/*.log
  • tests/release/packages/zod3-basic/package-lock.json is excluded by !**/package-lock.json
  • tests/release/packages/zod4-basic/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (153)
  • constv
  • crates/perry-codegen/src/codegen/artifacts.rs
  • crates/perry-codegen/src/codegen/closure.rs
  • crates/perry-codegen/src/codegen/entry.rs
  • crates/perry-codegen/src/codegen/function.rs
  • crates/perry-codegen/src/codegen/helpers.rs
  • crates/perry-codegen/src/codegen/method.rs
  • crates/perry-codegen/src/codegen/mod.rs
  • crates/perry-codegen/src/codegen/module_globals_emit.rs
  • crates/perry-codegen/src/codegen/opts.rs
  • crates/perry-codegen/src/expr/dyn_extern_i18n.rs
  • crates/perry-codegen/src/expr/index_get.rs
  • crates/perry-codegen/src/expr/instance_misc1.rs
  • crates/perry-codegen/src/expr/mod.rs
  • crates/perry-codegen/src/expr/property_get.rs
  • crates/perry-codegen/src/expr/this_super_call.rs
  • crates/perry-codegen/src/lower_call/console_promise.rs
  • crates/perry-codegen/src/lower_call/namespace_call.rs
  • crates/perry-codegen/src/lower_call/new.rs
  • crates/perry-codegen/src/lower_call/new_helpers.rs
  • crates/perry-codegen/src/lower_call/property_get.rs
  • crates/perry-codegen/src/lower_call/property_get/number_string.rs
  • crates/perry-codegen/tests/argless_builtin_extra_args.rs
  • crates/perry-codegen/tests/class_keys_gc_root.rs
  • crates/perry-codegen/tests/constructor_recursion.rs
  • crates/perry-codegen/tests/destructure_call_location.rs
  • crates/perry-codegen/tests/large_object_barriers.rs
  • crates/perry-codegen/tests/macos_bundle_chdir_gate.rs
  • crates/perry-codegen/tests/native_proof_buffer_views.rs
  • crates/perry-codegen/tests/native_proof_regressions.rs
  • crates/perry-codegen/tests/shadow_slot_hygiene.rs
  • crates/perry-codegen/tests/static_symbol_hygiene.rs
  • crates/perry-codegen/tests/typed_feedback.rs
  • crates/perry-codegen/tests/typed_shape_descriptor.rs
  • crates/perry-codegen/tests/typed_shape_descriptors.rs
  • crates/perry-hir/src/dynamic_import.rs
  • crates/perry-hir/src/dynamic_import/tests.rs
  • crates/perry-hir/src/dynamic_import/visitors.rs
  • crates/perry-hir/src/eval_classifier.rs
  • crates/perry-hir/src/lower/closure_analysis.rs
  • crates/perry-hir/src/lower/const_fold_fn.rs
  • crates/perry-hir/src/lower/expr_call/array_only_methods.rs
  • crates/perry-hir/src/lower/expr_call/imported_array_methods.rs
  • crates/perry-hir/src/lower/expr_function.rs
  • crates/perry-hir/src/lower/expr_new.rs
  • crates/perry-hir/src/lower/lower_expr/arm_class.rs
  • crates/perry-hir/src/lower/lower_module_fn.rs
  • crates/perry-hir/src/lower/module_decl.rs
  • crates/perry-hir/src/lower/module_decl/reexports.rs
  • crates/perry-hir/src/lower/stmt.rs
  • crates/perry-hir/src/lower_decl/block.rs
  • crates/perry-hir/src/lower_decl/body_stmt.rs
  • crates/perry-hir/src/lower_decl/enum_decl.rs
  • crates/perry-hir/src/lower_decl/mod.rs
  • crates/perry-hir/src/lower_decl/static_init.rs
  • crates/perry-hir/src/lower_patterns.rs
  • crates/perry-runtime/src/collection_iter.rs
  • crates/perry-runtime/src/json/replacer.rs
  • crates/perry-runtime/src/map.rs
  • crates/perry-runtime/src/node_submodules/blob.rs
  • crates/perry-runtime/src/object/array_object_ops.rs
  • crates/perry-runtime/src/object/class_registry.rs
  • crates/perry-runtime/src/object/class_registry/construct.rs
  • crates/perry-runtime/src/object/class_registry/parent_static.rs
  • crates/perry-runtime/src/object/class_registry/state.rs
  • crates/perry-runtime/src/object/descriptors.rs
  • crates/perry-runtime/src/object/field_get_set/get_field_by_name.rs
  • crates/perry-runtime/src/object/field_get_set/get_field_by_name_tail.rs
  • crates/perry-runtime/src/object/field_get_set/has_property.rs
  • crates/perry-runtime/src/object/global_this.rs
  • crates/perry-runtime/src/object/global_this/builtin_thunks.rs
  • crates/perry-runtime/src/object/global_this/proto_methods.rs
  • crates/perry-runtime/src/object/instanceof.rs
  • crates/perry-runtime/src/object/mod.rs
  • crates/perry-runtime/src/object/native_call_method.rs
  • crates/perry-runtime/src/object/native_call_method/collection_methods.rs
  • crates/perry-runtime/src/object/native_call_method/common_methods.rs
  • crates/perry-runtime/src/object/native_call_method/primitive_methods.rs
  • crates/perry-runtime/src/object/object_ops/define_properties.rs
  • crates/perry-runtime/src/object/object_ops/define_property.rs
  • crates/perry-runtime/src/object/object_ops/has_own.rs
  • crates/perry-runtime/src/object/object_ops/prototype.rs
  • crates/perry-runtime/src/object/to_string_tag.rs
  • crates/perry-runtime/src/proxy.rs
  • crates/perry-runtime/src/set.rs
  • crates/perry-runtime/src/string/char_ops.rs
  • crates/perry-runtime/src/string/format.rs
  • crates/perry-runtime/src/symbol/get.rs
  • crates/perry-runtime/src/url/mod.rs
  • crates/perry-runtime/src/url/parse.rs
  • crates/perry-runtime/src/value/dyn_index.rs
  • crates/perry-runtime/src/value/dynamic_arith.rs
  • crates/perry-runtime/src/value/nanbox.rs
  • crates/perry-stdlib/src/fetch/dispatch.rs
  • crates/perry/src/commands/compile/collect_modules.rs
  • crates/perry/src/commands/compile/object_cache.rs
  • crates/perry/src/commands/compile/run_pipeline.rs
  • direct
  • test-files/test_parity_bigint_switch.ts
  • test-files/test_parity_builtin_subclass_fields.ts
  • test-parity/known_failures.json
  • tests/_perry_test_lib.sh
  • tests/release/packages/zod3-basic/entry.ts
  • tests/release/packages/zod3-basic/expected.txt
  • tests/release/packages/zod3-basic/fixture.sh
  • tests/release/packages/zod3-basic/package.json
  • tests/release/packages/zod4-basic/entry.ts
  • tests/release/packages/zod4-basic/expected.txt
  • tests/release/packages/zod4-basic/fixture.sh
  • tests/release/packages/zod4-basic/package.json
  • tests/test_array_not_instanceof_error_subclass.sh
  • tests/test_bigint_samevalue_map.sh
  • tests/test_bigint_samevalue_set.sh
  • tests/test_builtin_prototype_and_fetch_reflection.sh
  • tests/test_builtin_subclass_implicit_ctor_fields.sh
  • tests/test_class_define_property_name.sh
  • tests/test_dynamic_arithmetic_bigint_any.sh
  • tests/test_dynamic_class_extends_once.sh
  • tests/test_dynamic_extends_class_binding.sh
  • tests/test_dynamic_function_probe_fallback_stderr.sh
  • tests/test_dynamic_import_package_registry.sh
  • tests/test_dynamic_parent_builtin_no_downgrade.sh
  • tests/test_error_subclass_arrow_field_init.sh
  • tests/test_export_enum_runtime_object.sh
  • tests/test_file_instanceof.sh
  • tests/test_forward_captured_let_box.sh
  • tests/test_function_prototype_instanceof.sh
  • tests/test_imported_default_named_reexport.sh
  • tests/test_imported_error_new_target.sh
  • tests/test_imported_static_field_alias_method.sh
  • tests/test_json_stringify_replacer_key_order.sh
  • tests/test_map_set_subclass_constructor_iterable.sh
  • tests/test_missing_error_property_undefined.sh
  • tests/test_namespace_default_alias_call.sh
  • tests/test_namespace_homonymous_class_export.sh
  • tests/test_namespace_homonymous_var_function_exports.sh
  • tests/test_namespace_reexport_binding.sh
  • tests/test_namespace_reexport_optional_arg.sh
  • tests/test_namespace_subobject_method_call.sh
  • tests/test_new_parameter_shadows_class.sh
  • tests/test_number_to_string_large_exponent.sh
  • tests/test_object_create_for_in_prototype.sh
  • tests/test_object_create_in_operator_prototype.sh
  • tests/test_object_create_inherited_constructor.sh
  • tests/test_object_prototype_method_call_fallback.sh
  • tests/test_own_to_string_method.sh
  • tests/test_prototype_cycle_has_property.sh
  • tests/test_reflect_set_frozen_array.sh
  • tests/test_string_computed_length.sh
  • tests/test_switch_bigint_case.sh
  • tests/test_unicode_regex_literal.sh
  • tests/test_url_href_normalization.sh
  • tests/test_url_instanceof_reflection.sh

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/revert-5874-payload-rebased

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…essions

A test262 sweep of main at the #6008 tip regressed vs the #5979 tip
(parity 96.5% -> 95.8%, Temporal self-validated 99.1% -> 96.7%, 322
tests newly failing). git bisect (good 28948ea .. bad 76cc2b9,
witness = built-ins/Boolean + Number + Temporal.Duration parity) lands
on 849f297 "Improve Zod compatibility support" (#5874) as the first
bad commit: 98.3% witness parity at its parent-2 (4f5bc6a) drops to
93.9% at #5874 (Boolean 89%->67%, Temporal 100%->95%, self-validated
100%->95.1%).

#5874 was a 156-file monolithic squash that swept in unreviewed
codegen/runtime WIP + two 5.1MB binaries (constv, direct) + ~30 stray
tests/*.sh alongside the intended Zod work. Two swept changes dominate:

  - codegen/lower_call/property_get/number_string.rs gated the universal
    .toString() interception on is_numeric_expr || is_bigint_expr, so
    boxed built-in receivers (new String()/Number()/Date()) with a
    user-assigned built-in method bypassed the brand-check and stopped
    throwing TypeError (Boolean S15.6.4.2_A2_T1..T3) -> the "method is
    not a function" + SameValue clusters.
  - the runtime prototype-identity / class-registry / instanceof rewrite
    regressed Temporal subclass prototype resolution
    (Object.getPrototypeOf(result) === construct.prototype) -> the
    Temporal 159 + "(no output)" crash clusters.

This is the inverse patch of the #5874 payload applied to CURRENT main
(not a snapshot restore), so the later fleet merges are preserved:

  - #5991 (class X extends Promise): its promise_parent_runtime scaffold,
    emit_promise_subclass_init wiring, and new_helpers additions are
    kept (subclass executor resolves and .then sees the value).
  - #5999 (js_dynamic_mod fmod sign-of-zero): kept; only #5874s
    dynamic_number_operand double-coercion was dropped from the modulo
    path.
  - #5983 (external-http-client-pump dropped from stdlib full): untouched
    and links green.

new.rs / new_helpers.rs: reverting new.rs to its pre-#5874 form put it
at 2000 lines; applying #5991s +9 net lines on top pushed it to 2009,
over the 2000-line file-size gate. Moved three self-contained ctor
predicate helpers (effective_constructor_param_count,
local_constructor_symbol_exists, ctor_chain_uses_new_target) into the
new_helpers sibling to restore the split (new.rs -> 1939 lines).

Verified on an internal Linux sweep host: witness slice back to 98.3% /
self-validated 100% / Temporal.Duration 100%; fmt + file-size +
gc-store-site + addr-class audits clean. #5874 remains in history for
its author to re-land in reviewable pieces.
@proggeramlug proggeramlug force-pushed the fix/revert-5874-payload-rebased branch from 796125f to 76b2573 Compare July 5, 2026 06:57
@proggeramlug

Copy link
Copy Markdown
Contributor Author

Verification (internal Linux sweep host)

Witness slice (built-ins/Boolean/prototype/toString + Number/prototype/toString + Temporal/Duration/{compare,from}) restored to the last-good (4f5bc6adb) numbers:

dir bad main (76cc2b996) this PR
built-ins/Boolean 67% 89%
built-ins/Number 96% 98%
built-ins/Temporal.Duration 95% 100%
slice parity 93.9% 98.3%
self-validated 95.1% 100%

(Boolean 89% / Number 98% are pre-existing — identical on the good baseline 4f5bc6adb; not part of this regression.)

Direct repros on the built binary:

  • s = new String(); s.toString = Boolean.prototype.toString; s.toString() now throws TypeError as Node does (was silently returning a value).
  • Temporal.Duration.from(...).apply(...) + Object.getPrototypeOf(r) === Temporal.Duration.prototype both correct.

Lint gate green after moving three ctor-predicate helpers into the new_helpers sibling (revert put new.rs back to its pre-#5874 2000-line form; #5991's +9 net lines pushed it to 2009 over the 2000-line gate → now 1939). cargo fmt --all -- --check, check_file_size.sh, GC store-site inventory, and addr-class audit all pass.

@proggeramlug proggeramlug merged commit 5afa08f into main Jul 5, 2026
16 of 17 checks passed
@proggeramlug proggeramlug deleted the fix/revert-5874-payload-rebased branch July 5, 2026 07:05
proggeramlug added a commit that referenced this pull request Jul 5, 2026
…6014)

Boot-chain hardening behind #5989 (dynamic RSC render evaporation), the subset independent of #5874 (which #6015 reverted mid-review):

1. hir,runtime: strict-mode assignment to an existing global builtin is a property write, not a ReferenceError (spec PutValue) — Next's cacheComponents installs its Date extension via strict 'Date = createDate(Date)', which previously failed at boot. New js_global_assign_existing_or_throw helper; both HIR assign arms via a shared helper; absent bindings still throw the named ReferenceError.
2. runtime: make the Date-extension wrapper construct real Dates — reified Reflect.construct was a no-op stub; Reflect.construct(Date,args,newTarget) didn't brand; constructor-name recovery broke on global reassignment. Fixed all three.
3. runtime: validate keys_array before deref in shape_is_url_search_params — a mid-transition GC_TYPE_OBJECT receiver SIGSEGV'd on the first request; require the eager GC_TYPE_ARRAY layout (try_read_gc_header, #5429/#5943 family).

Includes both CodeRabbit review fixes (reject GC_TYPE_LAZY_ARRAY; shared strict-assign helper). Validated on current main: builds green, integration tests pass, Date extension installs+constructs (proto-constructor matches node), 21/23 class/date/reflect gap with zero new regressions.

The two class-forward-capture fixes are deferred — #6015's revert of #5874 removed the class-lowering machinery they built on; they'll be re-derived against the post-revert base (tracked in #5989).
proggeramlug added a commit that referenced this pull request Jul 5, 2026
…ar-bound multi-array loops run inline (#6033)

A tight float loop (`for (i = 1; i < N; i++) ema[i] = prices[i]*a +
ema[i-1]*b`) ran ~9x slower than Node: the existing packed-f64 loop
versioning only matched `i < arr.length` bounds on a single array with
exact-`i` indices, so every access went through generic runtime calls
(reads probing four registries per element, stores paying the write
barrier's thread-local preamble per element).

Codegen:
- new range-loop matcher + lowering (stmt/loops.rs): scalar loop-invariant
  bounds (`i < N`), multiple arrays per loop, affine `i±c` indices; one
  range guard per array at loop entry, hole-checked inline loads with a
  side exit to the slow loop
- array-kind facts: seed params and `new Array<number>(n)` locals
  (Generic{"Array"} type spelling + New{Array} initializers); facts stay
  versioning hints — every fast loop is runtime-guard validated
- `arr[i±c]` offset support in the fast-loop index get/set lowerings

Runtime:
- js_typed_feedback_packed_f64_range_loop_guard: kind/shape/frozen checks
  + static index-range bounds proof + hole-tolerant slot canonicalization
  (rebuild_array_numeric_raw_f64_allow_holes)
- GC_ARRAY_RAW_F64_HOLES header bit: `new Array(n)` is raw-f64-or-holes
  by construction; the invariant is maintained by the store choke points
  and makes the guard's verify walk O(1) (also O(1)-fails the per-store
  dense-layout probe while a fill is in flight — the walk there was
  O(N²) across a sequential fill)
- write barrier: primitive-child early-exit before the incremental-mark
  TLS probe; decode_heap_addr fast-rejects f64 payload bit patterns
  before the page-map lookup

EMA benchmark (100k elems × 100 iters): 55.6 → 5.9-6.1 ns/elem — at/below
node v26 (6.0-6.1). Verification: 22-case loop matrix byte-identical to
node (holes, guard-failure fallbacks, param arrays, offset reads);
packed_f64_loop_versioning fixtures green; parity --filter array
unchanged (49 pass, 1 pre-existing failure); cargo test -p perry-runtime
1155/1155 serial; the one perry-codegen failure
(pod_field_read_after_dynamic_materialization_uses_number_coerce) is
pre-existing on main (#6015 revert left tests/native_proof_regressions.rs
uncompilable; this branch restores its compilation).

Known follow-up: an array that later appears as an array-method receiver
(`arr.filter(...)`) is currently rejected by the range matcher, so
fill-then-chain code takes the per-access guarded path (~1.8x slower than
the legacy call on that phase). Tracked for a follow-up relaxation.

Closes #6011

Co-authored-by: Ralph <ralph@skelpo.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.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.

test262 regression on main — parity 96.5%→95.8%, 322 tests (bisecting)

1 participant