compiler: Process binary global data in checked code

1582c496571b8aae808e22a8e874daeed870c3e40a0f24174368acd4edfd87d0
Alexis Sellier committed ago 1 parent 8a293756
lib/std/lang/il/binary/collect.rad +16 -11
151 151
        throw binary::Error::Invalid;
152 152
    }
153 153
    try add(names, name);
154 154
}
155 155
156 +
/// Collect definitions and symbolic initializers from global data.
157 +
fn collectData 'tables (names: &mut Names 'tables, owner: *[u8], items: &[il::Data]) throws (binary::Error) {
158 +
    for item in items {
159 +
        try definition(names, owner, item.name);
160 +
        for data in item.values {
161 +
            match data.item {
162 +
                case il::DataItem::Sym(name) => try reference(names, owner, name),
163 +
                case il::DataItem::Fn(name) => try reference(names, owner, name),
164 +
                else => {
165 +
                },
166 +
            }
167 +
        }
168 +
    }
169 +
}
170 +
156 171
/// Build package tables from local definitions and their qualified references.
157 172
/// Returned tables borrow `names`. Reset the collector before building another package.
158 173
export unsafe fn package 'tables (
159 174
    names: &mut Names 'tables,
160 175
    owner: *[u8],
167 182
        try definition(names, owner, item.name);
168 183
    }
169 184
    if let name = entry {
170 185
        try definition(names, owner, name);
171 186
    }
172 -
    for item in program.data {
173 -
        try definition(names, owner, item.name);
174 -
        for data in item.values {
175 -
            match data.item {
176 -
                case il::DataItem::Sym(name) => try reference(names, owner, name),
177 -
                case il::DataItem::Fn(name) => try reference(names, owner, name),
178 -
                else => {
179 -
                },
180 -
            }
181 -
        }
182 -
    }
187 +
    try collectData(names, owner, &program.data[..]);
183 188
    for func in program.fns {
184 189
        try definition(names, owner, func.name);
185 190
        for block in func.blocks {
186 191
            for instr in block.instrs {
187 192
                try instruction(names, owner, instr);
lib/std/lang/il/binary/decodeTests.rad +35 -0
360 360
        try testing::expectBytesEq(package.dependencies[0], "dep");
361 361
        try testing::expect(package.symbols.len == 4);
362 362
    }
363 363
}
364 364
365 +
/// Data collection retains first-use order and unique dependencies.
366 +
@test unsafe fn dataCollectionOrder() throws (testing::TestError) {
367 +
    let item = il::Data {
368 +
        name: "p::data", size: 64, alignment: 8, readOnly: true, isZeroInit: false,
369 +
        values: &[
370 +
            il::DataValue { item: il::DataItem::Fn("z::fn"), count: 1 },
371 +
            il::DataValue { item: il::DataItem::Sym("a::data"), count: 1 },
372 +
            il::DataValue { item: il::DataItem::Fn("z::fn"), count: 1 },
373 +
            il::DataValue { item: il::DataItem::Sym("p::data"), count: 1 },
374 +
            il::DataValue { item: il::DataItem::Str("not::a::symbol"), count: 1 },
375 +
            il::DataValue { item: il::DataItem::Val { typ: il::Type::W16, val: 9 }, count: 2 },
376 +
        ],
377 +
    };
378 +
    let zero = il::Data {
379 +
        name: "p::zero", size: 32, alignment: 8, readOnly: false, isZeroInit: true, values: &[],
380 +
    };
381 +
    let local = il::Program { data: retainData(&[item, zero]), fns: &[] };
382 +
    let mut symbols: [*[u8]; 7] = [""; 7];
383 +
    let mut dependencies: [*[u8]; 2] = [""; 2];
384 +
    let symbolTable: 'tables = &mut symbols[..], dependencyTable = &mut dependencies[..] in {
385 +
        let mut names = collect::new(symbolTable, dependencyTable);
386 +
        let package = try collect::package(&mut names, "p", local,
387 +
            &[binary::Export { name: "p::data", kind: binary::ExportKind::Data }], nil
388 +
        ) catch { throw testing::TestError::Failed; };
389 +
        assert package.symbols.len == 7;
390 +
        for expected, index in ["p", "p::data", "z::fn", "z", "a::data", "a", "p::zero"] {
391 +
            try testing::expectBytesEq(package.symbols[index], expected);
392 +
        }
393 +
        assert package.dependencies.len == 2;
394 +
        try testing::expectBytesEq(package.dependencies[0], "z");
395 +
        try testing::expectBytesEq(package.dependencies[1], "a");
396 +
        try roundTrip(&package);
397 +
    }
398 +
}
399 +
365 400
/// Copy data fixtures into stable storage for the package descriptor.
366 401
unsafe fn retainData(items: &[il::Data]) -> *[il::Data] {
367 402
    unsafe static DATA: [il::Data; 2] = undefined;
368 403
    assert items.len <= DATA.len;
369 404
    for item, i in items {
lib/std/lang/il/binary/program.rad +17 -12
16 16
        try writer::integer(out, param.value.n as u64, 4);
17 17
        try writer::typ(out, param.type);
18 18
    }
19 19
}
20 20
21 +
/// Write global data definitions and their initializer sequences.
22 +
fn writeData 'buffer (out: &mut writer::Writer 'buffer, items: &[il::Data]) throws (binary::Error) {
23 +
    try writer::integer(out, items.len as u64, 4);
24 +
    for item in items {
25 +
        try writer::symbol(out, item.name);
26 +
        try writer::integer(out, item.size as u64, 4);
27 +
        try writer::integer(out, item.alignment as u64, 4);
28 +
        try writer::integer(out, 1 if item.readOnly else 0, 1);
29 +
        try writer::integer(out, 1 if item.isZeroInit else 0, 1);
30 +
        try writer::integer(out, item.values.len as u64, 4);
31 +
        for value in item.values {
32 +
            try writer::dataValue(out, value);
33 +
        }
34 +
    }
35 +
}
36 +
21 37
/// Write a package. Return the number of encoded bytes.
22 38
/// All package tables and IL storage must remain valid during encoding.
23 39
export unsafe fn encode(bytes: &mut [u8], package: &binary::Package) -> u32 throws (binary::Error) {
24 40
    let output: 'output = &mut bytes[..], symbols = &package.symbols[..] in {
25 41
        let mut out = writer::new(output, symbols);
46 62
            try writer::integer(&mut out, 1, 1);
47 63
            try writer::symbol(&mut out, entry);
48 64
        } else {
49 65
            try writer::integer(&mut out, 0, 1);
50 66
        }
51 -
        try writer::integer(&mut out, package.program.data.len as u64, 4);
52 -
        for item in package.program.data {
53 -
            try writer::symbol(&mut out, item.name);
54 -
            try writer::integer(&mut out, item.size as u64, 4);
55 -
            try writer::integer(&mut out, item.alignment as u64, 4);
56 -
            try writer::integer(&mut out, 1 if item.readOnly else 0, 1);
57 -
            try writer::integer(&mut out, 1 if item.isZeroInit else 0, 1);
58 -
            try writer::integer(&mut out, item.values.len as u64, 4);
59 -
            for value in item.values {
60 -
                try writer::dataValue(&mut out, value);
61 -
            }
62 -
        }
67 +
        try writeData(&mut out, &package.program.data[..]);
63 68
        try writer::integer(&mut out, package.program.fns.len as u64, 4);
64 69
        for func in package.program.fns {
65 70
            try writer::symbol(&mut out, func.name);
66 71
            try writer::typ(&mut out, func.returnType);
67 72
            try writer::integer(&mut out, 1 if func.isExtern else 0, 1);