Summary
A DataView and a raw ArrayBuffer are byte-indexable in Perry. Node's are
not — they have no integer-indexed own properties at all. Separately,
Object.keys on a real Buffer returns [] where Node lists the byte
indices.
Found while settling #8116's reachability question with a
receiver-representation probe. It is not #8116: all three reproduce with
no typed-array static hint anywhere in the program, so the defect is one
receiver-kind question further out — in js_dyn_index_get's
registered-buffer arm, not in the typed-array element helpers.
Reproduction
const ab = new ArrayBuffer(8);
const D = new DataView(ab);
console.log((D as any)[0]); // perry 0 node undefined
console.log((D as any)[3]); // perry 0 node undefined
console.log((D as any).length); // perry 8 node undefined
console.log(0 in (D as any)); // perry true node false
console.log((ab as any)[0]); // perry 0 node undefined
const b = Buffer.from([1, 2, 3]);
console.log((b as any)[1]); // perry 2 node 2 (correct)
console.log(JSON.stringify(Object.keys(b as any)));
// perry [] node ["0","1","2"]
Object.keys(D) is [] in both, so the in/index divergence is not visible
through enumeration — only through the element read.
Perry 0.5.1510 @ fb87d8923, --profile perry-dev, oracle Node 26.5.1
(the .node-version pin).
Where it comes from
buffer::from::js_data_view_new builds a real BufferHeader, registers it
(buffer::view::register) and calls mark_as_data_view. So
is_registered_buffer(addr) is true for a DataView, and every consumer that
triages a receiver as "registered buffer ⇒ byte-indexable" serves it:
value::dyn_index — the is_registered_buffer(raw_ptr) arm reads
js_buffer_get;
object::polymorphic_index — same shape;
typed_feedback::js_typed_feedback_array_index_get_fallback_boxed — same
shape.
None of them asks is_data_view, although the flag is recorded at
construction, and the sibling discrimination (is_uint8array_buffer) is
already made right next to it in typedarray_props::typed_array_owner_kind.
A raw ArrayBuffer (buffer::js_array_buffer_new_value) appears to reach the
same arm.
The Object.keys half is the mirror image: the enumeration path does not
synthesize the integer-indexed own properties a Node Buffer (an ordinary
Uint8Array object) exposes.
Suggested shape
This is the same family as #8090 / #8109 / #8111 / #8119 / #8120 / #8124 /
#8141: a receiver-specific fast path claims an operation before the
receiver-kind question is asked. The fix shape those established is to add
the discriminating arm ABOVE the generic one — here, is_data_view (and the
plain-ArrayBuffer case) before the byte-index arm, answering undefined for
an integer index and false for in.
Worth checking in the same pass, since they share the arm: .length,
for…in, Object.getOwnPropertyNames, hasOwnProperty, and the store side
((dv as any)[0] = 1 presumably writes a byte where Node creates an ordinary
expando property).
A regression test must assert VALUES against the Node oracle, and — per
#8116's experience — be run against a build with the fix removed, since a
DataView receiver reaches several of these arms by different routes.
Summary
A
DataViewand a rawArrayBufferare byte-indexable in Perry. Node's arenot — they have no integer-indexed own properties at all. Separately,
Object.keyson a realBufferreturns[]where Node lists the byteindices.
Found while settling #8116's reachability question with a
receiver-representation probe. It is not #8116: all three reproduce with
no typed-array static hint anywhere in the program, so the defect is one
receiver-kind question further out — in
js_dyn_index_get'sregistered-buffer arm, not in the typed-array element helpers.
Reproduction
Object.keys(D)is[]in both, so thein/index divergence is not visiblethrough enumeration — only through the element read.
Perry
0.5.1510@fb87d8923,--profile perry-dev, oracle Node26.5.1(the
.node-versionpin).Where it comes from
buffer::from::js_data_view_newbuilds a realBufferHeader, registers it(
buffer::view::register) and callsmark_as_data_view. Sois_registered_buffer(addr)is true for aDataView, and every consumer thattriages a receiver as "registered buffer ⇒ byte-indexable" serves it:
value::dyn_index— theis_registered_buffer(raw_ptr)arm readsjs_buffer_get;object::polymorphic_index— same shape;typed_feedback::js_typed_feedback_array_index_get_fallback_boxed— sameshape.
None of them asks
is_data_view, although the flag is recorded atconstruction, and the sibling discrimination (
is_uint8array_buffer) isalready made right next to it in
typedarray_props::typed_array_owner_kind.A raw
ArrayBuffer(buffer::js_array_buffer_new_value) appears to reach thesame arm.
The
Object.keyshalf is the mirror image: the enumeration path does notsynthesize the integer-indexed own properties a Node
Buffer(an ordinaryUint8Arrayobject) exposes.Suggested shape
This is the same family as #8090 / #8109 / #8111 / #8119 / #8120 / #8124 /
#8141: a receiver-specific fast path claims an operation before the
receiver-kind question is asked. The fix shape those established is to add
the discriminating arm ABOVE the generic one — here,
is_data_view(and theplain-
ArrayBuffercase) before the byte-index arm, answeringundefinedforan integer index and
falseforin.Worth checking in the same pass, since they share the arm:
.length,for…in,Object.getOwnPropertyNames,hasOwnProperty, and the store side(
(dv as any)[0] = 1presumably writes a byte where Node creates an ordinaryexpando property).
A regression test must assert VALUES against the Node oracle, and — per
#8116's experience — be run against a build with the fix removed, since a
DataViewreceiver reaches several of these arms by different routes.