…ers (P3 B4b)
No producer of an INT32-tagged Number exists since B4a and codegen stopped
reading one in B3. The runtime, stdlib and extension consumers go: equality
and compare, ToString / ToNumber, JSON, console formatting, key and index
decoding, argument validation. JSValue::is_int32 / as_int32 and
is_int32_bits are deleted; the 0x7FFE tag is INTERNAL_WORD_TAG (runtime
internal words only). The classifiers that read raw slot words keep the I32
slot word of an at-rest Array or I32 field lane (layout_slot).
What
The last phase of the canonical-Number plan (representation RFC §10 P3; after B1, B2, B4a #14372 and B3 #14395).
No code can make an INT32-tagged Number since B4a, and codegen stopped reading one in B3. This PR deletes the
runtime side: every place that still decoded a
0x7FFE_0000_xxxx_xxxxword as a Number.JSValue::is_int32/as_int32,value::is_int32_bitsandINT32_MASKare gone. About 330 consumer arms gowith them in perry-runtime (equality and relational compare, loose equality, ToNumber / ToString / radix,
truthiness, typeof, JSON writers, console and
util.format, key and index decoding for Arrays, typed arrays,Buffers, Maps and Sets, argument validation in fs / net / dgram / tls / zlib / child_process / bun:ffi / sqlite),
perry-stdlib (crypto, webcrypto, sqlite, streams, events, querystring) and the http, net, sharp and
better-sqlite3 extensions.
INTERNAL_WORD_TAGin perry-runtime: the0x7FFEband holds runtime-internal words onlyand never a JS value.
JsValue::is_number,to_numberandto_int32read a plain double only.JsValue::is_int32stays,deprecated and always false, so an out-of-tree extension that calls it keeps compiling.
canonicalize_typed_slot_store_bits(andslot_holds_raw_f64), andjs_closure_call_array's defensiveargument decode with its scratch buffer;
numify_arith_operandandint32_or_class_reprlikewise.One thing the design did not know: I32 at rest
DESIGN-p3 was written before I32 at rest (N1). Since then the
0x7FFEband also holds the I32 slot words of anat-rest Array and of an I32 field lane (
layout_slot.rs); they are decoded by the layout accessor before a valueleaves the slot. So the sweep separates two kinds of reader:
layout_slot::is_i32_word(the samebits the old predicate tested, so nothing changes for it):
array::value_bits_to_number, the check-mode kindtests (
wpfacts_check::kind_of,contracts::kind_of), the GC census, typed feedback's stable kind and thestructured-clone writer.
A generic reader that wpfacts admits never meets an at-rest slot (that is the at-rest admission rule), so no
value-side arm was reachable through one. The language parity corpus and check mode below are the evidence.
Not in this PR
INT32_TAGconstants (the at-rest word and the control cells) keep their names.wasm_runtime.js(not checkable here)._slot_indexparameter of
runtime_store_jsvalue_slot_layout_deferred, and codegen's calls of the now-identityjs_typed_f64_arg_to_raw/js_typed_i32_arg_to_raw. Listed in FOLLOWUPS.Switch, probe
None: a pure deletion with no fact and no lowering change, like B3. The off arm is main dd083f3. The chess facts dump is byte-identical to main's (
facts_shabelow).Chess (qb10,
instructions:u, each arm x2, same session; off = main dd083f3, on = this branch 9f48f8a = main dd083f3 merged in)Second runs: search 11 848.183 / 11 845.511, perft 258.931 / 258.911, evaluate 1 191.814 / 1 190.590, legal
354.793 / 354.774. Binary 9 320 576 -> 9 308 288 B (−12 288). Facts dump identical (
facts_sha69df1bea5e8af5b7 inboth). Chess check mode: all four modes rc 0, 0 misses, in both arms.
Gates run
All on the merged head 9f48f8a (qb10). Earlier runs on the pre-merge heads 75baabc and 5c46e43 (base
b44f944) gave the same picture and are superseded by these.
tests/parity/language/number/test_p3_b4b_one_number_encoding.ts: = node in default, DCE off, check mode,check mode with DCE off.
cargo test -p perry-runtime --lib: 6819 passed, 0 failed.-p perry-ffi --lib: 55 passed.cargo test -p perry-stdlib --lib: 342 passed, 1 failed:sqlite::bind::tests::typed_arrays_are_not_named_parameter_objects. It fails the same way on main (checked onb44f944: the test binary has no typed-array family hooks); not from this PR.
dd083f3; against the newest one (main 12cace2) no program that matched there fails here, and the
number-births branch on the same base gives the identical per-file result.
canonnumruntime built from this branch: 203 executable controls passed(
canonical-number-negative: 0 / 86 / 86 for the array-rep arm).scripts/check_file_size.sh: OK (four allowlist counts re-recorded, all smaller).The merge of main
Main moved by 46 commits in the same files while the gates ran; it is merged in (not rebased). Two conflicts:
typedarray/bigint.rs(main moved the ToBigInt label intobigint_coerce.rs; its INT32 arm is deleted there) andthe
check_file_size.shcounts. The S0 hunk this branch first carried (acceptarray repincanonical-number-negative) is dropped: main fixed that arm itself, and the branch has main's script unchanged.instanceofand internal wordsOn main
x instanceof Canswers false whenxis a0x7FFEword that names no class, through the INT32 arms ofinstanceof_lhs_is_primitiveand of the prototype walk. Deleting those arms made the walk throw for such a word.Both are restored as "an internal word is no object" (unit tests
ordinary_has_instance_walk_is_false_for_primitive_lhs,lhs_primitive_classification_is_tag_only). No fixtureline: a JS program cannot reach the case, since no code makes a
0x7FFEword as a value (B4a) and an I32 slot wordis decoded before it leaves its slot.
Not run
Full suites other than the three lib suites above, parity IR census, node-suite check mode, tssrc, Supabase, skin
size, hello / hello2 startup Ir, the ext crates' ABI tests.