ReviewOS

zig-utils/zig-js

Arguments: enumerate the ordinary length property only once

#1093
Closed chris opened this 8 days ago ·
8 days ago

Parent: #465. Related: Function.arguments snapshot qualification.

Executed on 5b73904e: both sloppy and strict Reflect.ownKeys(arguments) produce 0,length,length,callee,iterator in tree and required-VM mode. Node and direct system JavaScriptCore both produce 0,length,callee,iterator.

The arguments object uses dense array storage but owns an ordinary length property. Reflection currently emits both the array's synthetic length key and that ordinary property.

Scope: enumerate the ordinary arguments length once, retaining numeric/string/symbol order, deletion and redefinition behavior, proxy invariants, and ordinary array length enumeration. Pin the reference-confirmed behavior across tree/required-VM/native-enabled modes and run exact-parent arguments/Reflect/Object reflection corpus comparisons.

Definition of done:

  • Sloppy/strict key lists match both references without a duplicate length.
  • Deletion/re-addition/order and ordinary-array controls are pinned.
  • Focused Debug/ReleaseSafe/TSan and affected exact-parent corpus outcomes pass.
  • Small conventional fix and evidence pushed to main.

The getter/enumerability probe also confirmed that keys, values, entries, assign and propertyIsEnumerable were hiding an enumerable ordinary length, and fast data reads skipped a replacement length getter. Those paths are fixed in the same change. Related snapshot issue: #1092.

8 days ago

Implemented in 8fcbf4dc, pushed to main over exact parent 5b73904e.

Arguments keep dense indexed storage while their length uses ordinary property semantics. Reflection now emits the named length once, honors deletion/re-addition and enumerable attributes, and uses ordinary data/accessor/prototype lookup for length. The keys/values/entries/assign/propertyIsEnumerable filters distinguish real Arrays from arguments objects. The real Array controls retain their exotic non-enumerable, non-configurable length.

The basic sloppy/strict key lists and accessor-length getter-count witness match Node and direct system JavaScriptCore. Before, both engine modes duplicate length and hide an enumerable accessor length, returning ["0",false,0,"4","0:4",null,0]; now the permanent witness observes ["0,length",true,0,"4,7","0:4,length:7",7,3]. Deletion/re-addition/string/symbol order follows OrdinaryOwnPropertyKeys and Node; JSC differs on that extended mutation-order witness, so no cross-oracle equality is claimed there.

Qualification:

  • The fixture exercises tree, required-VM, and native-enabled contexts, including numeric/string/symbol order, proxy ownKeys invariants, deletion/re-addition, ordinary Arrays, and exact getter counts. Fixture plus import smoke: 2/2 in Debug, ReleaseSafe, and unsuppressed TSan.
  • Exact-parent/current reports match for 475 cases across arguments-object 263, Reflect.ownKeys 13, Object.keys 59, getOwnPropertyNames 45, assign 38, entries 21, values 20, and propertyIsEnumerable 16. Both binaries have zero default-tier failures and zero tree/VM differences. Flips 0 test262 cases.
  • Parent/changed runner SHA-256: 1b5a2f568bee2523fa795c7aae5c22e2bce30f635f84a91a4734bcf8dba74595 / af6238ed45afb8ae6c123ef0e1c7e79d6d16e6070b978e25171b3db122235e84.
  • Production build, frontend 79-case and VM four-case gates, 378-file docs-link audit, GC relocation inventory, and diff checks pass.

The full combined local unit link remains blocked by #933's unchanged memory cap. Hosted integration is pending. Fresh detached Function.arguments snapshots remain open in #1092; this does not close the captured-binding admission work under #467.

Sign in to comment on this issue.