fix(runtime): built-ins/Object test262 parity (v3) — exotic expandos, array descriptors, Object statics#4863
Merged
Merged
Conversation
… array descriptors, Object statics
built-ins/Object: 2862/3173 (90.2%) -> ~3001/3173 (94.6%), +143 tests, zero
regressions (verified by failure-set diff against the baseline sweep).
Root causes, by cluster size:
1. Exotic expando properties (Date/RegExp/Error, ~90 tests). New
object/exotic_expando.rs: own user properties for instances whose heap
form is not an ObjectHeader (DateCell / RegExpHeader / ErrorHeader).
Values live in an insertion-ordered side table keyed by cell address
(Error delegates to the existing ERROR_USER_PROPS store); attributes and
accessors reuse the generic PROPERTY_DESCRIPTORS / ACCESSOR_DESCRIPTORS
tables. Wired into set (js_object_set_field_by_name guard +
js_put_value_set), get (per-kind arms), defineProperty, gOPD, gOPN,
keys, has/hasOwnProperty, delete, propertyIsEnumerable, freeze/seal,
TestIntegrityLevel. A registered GC scanner keeps stored values alive;
Date/RegExp allocation clears stale entries on address reuse. Writes
falling through to an accessor on the builtin prototype invoke the
setter instead of creating an own property; Error instance reads fall
back to <Kind>.prototype then Error.prototype. Previously: Date expando
sets crashed in ordinary_set_with_receiver (cell bit-cast as
ObjectHeader), RegExp sets wrote through garbage field offsets, and
ToPropertyDescriptor couldn't read exotic attribute bags.
2. Array descriptor semantics (~70 tests). Named-key accessors on array
targets were silently dropped (define stored undefined as data);
accessor get/set now dispatches on the named path, the dynamic index
paths, and the raw numeric fast paths (array_numeric_raw_f64_get/
set_inbounds, js_array_get/set_f64_unchecked, js_array_set_f64_extend
gate on descriptors_in_use). defineProperty(arr,'length',
{writable:false}) is now honored by gOPD, arr.length writes, and
extending index stores. A generic (attrs-only) redefine no longer
converts an accessor index back to data; accessor->data conversions
default writable to false instead of retaining the accessor's
placeholder attrs; data->accessor keeps the existing dense element's
enumerability. [[DefineOwnProperty]] stores clear stale attrs first so
the new [[Set]]-side writability gate can't reject them, and the
element is materialized before the accessor is installed so the
internal write doesn't fire the brand-new setter.
3. Object statics reified (~35 tests). install_builtin_constructor_statics
now installs seal/isSealed/isFrozen/isExtensible/preventExtensions/is/
setPrototypeOf/getOwnPropertySymbols/getOwnPropertyDescriptors/
defineProperties/groupBy as real closures (Object.create length fixed
to 2, with Properties-arg support); codegen value reads of
Object.<static> (GlobalGet sentinel) route to those closures for names
unique to Object — the Reflect-overlapping names (defineProperty,
getOwnPropertyDescriptor, get/setPrototypeOf, isExtensible,
preventExtensions) and Map-overlapping groupBy keep their old behavior
since the HIR collapses the receiver name.
4. freeze/seal/TestIntegrityLevel on non-ObjectHeader receivers. The
mark_all_keys walk bit-cast TypedArray/closure/exotic receivers (the
seal-int8array crash was latent and surfaced when this PR's extra
closure installs shifted the heap layout). TypedArrays now use the GC
flag bits only; closures and exotics freeze/seal via side-table attrs.
5. Smaller fixes: symbol-keyed writes honor FROZEN/NO_EXTEND/per-symbol
writability; Object.getPrototypeOf(primitive) returns the wrapper
prototype (class-ref INT32 values excluded); array Object.keys/gOPN
include accessor-only properties; js_put_value_set relocated to
proxy/put_value.rs for the 2000-line gate.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Third pass on
built-ins/Objecttest262 parity (after #4784 / #4789). Groups the remaining ~311 failures by root cause and fixes the five biggest clusters.built-ins/Object: 2862/3173 (90.2%) → 3006/3173 (94.7%), +144 tests, zero regressions.
Root causes
1. Exotic expando properties — Date / RegExp / Error (~90 tests)
New
crates/perry-runtime/src/object/exotic_expando.rs: own user properties for instances whose heap form is not anObjectHeader(DateCell/RegExpHeader/ErrorHeader). test262 exercises these in both directions: asdefinePropertytargets and as the attributes bag (dateObj.value = "x"; Object.defineProperty(o, k, dateObj)).ERROR_USER_PROPSstore); attributes/accessors reuse the genericPROPERTY_DESCRIPTORS/ACCESSOR_DESCRIPTORStables.js_object_set_field_by_nameguard +js_put_value_set), get (per-kind arms),defineProperty,getOwnPropertyDescriptor,getOwnPropertyNames,keys,has/hasOwnProperty,delete,propertyIsEnumerable,freeze/seal,TestIntegrityLevel.Object.defineProperty(Date.prototype, "p", {set})) invoke the setter instead of creating an own property; Error reads fall back to<Kind>.prototype→Error.prototype.Previously: Date expando sets segfaulted (
ordinary_set_with_receiverbit-cast the 8-byte cell asObjectHeader), RegExp sets wrote through garbage field offsets, Error attribute bags read as empty.2. Array descriptor semantics (~70 tests)
define_array_propertystoredundefinedas data and discarded get/set).array_numeric_raw_f64_get/set_inbounds,js_array_get/set_f64_unchecked,js_array_set_f64_extend), gated by a new per-arrayOBJ_FLAG_ARRAY_DESCRIPTORSheader bit (set on firstdefinePropertyagainst the array) so ordinary arrays pay one header-flag test, not a side-table probe.defineProperty(arr, "length", {writable:false})now honored bygetOwnPropertyDescriptor,arr.length =writes, and extending index stores.writabletofalse(spec: retained-attrs rule doesn't cross the kind switch — both the array and ordinary-object paths); data→accessor keeps the existing dense element's enumerability.[[DefineOwnProperty]]stores clear stale attrs first (so the new[[Set]]-side writability gate can't reject them) and materialize the element before installing the accessor (so the internal write doesn't fire the brand-new setter).3. Object statics reified (~35 tests)
install_builtin_constructor_staticswas missingseal/isSealed/isFrozen/isExtensible/preventExtensions/is/setPrototypeOf/getOwnPropertySymbols/getOwnPropertyDescriptors/defineProperties/groupBy(andObject.createhadlength1 with no Properties-arg support). Reading e.g.Object.sealas a value produced a raw function-pointer number —typeofsaid"number",.length/.name/hasOwnPropertyall failed. Codegen value reads now route through the reified closures for names unique toObject; the Reflect-overlapping names (defineProperty,getOwnPropertyDescriptor,get/setPrototypeOf,isExtensible,preventExtensions) and Map-overlappinggroupBykeep their old behavior because the HIR collapses the receiver to aGlobalGet(0)sentinel (documented; ~8 tests deferred).4. freeze/seal/TestIntegrityLevel on non-
ObjectHeaderreceiversmark_all_keysbit-cast TypedArray / closure / exotic receivers asObjectHeaderand walked a garbagekeys_array. TheObject.seal(new Int8Array())crash was latent on main — this PR's extra closure installs shifted the heap layout and surfaced it. TypedArrays now use the GC flag bits only; closures and exotics freeze/seal via side-table attrs;object_integrity_levelgot matching arms.5. Smaller fixes
FROZEN/NO_EXTEND/ per-symbol writability (silent rejection, matching the sloppy-mode oracle).Object.getPrototypeOf(primitive)returns the wrapper prototype (Number.prototypeetc.); INT32-tagged class refs are explicitly excluded from the number arm.Object.keys/getOwnPropertyNamesinclude accessor-only properties.js_put_value_setrelocated toproxy/put_value.rs(proxy.rssat at 1999 lines, over the 2000-line gate with any addition).Validation
--shard 0/12overbuilt-ins languagevs a clean main (8ff2c81) build: main 279 fails → branch 261 fails; 18 fixed, 0 regressed (bonus fixes in RegExp/Array/Temporal/literals).RUST_TEST_THREADS=1 cargo test --release -p perry-runtime: green (the two raw-f64 layout tests initially tripped the process-global descriptor gate — that's what motivated the per-arrayOBJ_FLAG_ARRAY_DESCRIPTORSbit).cargo fmt --all+scripts/check_file_size.shgreen.Deferred (documented for the next pass)
arguments-object
definePropertytail;Array.prototype-as-target index defines;entries/valuesobservable-operations ordering;Object.assignOwnPropertyKeys ordering + proxy source traps; gOPD of global builtins (eval/parseInt); Reflect-overlap static value reads; bound-function writes through inheritedFunction.prototypeaccessors.Per CONTRIBUTING guidance for external PRs, no version bump / changelog edits — maintainer folds those in at merge.