compiler: Borrow package name collection tables by region
6d74348fcb847b8fc995536989e6188057bf1a01929d01c77bc02e9683ee71e6
1 parent
44316af2
compiler/radiance.rad
+20 -18
| 95 | 95 | /// Maximum number of indexed names in one binary package. |
|
| 96 | 96 | constant MAX_PACKAGE_SYMBOLS: u32 = 16384; |
|
| 97 | 97 | /// Export workspace reused for each binary package. |
|
| 98 | 98 | unsafe static PACKAGE_EXPORTS: [binary::Export; MAX_PACKAGE_EXPORTS] = undefined; |
|
| 99 | 99 | /// Symbol workspace reused for each binary package. |
|
| 100 | - | unsafe static PACKAGE_SYMBOLS: [*[u8]; MAX_PACKAGE_SYMBOLS] = undefined; |
|
| 100 | + | static PACKAGE_SYMBOLS: [*[u8]; MAX_PACKAGE_SYMBOLS] = [""; MAX_PACKAGE_SYMBOLS]; |
|
| 101 | 101 | ||
| 102 | 102 | /// Debug info file extension. |
|
| 103 | 103 | constant DEBUG_EXT: *[u8] = ".debug"; |
|
| 104 | 104 | ||
| 105 | 105 | /// Maximum rodata size (4MB). |
| 1271 | 1271 | functions.append(func, allocator); |
|
| 1272 | 1272 | } |
|
| 1273 | 1273 | } |
|
| 1274 | 1274 | let local = il::Program { data: &dataItems[..], fns: functions }; |
|
| 1275 | 1275 | let selected = try packageExports(ctx, pkg, &local, &mut PACKAGE_EXPORTS[..], &mut *res.arena); |
|
| 1276 | - | let mut dependencies: [*[u8]; MAX_PACKAGES] = undefined; |
|
| 1277 | - | let mut names = collect::new(&mut PACKAGE_SYMBOLS[..], &mut dependencies[..]); |
|
| 1278 | - | let image = try collect::package(&mut names, pkg.name, local, &PACKAGE_EXPORTS[..selected.count], selected.entry) catch { |
|
| 1279 | - | throw error(&["cannot collect binary RIL package", pkg.name]); |
|
| 1280 | - | }; |
|
| 1281 | - | let length = try program::encode(&mut FN_ARENA[..], &image) catch { |
|
| 1282 | - | throw error(&["binary RIL output capacity exceeded", pkg.name]); |
|
| 1283 | - | }; |
|
| 1284 | - | let mut path: [u8; MAX_PATH_LEN] = undefined; |
|
| 1285 | - | let mut pos: u32 = 0; |
|
| 1286 | - | for part in &[directory, "/", pkg.name, ".ril"] { |
|
| 1287 | - | set pos += try mem::copy(&mut path[pos..MAX_PATH_LEN - 1], part) catch { |
|
| 1288 | - | throw error(&["binary RIL output path is too long"]); |
|
| 1276 | + | let mut dependencies: [*[u8]; MAX_PACKAGES] = [""; MAX_PACKAGES]; |
|
| 1277 | + | let symbolTable: 'names = &mut PACKAGE_SYMBOLS[..], dependencyTable = &mut dependencies[..] in { |
|
| 1278 | + | let mut names = collect::new(symbolTable, dependencyTable); |
|
| 1279 | + | let image = try collect::package(&mut names, pkg.name, local, &PACKAGE_EXPORTS[..selected.count], selected.entry) catch { |
|
| 1280 | + | throw error(&["cannot collect binary RIL package", pkg.name]); |
|
| 1289 | 1281 | }; |
|
| 1290 | - | } |
|
| 1291 | - | set path[pos] = 0; |
|
| 1292 | - | if not unix::writeFile(&path[..pos], &FN_ARENA[..length]) { |
|
| 1293 | - | throw error(&["cannot write binary RIL package", pkg.name]); |
|
| 1282 | + | let length = try program::encode(&mut FN_ARENA[..], &image) catch { |
|
| 1283 | + | throw error(&["binary RIL output capacity exceeded", pkg.name]); |
|
| 1284 | + | }; |
|
| 1285 | + | let mut path: [u8; MAX_PATH_LEN] = undefined; |
|
| 1286 | + | let mut pos: u32 = 0; |
|
| 1287 | + | for part in &[directory, "/", pkg.name, ".ril"] { |
|
| 1288 | + | set pos += try mem::copy(&mut path[pos..MAX_PATH_LEN - 1], part) catch { |
|
| 1289 | + | throw error(&["binary RIL output path is too long"]); |
|
| 1290 | + | }; |
|
| 1291 | + | } |
|
| 1292 | + | set path[pos] = 0; |
|
| 1293 | + | if not unix::writeFile(&path[..pos], &FN_ARENA[..length]) { |
|
| 1294 | + | throw error(&["cannot write binary RIL package", pkg.name]); |
|
| 1295 | + | } |
|
| 1294 | 1296 | } |
|
| 1295 | 1297 | } |
|
| 1296 | 1298 | } |
|
| 1297 | 1299 | ||
| 1298 | 1300 | /// Match a qualified definition to its package name. |
lib/std/lang/il/binary/collect.rad
+15 -15
| 3 | 3 | use std::mem; |
|
| 4 | 4 | use std::lang::il; |
|
| 5 | 5 | use std::lang::il::binary; |
|
| 6 | 6 | ||
| 7 | 7 | /// Caller-owned storage for a package's indexed names. |
|
| 8 | - | /// Both tables must outlive the collector and all packages that use them. |
|
| 9 | - | export record Names: Copy { |
|
| 8 | + | /// Both tables are exclusively borrowed for the collector's region. |
|
| 9 | + | export record Names: 'tables { |
|
| 10 | 10 | /// Unique names in first-use order. |
|
| 11 | - | symbols: *unsafe mut [*[u8]], |
|
| 11 | + | symbols: &'tables mut [*[u8]], |
|
| 12 | 12 | /// Number of initialized symbol entries. |
|
| 13 | 13 | symbolCount: u32, |
|
| 14 | 14 | /// Unique dependency names in first-use order. |
|
| 15 | - | dependencies: *unsafe mut [*[u8]], |
|
| 15 | + | dependencies: &'tables mut [*[u8]], |
|
| 16 | 16 | /// Number of initialized dependency entries. |
|
| 17 | 17 | dependencyCount: u32, |
|
| 18 | 18 | } |
|
| 19 | 19 | ||
| 20 | 20 | /// Start collection with empty caller-provided tables. |
|
| 21 | - | /// The caller must retain exclusive access to both tables during collection. |
|
| 22 | - | export unsafe fn new(symbols: &mut [*[u8]], dependencies: &mut [*[u8]]) -> Names { |
|
| 23 | - | return Names { symbols: symbols as *unsafe mut [*[u8]], symbolCount: 0, dependencies: dependencies as *unsafe mut [*[u8]], dependencyCount: 0 }; |
|
| 21 | + | /// Retain both tables for the same region. |
|
| 22 | + | export fn new 'tables (symbols: &'tables mut [*[u8]], dependencies: &'tables mut [*[u8]]) -> Names 'tables { |
|
| 23 | + | return Names 'tables { symbols, symbolCount: 0, dependencies, dependencyCount: 0 }; |
|
| 24 | 24 | } |
|
| 25 | 25 | ||
| 26 | 26 | /// Add a unique name and check the symbol table's capacity. |
|
| 27 | - | unsafe fn add(names: &mut Names, name: *[u8]) throws (binary::Error) { |
|
| 27 | + | fn add 'tables (names: &mut Names 'tables, name: *[u8]) throws (binary::Error) { |
|
| 28 | 28 | if name.len == 0 { |
|
| 29 | 29 | throw binary::Error::Invalid; |
|
| 30 | 30 | } |
|
| 31 | 31 | for i in 0..names.symbolCount { |
|
| 32 | 32 | if mem::eq(names.symbols[i], name) { |
| 39 | 39 | set names.symbols[names.symbolCount] = name; |
|
| 40 | 40 | set names.symbolCount += 1; |
|
| 41 | 41 | } |
|
| 42 | 42 | ||
| 43 | 43 | /// Add a qualified reference and its owning package dependency. |
|
| 44 | - | unsafe fn reference(names: &mut Names, owner: *[u8], name: *[u8]) throws (binary::Error) { |
|
| 44 | + | fn reference 'tables (names: &mut Names 'tables, owner: *[u8], name: *[u8]) throws (binary::Error) { |
|
| 45 | 45 | try add(names, name); |
|
| 46 | 46 | for i in 0..name.len { |
|
| 47 | 47 | if name[i] == ':' and i + 1 < name.len and name[i + 1] == ':' { |
|
| 48 | 48 | if i == 0 or i + 2 == name.len { |
|
| 49 | 49 | throw binary::Error::Invalid; |
| 68 | 68 | } |
|
| 69 | 69 | throw binary::Error::Invalid; |
|
| 70 | 70 | } |
|
| 71 | 71 | ||
| 72 | 72 | /// Collect names referenced by one IL value. |
|
| 73 | - | unsafe fn value(names: &mut Names, owner: *[u8], item: il::Val) throws (binary::Error) { |
|
| 73 | + | fn value 'tables (names: &mut Names 'tables, owner: *[u8], item: il::Val) throws (binary::Error) { |
|
| 74 | 74 | match item { |
|
| 75 | 75 | case il::Val::DataSym(name) => try reference(names, owner, name), |
|
| 76 | 76 | case il::Val::FnAddr(name) => try reference(names, owner, name), |
|
| 77 | 77 | else => { |
|
| 78 | 78 | }, |
|
| 79 | 79 | } |
|
| 80 | 80 | } |
|
| 81 | 81 | ||
| 82 | 82 | /// Collect names from an instruction's variable-length operand sequence. |
|
| 83 | - | unsafe fn values(names: &mut Names, owner: *[u8], items: &[il::Val]) throws (binary::Error) { |
|
| 83 | + | fn values 'tables (names: &mut Names 'tables, owner: *[u8], items: &[il::Val]) throws (binary::Error) { |
|
| 84 | 84 | for item in items { |
|
| 85 | 85 | try value(names, owner, item); |
|
| 86 | 86 | } |
|
| 87 | 87 | } |
|
| 88 | 88 | ||
| 89 | 89 | /// Collect all symbolic instruction operands. |
|
| 90 | - | unsafe fn instruction(names: &mut Names, owner: *[u8], instr: il::Instr) throws (binary::Error) { |
|
| 90 | + | unsafe fn instruction 'tables (names: &mut Names 'tables, owner: *[u8], instr: il::Instr) throws (binary::Error) { |
|
| 91 | 91 | match instr { |
|
| 92 | 92 | case il::Instr::Reserve { size, .. } => try value(names, owner, size), |
|
| 93 | 93 | case il::Instr::Blit { size, .. } => try value(names, owner, size), |
|
| 94 | 94 | case il::Instr::Store { src, .. } => try value(names, owner, src), |
|
| 95 | 95 | case il::Instr::Copy { val, .. } => try value(names, owner, val), |
| 141 | 141 | }, |
|
| 142 | 142 | } |
|
| 143 | 143 | } |
|
| 144 | 144 | ||
| 145 | 145 | /// Check that a definition belongs to the selected package. |
|
| 146 | - | unsafe fn definition(names: &mut Names, owner: *[u8], name: *[u8]) throws (binary::Error) { |
|
| 146 | + | fn definition 'tables (names: &mut Names 'tables, owner: *[u8], name: *[u8]) throws (binary::Error) { |
|
| 147 | 147 | let rest = mem::stripPrefix(owner, name) else { |
|
| 148 | 148 | throw binary::Error::Invalid; |
|
| 149 | 149 | }; |
|
| 150 | 150 | if rest.len < 3 or rest[0] <> ':' or rest[1] <> ':' { |
|
| 151 | 151 | throw binary::Error::Invalid; |
| 153 | 153 | try add(names, name); |
|
| 154 | 154 | } |
|
| 155 | 155 | ||
| 156 | 156 | /// Build package tables from local definitions and their qualified references. |
|
| 157 | 157 | /// Returned tables borrow `names`. Reset the collector before building another package. |
|
| 158 | - | export unsafe fn package( |
|
| 159 | - | names: &mut Names, |
|
| 158 | + | export unsafe fn package 'tables ( |
|
| 159 | + | names: &mut Names 'tables, |
|
| 160 | 160 | owner: *[u8], |
|
| 161 | 161 | program: il::Program, |
|
| 162 | 162 | exports: &[binary::Export], |
|
| 163 | 163 | entry: ?*[u8] |
|
| 164 | 164 | ) -> binary::Package throws (binary::Error) { |
lib/std/lang/il/binary/decodeTests.rad
+38 -30
| 305 | 305 | } |
|
| 306 | 306 | } |
|
| 307 | 307 | ||
| 308 | 308 | /// Check symbol collection capacity and package ownership failures. |
|
| 309 | 309 | @test unsafe fn collectionBounds() throws (testing::TestError) { |
|
| 310 | - | let mut symbols: [*[u8]; 8] = undefined; |
|
| 311 | - | let mut dependencies: [*[u8]; 1] = undefined; |
|
| 310 | + | let mut symbols: [*[u8]; 8] = [""; 8]; |
|
| 311 | + | let mut dependencies: [*[u8]; 1] = [""; 1]; |
|
| 312 | 312 | let empty = il::Program { data: &[], fns: &[] }; |
|
| 313 | - | let mut names = collect::new(&mut symbols[..0], &mut dependencies[..]); |
|
| 314 | - | let mut failed = false; |
|
| 315 | - | try collect::package(&mut names, "p", empty, &[], nil) catch err { |
|
| 316 | - | try testing::expect(err == binary::Error::Capacity); |
|
| 317 | - | set failed = true; |
|
| 318 | - | }; |
|
| 319 | - | try testing::expect(failed); |
|
| 313 | + | let symbolTable: 'empty = &mut symbols[..0], dependencyTable = &mut dependencies[..] in { |
|
| 314 | + | let mut names = collect::new(symbolTable, dependencyTable); |
|
| 315 | + | let mut failed = false; |
|
| 316 | + | try collect::package(&mut names, "p", empty, &[], nil) catch err { |
|
| 317 | + | try testing::expect(err == binary::Error::Capacity); |
|
| 318 | + | set failed = true; |
|
| 319 | + | }; |
|
| 320 | + | try testing::expect(failed); |
|
| 321 | + | } |
|
| 320 | 322 | let item = il::Data { |
|
| 321 | 323 | name: "p::data", size: 8, alignment: 8, readOnly: false, isZeroInit: false, |
|
| 322 | 324 | values: &[il::DataValue { item: il::DataItem::Fn("dep::fn"), count: 1 }], |
|
| 323 | 325 | }; |
|
| 324 | 326 | let local = il::Program { data: retainData(&[item]), fns: &[] }; |
|
| 325 | - | set names = collect::new(&mut symbols[..], &mut dependencies[..0]); |
|
| 326 | - | set failed = false; |
|
| 327 | - | try collect::package(&mut names, "p", local, &[], nil) catch err { |
|
| 328 | - | try testing::expect(err == binary::Error::Capacity); |
|
| 329 | - | set failed = true; |
|
| 330 | - | }; |
|
| 331 | - | try testing::expect(failed); |
|
| 332 | - | set names = collect::new(&mut symbols[..], &mut dependencies[..]); |
|
| 333 | - | set failed = false; |
|
| 334 | - | try collect::package(&mut names, "other", local, &[], nil) catch err { |
|
| 335 | - | try testing::expect(err == binary::Error::Invalid); |
|
| 336 | - | set failed = true; |
|
| 337 | - | }; |
|
| 338 | - | try testing::expect(failed); |
|
| 339 | - | set names = collect::new(&mut symbols[..], &mut dependencies[..]); |
|
| 340 | - | let package = try collect::package(&mut names, "p", local, &[], nil) catch { |
|
| 341 | - | throw testing::TestError::Failed; |
|
| 342 | - | }; |
|
| 343 | - | try testing::expect(package.dependencies.len == 1); |
|
| 344 | - | try testing::expectBytesEq(package.dependencies[0], "dep"); |
|
| 345 | - | try testing::expect(package.symbols.len == 4); |
|
| 327 | + | let symbolTable: 'capacity = &mut symbols[..], dependencyTable = &mut dependencies[..0] in { |
|
| 328 | + | let mut names = collect::new(symbolTable, dependencyTable); |
|
| 329 | + | let mut failed = false; |
|
| 330 | + | try collect::package(&mut names, "p", local, &[], nil) catch err { |
|
| 331 | + | try testing::expect(err == binary::Error::Capacity); |
|
| 332 | + | set failed = true; |
|
| 333 | + | }; |
|
| 334 | + | try testing::expect(failed); |
|
| 335 | + | } |
|
| 336 | + | let symbolTable: 'owner = &mut symbols[..], dependencyTable = &mut dependencies[..] in { |
|
| 337 | + | let mut names = collect::new(symbolTable, dependencyTable); |
|
| 338 | + | let mut failed = false; |
|
| 339 | + | try collect::package(&mut names, "other", local, &[], nil) catch err { |
|
| 340 | + | try testing::expect(err == binary::Error::Invalid); |
|
| 341 | + | set failed = true; |
|
| 342 | + | }; |
|
| 343 | + | try testing::expect(failed); |
|
| 344 | + | } |
|
| 345 | + | let symbolTable: 'valid = &mut symbols[..], dependencyTable = &mut dependencies[..] in { |
|
| 346 | + | let mut names = collect::new(symbolTable, dependencyTable); |
|
| 347 | + | let package = try collect::package(&mut names, "p", local, &[], nil) catch { |
|
| 348 | + | throw testing::TestError::Failed; |
|
| 349 | + | }; |
|
| 350 | + | try testing::expect(package.dependencies.len == 1); |
|
| 351 | + | try testing::expectBytesEq(package.dependencies[0], "dep"); |
|
| 352 | + | try testing::expect(package.symbols.len == 4); |
|
| 353 | + | } |
|
| 346 | 354 | } |
|
| 347 | 355 | ||
| 348 | 356 | /// Copy data fixtures into stable storage for the package descriptor. |
|
| 349 | 357 | unsafe fn retainData(items: &[il::Data]) -> *[il::Data] { |
|
| 350 | 358 | unsafe static DATA: [il::Data; 2] = undefined; |