Files
ladybird/Tests/LibJS/Runtime/builtins/Array/array-spread.js
Andreas Kling 614713ed08 LibJS: Replace IndexedProperties with inline Packed/Holey/Dictionary
Replace the OwnPtr<IndexedPropertyStorage> indirection with inline
indexed element storage directly on Object. This eliminates virtual
dispatch and reduces indirection for indexed property access.

The new system uses three storage kinds tracked by IndexedStorageKind:

- Packed: Dense array, no holes. Elements stored in a malloced Value*
  array with capacity header (same layout as named properties).
- Holey: Dense array with possible holes marked by empty sentinel.
  Same physical layout as Packed.
- Dictionary: Sparse storage using GenericIndexedPropertyStorage,
  type-punned into the m_indexed_elements pointer.

Transitions: None->Packed->Holey->Dictionary (mostly monotonic).
Dictionary mode triggers on non-default attributes or sparse arrays.

Object keeps the same 48-byte size since m_indexed_elements (8 bytes)
replaces IndexedProperties (8 bytes), and the storage kind + array
size fit in existing padding alongside m_flags.

The asm interpreter benefits from one fewer indirection: it now reads
the element pointer and array size directly from Object fields instead
of chasing through OwnPtr -> IndexedPropertyStorage -> Vector.

Removes: IndexedProperties, SimpleIndexedPropertyStorage,
IndexedPropertyStorage, IndexedPropertyIterator.
Keeps: GenericIndexedPropertyStorage (for Dictionary mode).
2026-03-17 22:28:35 -05:00

62 lines
2.0 KiB
JavaScript

describe("errors", () => {
test("cannot spread number in array", () => {
expect(() => {
[...1];
}).toThrowWithMessage(TypeError, "1 is not iterable");
});
test("cannot spread object in array", () => {
expect(() => {
[...{}];
}).toThrowWithMessage(TypeError, "[object Object] is not iterable");
});
});
test("basic functionality", () => {
expect([1, ...[2, 3], 4]).toEqual([1, 2, 3, 4]);
let a = [2, 3];
expect([1, ...a, 4]).toEqual([1, 2, 3, 4]);
let obj = { a: [2, 3] };
expect([1, ...obj.a, 4]).toEqual([1, 2, 3, 4]);
expect([...[], ...[...[1, 2, 3]], 4]).toEqual([1, 2, 3, 4]);
});
test("elisions after spread remain holes", () => {
let array = [...[], ,];
expect(array).toHaveLength(1);
expect(array.hasOwnProperty(0)).toBeFalse();
expect(0 in array).toBeFalse();
expect(array[0]).toBeUndefined();
expect(String(array[0])).toBe("undefined");
array = [1, ...[], ,];
expect(array).toHaveLength(2);
expect(array.hasOwnProperty(0)).toBeTrue();
expect(array.hasOwnProperty(1)).toBeFalse();
expect(1 in array).toBeFalse();
expect(array[1]).toBeUndefined();
});
test("allows assignment expressions", () => {
expect("([ ...a = { hello: 'world' } ])").toEval();
expect("([ ...a += 'hello' ])").toEval();
expect("([ ...a -= 'hello' ])").toEval();
expect("([ ...a **= 'hello' ])").toEval();
expect("([ ...a *= 'hello' ])").toEval();
expect("([ ...a /= 'hello' ])").toEval();
expect("([ ...a %= 'hello' ])").toEval();
expect("([ ...a <<= 'hello' ])").toEval();
expect("([ ...a >>= 'hello' ])").toEval();
expect("([ ...a >>>= 'hello' ])").toEval();
expect("([ ...a &= 'hello' ])").toEval();
expect("([ ...a ^= 'hello' ])").toEval();
expect("([ ...a |= 'hello' ])").toEval();
expect("([ ...a &&= 'hello' ])").toEval();
expect("([ ...a ||= 'hello' ])").toEval();
expect("([ ...a ??= 'hello' ])").toEval();
expect("function* test() { return ([ ...yield a ]); }").toEval();
});