compiler: Build variable metadata in checked storage

447c3f8a45e1a871dee38f2ad4f80eb8dff2aa8963e9374e4d0217b46621ef57
Alexis Sellier committed ago 1 parent 355d20b0
lib/std/lang/lower.rad +5 -6
1011 1011
    set self.currentMod = nil;
1012 1012
    set self.packageDataStart = self.data.len;
1013 1013
}
1014 1014
1015 1015
/// Allocate initialized variable metadata for one function.
1016 -
unsafe fn variableStorage(arena: &mut alloc::Arena, count: u32) -> *mut [VarData] {
1017 -
    let entries = try! alloc::allocSlice(arena, @sizeOf(VarData), @alignOf(VarData), count)
1018 -
        as *mut [VarData];
1016 +
fn variableStorage(count: u32, allocator: alloc::Allocator) -> *mut [VarData] {
1017 +
    let mut entries: *mut [VarData] = &mut [];
1019 1018
    for i in 0..count {
1020 -
        set entries[i] = VarData { name: nil, type: il::Type::W64, mutable: false, addressTaken: false };
1019 +
        entries.append(VarData { name: nil, type: il::Type::W64, mutable: false, addressTaken: false }, allocator);
1021 1020
    }
1022 1021
    return entries;
1023 1022
}
1024 1023
1025 1024
/// Create a new function lowerer for a given function type and name.
1095 1094
1096 1095
    // Register function symbol for cross-package call resolution.
1097 1096
    if let sym = resolver::symbolFor(self.resolver, node) {
1098 1097
        registerSymbolName(&mut self.symbolNames, sym, qualName, alloc::arenaAllocator(self.arena));
1099 1098
    }
1100 -
    let variableSlots = variableStorage(functionArena, data.localCount);
1099 +
    let variableSlots = variableStorage(data.localCount, alloc::arenaAllocator(functionArena));
1101 1100
    let parent: 'function = &mut *self, arena = &mut *functionArena, variables = &mut variableSlots[..] where 'phase: 'function in {
1102 1101
        let mut fnLow = fnLowerer(parent, node.span.offset, fnType, qualName, arena, variables);
1103 1102
1104 1103
        // If the function returns an aggregate or is throwing, prepend a hidden
1105 1104
        // return parameter. The caller allocates the buffer and passes it
1277 1276
        throw LowerError::ExpectedFunction;
1278 1277
    };
1279 1278
    let sym = resolver::symbolFor(self.resolver, node) else throw LowerError::MissingSymbol(node);
1280 1279
    registerSymbolName(&mut self.symbolNames, sym, qualName, alloc::arenaAllocator(self.arena));
1281 1280
1282 -
    let variableSlots = variableStorage(functionArena, data.localCount);
1281 +
    let variableSlots = variableStorage(data.localCount, alloc::arenaAllocator(functionArena));
1283 1282
    let parent: 'function = &mut *self, arena = &mut *functionArena, variables = &mut variableSlots[..] where 'phase: 'function in {
1284 1283
        let mut fnLow = fnLowerer(parent, node.span.offset, fnType, qualName, arena, variables);
1285 1284
        if requiresReturnParam(fnType) {
1286 1285
            set fnLow.returnReg = nextReg(&mut fnLow);
1287 1286
        }
test/tests/variable.slots.scopes.rad +24 -0
44 44
}
45 45
46 46
/// Check repeated invocations and slot initialization in an empty function.
47 47
fn empty() {}
48 48
49 +
/// Keep local metadata live across multiple slice growth boundaries.
50 +
fn wide(seed: u64) -> u64 {
51 +
    let a = seed + 1;
52 +
    let b = seed + 2;
53 +
    let c = seed + 3;
54 +
    let d = seed + 4;
55 +
    let e = seed + 5;
56 +
    let f = seed + 6;
57 +
    let g = seed + 7;
58 +
    let h = seed + 8;
59 +
    let i = seed + 9;
60 +
    let j = seed + 10;
61 +
    let k = seed + 11;
62 +
    let l = seed + 12;
63 +
    let m = seed + 13;
64 +
    let n = seed + 14;
65 +
    let o = seed + 15;
66 +
    let mut p = seed + 16;
67 +
    increment(&mut p);
68 +
    return a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p;
69 +
}
70 +
49 71
/// Verify scoped metadata over several argument values.
50 72
@default fn main() -> u32 {
51 73
    empty();
52 74
    for seed in 0..16 {
53 75
        assert check(seed) == seed * 3 + 7;
76 +
        let value = 0x100000000 + seed as u64;
77 +
        assert wide(value) == value * 16 + 137;
54 78
    }
55 79
    empty();
56 80
    return 0;
57 81
}