compiler: Calculate optional aggregate layouts from resolved payloads
e8927bdf1c76a4d6cb14e5a477732a7f956edbf19bf11edfc0b65a35f338f0be
1 parent
9f38500b
lib/std/lang/resolver.rad
+9 -8
| 2021 | 2021 | case Type::Fn(_) => return Layout { size: PTR_SIZE, alignment: PTR_SIZE }, |
|
| 2022 | 2022 | case Type::Cell { .. } => return Layout { |
|
| 2023 | 2023 | size: PTR_SIZE, alignment: PTR_SIZE |
|
| 2024 | 2024 | }, |
|
| 2025 | 2025 | case Type::Array(arr) => return getArrayLayout(getTypeLayout(*arr.item), arr.length), |
|
| 2026 | - | case Type::Optional(inner) => return getOptionalLayout(*inner), |
|
| 2026 | + | case Type::Optional(inner) => { |
|
| 2027 | + | // Nullable types use null pointer optimization -- no tag byte needed. |
|
| 2028 | + | if isNullableType(*inner) { |
|
| 2029 | + | return getTypeLayout(*inner); |
|
| 2030 | + | } |
|
| 2031 | + | return getOptionalAggregateLayout(getTypeLayout(*inner)); |
|
| 2032 | + | } |
|
| 2027 | 2033 | case Type::Nominal(info) => return getNominalLayout(*info), |
|
| 2028 | 2034 | else => { |
|
| 2029 | 2035 | panic "getTypeLayout: the given type cannot be layed out"; |
|
| 2030 | 2036 | } |
|
| 2031 | 2037 | } |
| 2051 | 2057 | size: item.size * length, |
|
| 2052 | 2058 | alignment: item.alignment, |
|
| 2053 | 2059 | }; |
|
| 2054 | 2060 | } |
|
| 2055 | 2061 | ||
| 2056 | - | /// Get the layout of an optional type. |
|
| 2057 | - | export unsafe fn getOptionalLayout(inner: Type) -> Layout { |
|
| 2058 | - | // Nullable types use null pointer optimization -- no tag byte needed. |
|
| 2059 | - | if isNullableType(inner) { |
|
| 2060 | - | return getTypeLayout(inner); |
|
| 2061 | - | } |
|
| 2062 | - | let innerLayout = getTypeLayout(inner); |
|
| 2062 | + | /// Get an optional aggregate layout from its payload layout. |
|
| 2063 | + | export fn getOptionalAggregateLayout(innerLayout: Layout) -> Layout { |
|
| 2063 | 2064 | let valOffset = getOptionalValOffset(innerLayout); |
|
| 2064 | 2065 | let alignment = max(innerLayout.alignment, 1); |
|
| 2065 | 2066 | ||
| 2066 | 2067 | return Layout { |
|
| 2067 | 2068 | size: mem::alignUp(valOffset + innerLayout.size, alignment), |
lib/std/lang/resolver/tests.rad
+12 -0
| 26 | 26 | } |
|
| 27 | 27 | ||
| 28 | 28 | /// Synthetic file path used for resolver tests. |
|
| 29 | 29 | constant MODULE_PATH: *[u8] = "/dev/test.rad"; |
|
| 30 | 30 | ||
| 31 | + | /// Optional aggregate layouts align the tag and payload for safe callers. |
|
| 32 | + | @test fn testOptionalAggregateLayouts() throws (testing::TestError) { |
|
| 33 | + | for alignment in [1 as u32, 2, 4, 8, 16] { |
|
| 34 | + | for length in [0 as u32, 1, 3] { |
|
| 35 | + | let payload = super::Layout { size: length * alignment, alignment }; |
|
| 36 | + | let layout = super::getOptionalAggregateLayout(payload); |
|
| 37 | + | assert layout.size == (length + 1) * alignment; |
|
| 38 | + | assert layout.alignment == alignment; |
|
| 39 | + | } |
|
| 40 | + | } |
|
| 41 | + | } |
|
| 42 | + | ||
| 31 | 43 | /// AST arena storage used by resolver tests. |
|
| 32 | 44 | static AST_ARENA: [u8; 2097152] = [0; 2097152]; |
|
| 33 | 45 | ||
| 34 | 46 | /// Resolver arena storage used by resolver tests. |
|
| 35 | 47 | static ARENA_STORAGE: [u8; 2097152] = [0; 2097152]; |