compiler: Process binary global data in checked code
1582c496571b8aae808e22a8e874daeed870c3e40a0f24174368acd4edfd87d0
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); |