also looking at this
fix(compat): stop describing ArrayList's layout, and read it instead
#876
5 files
+88
-42
| @@ -3576,12 +3576,47 @@ fn emitDirectNamedPropertyWrite( | ||
| 3576 | 3576 | return direct; |
| 3577 | 3577 | } |
| 3578 | 3578 | |
| 3579 | /// The three words the JIT reads out of an `ObjectElementsState.list`, named | |
| 3580 | /// for the loads that use them. | |
| 3581 | /// | |
| 3582 | /// A description of the prefix, not a mirror of the type. | |
| 3583 | /// | |
| 3584 | /// This used to be asserted `@sizeOf`-equal to `std.ArrayListUnmanaged(Value)`, | |
| 3585 | /// which stopped being true when 0.17.0-dev.1963 appended `pointer_stability`. | |
| 3586 | /// Measured, `@sizeOf(ArrayListUnmanaged(u64))`: | |
| 3587 | /// | |
| 3588 | /// toolchain Debug ReleaseSafe ReleaseFast | |
| 3589 | /// dev.1818 24 24 24 | |
| 3590 | /// dev.1963 32 32 24 | |
| 3591 | /// | |
| 3592 | /// So the equality held everywhere on 1818, and on 1963 it fails in two build | |
| 3593 | /// modes and passes in the third — a compile error that depends on `-O`. The | |
| 3594 | /// JIT never read that tail: `@offsetOf(items)` is 0 and `@offsetOf(capacity)` | |
| 3595 | /// is 16 in all six combinations above. Only the assertion was wrong. | |
| 3596 | /// | |
| 3597 | /// The offsets the loads use come from the real type now | |
| 3598 | /// (`denseListWordOffset`); this struct only bounds them. | |
| 3579 | 3599 | const DenseListLayout = extern struct { |
| 3580 | 3600 | items: [*]Value, |
| 3581 | 3601 | len: usize, |
| 3582 | 3602 | capacity: usize, |
| 3583 | 3603 | }; |
| 3584 | 3604 | |
| 3605 | const DenseList = std.ArrayListUnmanaged(Value); | |
| 3606 | ||
| 3607 | /// Byte offset of one of the words above, inside the real list type. | |
| 3608 | /// | |
| 3609 | /// `@offsetOf` on `DenseList`, not on `DenseListLayout`: a std that reorders | |
| 3610 | /// or extends the struct moves the loads with it instead of silently reading | |
| 3611 | /// the wrong word. `len` is the second word of the `items` slice — pointer, | |
| 3612 | /// then length — which is the one layout fact here the language does fix. | |
| 3613 | fn denseListWordOffset(comptime field: []const u8) usize { | |
| 3614 | if (comptime std.mem.eql(u8, field, "items")) return @offsetOf(DenseList, "items"); | |
| 3615 | if (comptime std.mem.eql(u8, field, "len")) return @offsetOf(DenseList, "items") + @sizeOf([*]Value); | |
| 3616 | if (comptime std.mem.eql(u8, field, "capacity")) return @offsetOf(DenseList, "capacity"); | |
| 3617 | @compileError("not a word the JIT reads: " ++ field); | |
| 3618 | } | |
| 3619 | ||
| 3585 | 3620 | fn objectStorageByteOffset(comptime field: []const u8) !u15 { |
| 3586 | 3621 | return std.math.cast(u15, @offsetOf(ObjectStorageState, field)) orelse error.UnsupportedChunk; |
| 3587 | 3622 | } |
| @@ -3589,7 +3624,7 @@ fn objectStorageByteOffset(comptime field: []const u8) !u15 { | ||
| 3589 | 3624 | fn objectElementsByteOffset(comptime field: []const u8) !u15 { |
| 3590 | 3625 | return std.math.cast( |
| 3591 | 3626 | u15, |
| 3592 | @offsetOf(ObjectElementsState, "list") + @offsetOf(DenseListLayout, field), | |
| 3627 | @offsetOf(ObjectElementsState, "list") + denseListWordOffset(field), | |
| 3593 | 3628 | ) orelse error.UnsupportedChunk; |
| 3594 | 3629 | } |
| 3595 | 3630 | |
| @@ -3601,8 +3636,11 @@ fn emitDirectDenseArrayGuards( | ||
| 3601 | 3636 | comptime has_index: bool, |
| 3602 | 3637 | ) !void { |
| 3603 | 3638 | comptime { |
| 3604 | std.debug.assert(@sizeOf(DenseListLayout) == @sizeOf(std.ArrayListUnmanaged(Value))); | |
| 3605 | std.debug.assert(@alignOf(DenseListLayout) == @alignOf(std.ArrayListUnmanaged(Value))); | |
| 3639 | // The prefix the JIT reads, not the whole type — see `DenseListLayout`. | |
| 3640 | std.debug.assert(@sizeOf([]Value) == 2 * @sizeOf(usize)); // pointer, then length | |
| 3641 | std.debug.assert(@sizeOf(DenseListLayout) <= @sizeOf(DenseList)); | |
| 3642 | std.debug.assert(@alignOf(DenseListLayout) <= @alignOf(DenseList)); | |
| 3643 | std.debug.assert(denseListWordOffset("capacity") + @sizeOf(usize) <= @sizeOf(DenseList)); | |
| 3606 | 3644 | } |
| 3607 | 3645 | |
| 3608 | 3646 | // Shared-realm mutation requires the element lock. The same global gate |