compiler/
kernel/
lib/
examples/
std/
arch/
char/
collections/
lang/
alloc/
ast/
gen/
il/
binary/
collect.rad
7.2 KiB
decodeTests.rad
14.9 KiB
program.rad
10.8 KiB
reader.rad
14.0 KiB
tests.rad
13.4 KiB
writer.rad
12.7 KiB
binary.rad
5.9 KiB
printer.rad
15.4 KiB
module/
parser/
resolver/
scanner/
alloc.rad
5.3 KiB
ast.rad
23.6 KiB
gen.rad
513 B
il.rad
17.0 KiB
lower.rad
278.5 KiB
module.rad
13.5 KiB
package.rad
1.3 KiB
parser.rad
79.6 KiB
resolver.rad
329.1 KiB
scanner.rad
17.6 KiB
sexpr.rad
6.4 KiB
strings.rad
2.2 KiB
types.rad
286 B
sys/
arch.rad
68 B
char.rad
855 B
collections.rad
39 B
fmt.rad
8.3 KiB
intrinsics.rad
467 B
io.rad
1.7 KiB
lang.rad
276 B
mem.rad
2.3 KiB
sys.rad
179 B
testing.rad
2.4 KiB
tests.rad
15.7 KiB
vec.rad
3.2 KiB
std.rad
281 B
scripts/
seed/
sublime/
test/
vim/
.gitignore
336 B
.gitsigners
112 B
CONTRIBUTING
2.1 KiB
LICENSE
1.1 KiB
Makefile
10.2 KiB
README
2.5 KiB
STYLE
2.5 KiB
std.lib
1.5 KiB
std.lib.test
551 B
lib/std/lang/il/binary/program.rad
raw
| 1 | //! Binary package envelopes and IL program reconstruction. |
| 2 | //! Tables occur in this order: symbols, dependencies, exports, data, functions. |
| 3 | //! Block records carry labels, parameters, loop depth, predecessors, instructions. |
| 4 | |
| 5 | use std::lang::il; |
| 6 | use std::lang::il::binary; |
| 7 | use std::lang::il::binary::reader; |
| 8 | use std::lang::il::binary::writer; |
| 9 | use std::lang::alloc; |
| 10 | use std::mem; |
| 11 | |
| 12 | /// Write a counted sequence of typed SSA parameters. |
| 13 | unsafe fn writeParams(out: &mut writer::Writer, params: &[il::Param]) throws (binary::Error) { |
| 14 | try writer::integer(out, params.len as u64, 4); |
| 15 | for param in params { |
| 16 | try writer::integer(out, param.value.n as u64, 4); |
| 17 | try writer::typ(out, param.type); |
| 18 | } |
| 19 | } |
| 20 | |
| 21 | /// Write a package. Return the number of encoded bytes. |
| 22 | /// All package tables and IL storage must remain valid during encoding. |
| 23 | export unsafe fn encode(bytes: &mut [u8], package: &binary::Package) -> u32 throws (binary::Error) { |
| 24 | let mut out = writer::new(bytes, package.symbols); |
| 25 | try writer::integer(&mut out, binary::MAGIC as u64, 4); |
| 26 | try writer::integer(&mut out, binary::VERSION as u64, 4); |
| 27 | try writer::integer(&mut out, package.symbols.len as u64, 4); |
| 28 | for name in package.symbols { |
| 29 | try writer::bytes(&mut out, name); |
| 30 | } |
| 31 | try writer::symbol(&mut out, package.name); |
| 32 | try writer::integer(&mut out, package.dependencies.len as u64, 4); |
| 33 | for name in package.dependencies { |
| 34 | try writer::symbol(&mut out, name); |
| 35 | } |
| 36 | try writer::integer(&mut out, package.exports.len as u64, 4); |
| 37 | for item in package.exports { |
| 38 | try writer::symbol(&mut out, item.name); |
| 39 | match item.kind { |
| 40 | case binary::ExportKind::Function => try writer::integer(&mut out, 0, 1), |
| 41 | case binary::ExportKind::Data => try writer::integer(&mut out, 1, 1), |
| 42 | } |
| 43 | } |
| 44 | if let entry = package.entry { |
| 45 | try writer::integer(&mut out, 1, 1); |
| 46 | try writer::symbol(&mut out, entry); |
| 47 | } else { |
| 48 | try writer::integer(&mut out, 0, 1); |
| 49 | } |
| 50 | try writer::integer(&mut out, package.program.data.len as u64, 4); |
| 51 | for item in package.program.data { |
| 52 | try writer::symbol(&mut out, item.name); |
| 53 | try writer::integer(&mut out, item.size as u64, 4); |
| 54 | try writer::integer(&mut out, item.alignment as u64, 4); |
| 55 | try writer::integer(&mut out, 1 if item.readOnly else 0, 1); |
| 56 | try writer::integer(&mut out, 1 if item.isZeroInit else 0, 1); |
| 57 | try writer::integer(&mut out, item.values.len as u64, 4); |
| 58 | for value in item.values { |
| 59 | try writer::dataValue(&mut out, value); |
| 60 | } |
| 61 | } |
| 62 | try writer::integer(&mut out, package.program.fns.len as u64, 4); |
| 63 | for func in package.program.fns { |
| 64 | try writer::symbol(&mut out, func.name); |
| 65 | try writer::typ(&mut out, func.returnType); |
| 66 | try writer::integer(&mut out, 1 if func.isExtern else 0, 1); |
| 67 | try writeParams(&mut out, func.params); |
| 68 | try writer::integer(&mut out, func.blocks.len as u64, 4); |
| 69 | for block in func.blocks { |
| 70 | try writer::bytes(&mut out, block.label); |
| 71 | try writeParams(&mut out, block.params); |
| 72 | try writer::integer(&mut out, block.loopDepth as u64, 4); |
| 73 | try writer::integer(&mut out, block.preds.len as u64, 4); |
| 74 | for pred in block.preds { |
| 75 | try writer::integer(&mut out, pred as u64, 4); |
| 76 | } |
| 77 | try writer::integer(&mut out, block.instrs.len as u64, 4); |
| 78 | for instr in block.instrs { |
| 79 | try writer::instr(&mut out, instr); |
| 80 | } |
| 81 | } |
| 82 | } |
| 83 | return out.offset; |
| 84 | } |
| 85 | |
| 86 | /// Read typed SSA parameters with checked register indices. |
| 87 | unsafe fn readParams(input: &mut reader::Reader) -> *unsafe [il::Param] throws (binary::Error) { |
| 88 | let n = try reader::count(input, 5); |
| 89 | let params = try reader::storage(input, @sizeOf(il::Param), @alignOf(il::Param), n) |
| 90 | as *mut [il::Param]; |
| 91 | for i in 0..n { |
| 92 | let value = try reader::reg(input); |
| 93 | let t = try reader::typ(input); |
| 94 | set params[i] = il::Param { value, type: t }; |
| 95 | } |
| 96 | return (¶ms[..]) as *unsafe [il::Param]; |
| 97 | } |
| 98 | |
| 99 | /// Read global data and check initializer extents against declared storage. |
| 100 | unsafe fn readData(input: &mut reader::Reader) -> *[il::Data] throws (binary::Error) { |
| 101 | let n = try reader::count(input, 18); |
| 102 | let items = try reader::storage(input, @sizeOf(il::Data), @alignOf(il::Data), n) |
| 103 | as *mut [il::Data]; |
| 104 | for i in 0..n { |
| 105 | let name = try reader::symbol(input); |
| 106 | let size = try reader::integer(input, 4) as u32; |
| 107 | let alignment = try reader::integer(input, 4) as u32; |
| 108 | if alignment == 0 or (alignment & (alignment - 1)) <> 0 { |
| 109 | throw binary::Error::Invalid; |
| 110 | } |
| 111 | let readOnly = try reader::flag(input); |
| 112 | let isZeroInit = try reader::flag(input); |
| 113 | let count = try reader::count(input, 5); |
| 114 | let values = try reader::storage(input, @sizeOf(il::DataValue), @alignOf(il::DataValue), count) |
| 115 | as *mut [il::DataValue]; |
| 116 | let mut extent: u64 = 0; |
| 117 | for j in 0..count { |
| 118 | let value = try reader::dataValue(input); |
| 119 | let mut width: u32 = 0; |
| 120 | match value.item { |
| 121 | case il::DataItem::Val { typ, .. } => { set width = il::typeSize(typ); }, |
| 122 | case il::DataItem::Sym(_), il::DataItem::Fn(_) => { set width = 8; }, |
| 123 | case il::DataItem::Str(text) => { set width = text.len; }, |
| 124 | case il::DataItem::Undef => { set width = 1; }, |
| 125 | } |
| 126 | set extent += width as u64 * value.count as u64; |
| 127 | if extent > size as u64 { |
| 128 | throw binary::Error::Invalid; |
| 129 | } |
| 130 | set values[j] = value; |
| 131 | } |
| 132 | set items[i] = il::Data { name, size, alignment, readOnly, isZeroInit, values }; |
| 133 | } |
| 134 | return items; |
| 135 | } |
| 136 | |
| 137 | /// Read functions with checked block and register indices. |
| 138 | unsafe fn readFunctions(input: &mut reader::Reader, limits: binary::Limits) |
| 139 | -> *unsafe [*unsafe il::Fn] throws (binary::Error) |
| 140 | { |
| 141 | let n = try reader::count(input, 14); |
| 142 | let fns = try reader::storage(input, @sizeOf(*il::Fn), @alignOf(*il::Fn), n) as *mut [*unsafe il::Fn]; |
| 143 | set input.registers = limits.registers; |
| 144 | for i in 0..n { |
| 145 | let name = try reader::symbol(input); |
| 146 | let returnType = try reader::typ(input); |
| 147 | let isExtern = try reader::flag(input); |
| 148 | let params = try readParams(input); |
| 149 | let count = try reader::count(input, 20); |
| 150 | if count > limits.blocks or (isExtern and count <> 0) { |
| 151 | throw binary::Error::Invalid; |
| 152 | } |
| 153 | set input.blocks = count; |
| 154 | let blocks = try reader::storage(input, @sizeOf(il::Block), @alignOf(il::Block), count) |
| 155 | as *mut [il::Block]; |
| 156 | let mut isLeaf = true; |
| 157 | for j in 0..count { |
| 158 | let label = try reader::bytes(input); |
| 159 | let blockParams = try readParams(input); |
| 160 | let loopDepth = try reader::integer(input, 4) as u32; |
| 161 | let predCount = try reader::count(input, 4); |
| 162 | let preds = try reader::storage(input, @sizeOf(u32), @alignOf(u32), predCount) as *mut [u32]; |
| 163 | for k in 0..predCount { |
| 164 | set preds[k] = try reader::target(input); |
| 165 | } |
| 166 | let instrCount = try reader::count(input, 1); |
| 167 | let instrs = try reader::storage(input, @sizeOf(il::Instr), @alignOf(il::Instr), instrCount) |
| 168 | as *mut [il::Instr]; |
| 169 | for k in 0..instrCount { |
| 170 | let instr = try reader::instr(input); |
| 171 | if il::isCall(instr) { |
| 172 | set isLeaf = false; |
| 173 | } |
| 174 | set instrs[k] = instr; |
| 175 | } |
| 176 | set blocks[j] = il::Block { |
| 177 | label, params: blockParams, instrs: (&mut instrs[..]) as *unsafe mut [il::Instr], locs: &[], preds: (&preds[..]) as *unsafe [u32], loopDepth, |
| 178 | }; |
| 179 | } |
| 180 | let func = try reader::storage(input, @sizeOf(il::Fn), @alignOf(il::Fn), 1) as *mut [il::Fn]; |
| 181 | set func[0] = il::Fn { name, params, returnType, isExtern, isLeaf, blocks: (&blocks[..]) as *unsafe [il::Block] }; |
| 182 | set fns[i] = &func[0]; |
| 183 | } |
| 184 | return (&fns[..]) as *unsafe [*unsafe il::Fn]; |
| 185 | } |
| 186 | |
| 187 | /// Read the package tables. The input must contain exactly one package. |
| 188 | unsafe fn readPackage(input: &mut reader::Reader, limits: binary::Limits) |
| 189 | -> binary::Package throws (binary::Error) |
| 190 | { |
| 191 | let magic = try reader::integer(input, 4) as u32; |
| 192 | let version = try reader::integer(input, 4) as u32; |
| 193 | if magic <> binary::MAGIC or version <> binary::VERSION { |
| 194 | throw binary::Error::Invalid; |
| 195 | } |
| 196 | let symbolCount = try reader::count(input, 4); |
| 197 | let symbols = try reader::storage(input, @sizeOf(*[u8]), @alignOf(*[u8]), symbolCount) |
| 198 | as *mut [*[u8]]; |
| 199 | for i in 0..symbolCount { |
| 200 | let name = try reader::bytes(input); |
| 201 | if name.len == 0 { |
| 202 | throw binary::Error::Invalid; |
| 203 | } |
| 204 | for j in 0..i { |
| 205 | if mem::eq(name, symbols[j]) { |
| 206 | throw binary::Error::Invalid; |
| 207 | } |
| 208 | } |
| 209 | set symbols[i] = name; |
| 210 | } |
| 211 | set input.symbols = (&symbols[..]) as *unsafe [*[u8]]; |
| 212 | let name = try reader::symbol(input); |
| 213 | let depCount = try reader::count(input, 4); |
| 214 | let dependencies = try reader::storage(input, @sizeOf(*[u8]), @alignOf(*[u8]), depCount) |
| 215 | as *mut [*[u8]]; |
| 216 | for i in 0..depCount { |
| 217 | set dependencies[i] = try reader::symbol(input); |
| 218 | } |
| 219 | let exportCount = try reader::count(input, 5); |
| 220 | let exports = try reader::storage(input, @sizeOf(binary::Export), @alignOf(binary::Export), exportCount) |
| 221 | as *mut [binary::Export]; |
| 222 | for i in 0..exportCount { |
| 223 | let symbol = try reader::symbol(input); |
| 224 | let kind = binary::ExportKind::Data if try reader::flag(input) else binary::ExportKind::Function; |
| 225 | set exports[i] = binary::Export { name: symbol, kind }; |
| 226 | } |
| 227 | let mut entry: ?*[u8] = nil; |
| 228 | if try reader::flag(input) { |
| 229 | set entry = try reader::symbol(input); |
| 230 | } |
| 231 | let data = try readData(input); |
| 232 | let fns = try readFunctions(input, limits); |
| 233 | if input.offset <> input.bytes.len { |
| 234 | throw binary::Error::Invalid; |
| 235 | } |
| 236 | return binary::Package { symbols: (&symbols[..]) as *unsafe [*[u8]], name, dependencies: (&dependencies[..]) as *unsafe [*[u8]], exports: (&exports[..]) as *unsafe [binary::Export], entry, program: il::Program { data, fns } }; |
| 237 | } |
| 238 | |
| 239 | /// Decode one package. Restore the arena offset on every failure. |
| 240 | /// The caller must retain the decoded allocations until the last package use. |
| 241 | export unsafe fn decode(bytes: &[u8], arena: &mut alloc::Arena, limits: binary::Limits) |
| 242 | -> binary::Package throws (binary::Error) |
| 243 | { |
| 244 | let saved = alloc::save(arena); |
| 245 | let mut input = reader::new(bytes, arena, &[]); |
| 246 | return try readPackage(&mut input, limits) catch err { |
| 247 | alloc::restore(arena, saved); |
| 248 | throw err; |
| 249 | }; |
| 250 | } |