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.9 KiB
reader.rad
14.1 KiB
tests.rad
13.7 KiB
writer.rad
12.7 KiB
binary.rad
5.9 KiB
printer.rad
15.4 KiB
tests.rad
3.8 KiB
module/
parser/
resolver/
scanner/
alloc.rad
7.1 KiB
ast.rad
26.7 KiB
gen.rad
513 B
il.rad
19.5 KiB
lower.rad
308.1 KiB
module.rad
14.9 KiB
package.rad
1.3 KiB
parser.rad
89.5 KiB
resolver.rad
439.6 KiB
scanner.rad
18.0 KiB
sexpr.rad
6.4 KiB
strings.rad
2.2 KiB
types.rad
1.6 KiB
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
9.2 KiB
README
2.5 KiB
STYLE
2.5 KiB
std.lib
1.5 KiB
std.lib.test
662 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, .. } => { |
| 122 | set width = il::typeSize(typ); |
| 123 | }, |
| 124 | case il::DataItem::Sym(_), il::DataItem::Fn(_) => { |
| 125 | set width = 8; |
| 126 | }, |
| 127 | case il::DataItem::Str(text) => { |
| 128 | set width = text.len; |
| 129 | }, |
| 130 | case il::DataItem::Undef => { |
| 131 | set width = 1; |
| 132 | }, |
| 133 | } |
| 134 | set extent += width as u64 * value.count as u64; |
| 135 | if extent > size as u64 { |
| 136 | throw binary::Error::Invalid; |
| 137 | } |
| 138 | set values[j] = value; |
| 139 | } |
| 140 | set items[i] = il::Data { name, size, alignment, readOnly, isZeroInit, values }; |
| 141 | } |
| 142 | return items; |
| 143 | } |
| 144 | |
| 145 | /// Read functions with checked block and register indices. |
| 146 | unsafe fn readFunctions(input: &mut reader::Reader, limits: binary::Limits) |
| 147 | -> *unsafe [*unsafe il::Fn] throws (binary::Error) |
| 148 | { |
| 149 | let n = try reader::count(input, 14); |
| 150 | let fns = try reader::storage(input, @sizeOf(*il::Fn), @alignOf(*il::Fn), n) as *mut [*unsafe il::Fn]; |
| 151 | set input.registers = limits.registers; |
| 152 | for i in 0..n { |
| 153 | let name = try reader::symbol(input); |
| 154 | let returnType = try reader::typ(input); |
| 155 | let isExtern = try reader::flag(input); |
| 156 | let params = try readParams(input); |
| 157 | let count = try reader::count(input, 20); |
| 158 | if count > limits.blocks or (isExtern and count <> 0) { |
| 159 | throw binary::Error::Invalid; |
| 160 | } |
| 161 | set input.blocks = count; |
| 162 | let blocks = try reader::storage(input, @sizeOf(il::Block), @alignOf(il::Block), count) |
| 163 | as *mut [il::Block]; |
| 164 | let mut isLeaf = true; |
| 165 | for j in 0..count { |
| 166 | let label = try reader::bytes(input); |
| 167 | let blockParams = try readParams(input); |
| 168 | let loopDepth = try reader::integer(input, 4) as u32; |
| 169 | let predCount = try reader::count(input, 4); |
| 170 | let preds = try reader::storage(input, @sizeOf(u32), @alignOf(u32), predCount) as *mut [u32]; |
| 171 | for k in 0..predCount { |
| 172 | set preds[k] = try reader::target(input); |
| 173 | } |
| 174 | let instrCount = try reader::count(input, 1); |
| 175 | let instrs = try reader::storage(input, @sizeOf(il::Instr), @alignOf(il::Instr), instrCount) |
| 176 | as *mut [il::Instr]; |
| 177 | for k in 0..instrCount { |
| 178 | let instr = try reader::instr(input); |
| 179 | if il::isCall(instr) { |
| 180 | set isLeaf = false; |
| 181 | } |
| 182 | set instrs[k] = instr; |
| 183 | } |
| 184 | set blocks[j] = il::Block { |
| 185 | label, params: blockParams, instrs: (&mut instrs[..]) as *unsafe mut [il::Instr], locs: &[], preds: (&preds[..]) as *unsafe [u32], loopDepth, |
| 186 | }; |
| 187 | } |
| 188 | let func = try reader::storage(input, @sizeOf(il::Fn), @alignOf(il::Fn), 1) as *mut [il::Fn]; |
| 189 | set func[0] = il::Fn { name, params, returnType, isExtern, isLeaf, blocks: (&blocks[..]) as *unsafe [il::Block] }; |
| 190 | set fns[i] = &func[0]; |
| 191 | } |
| 192 | return (&fns[..]) as *unsafe [*unsafe il::Fn]; |
| 193 | } |
| 194 | |
| 195 | /// Read the package tables. The input must contain exactly one package. |
| 196 | unsafe fn readPackage(input: &mut reader::Reader, limits: binary::Limits) |
| 197 | -> binary::Package throws (binary::Error) |
| 198 | { |
| 199 | let magic = try reader::integer(input, 4) as u32; |
| 200 | let version = try reader::integer(input, 4) as u32; |
| 201 | if magic <> binary::MAGIC or version <> binary::VERSION { |
| 202 | throw binary::Error::Invalid; |
| 203 | } |
| 204 | let symbolCount = try reader::count(input, 4); |
| 205 | let symbols = try reader::storage(input, @sizeOf(*[u8]), @alignOf(*[u8]), symbolCount) |
| 206 | as *mut [*[u8]]; |
| 207 | for i in 0..symbolCount { |
| 208 | let name = try reader::bytes(input); |
| 209 | if name.len == 0 { |
| 210 | throw binary::Error::Invalid; |
| 211 | } |
| 212 | for j in 0..i { |
| 213 | if mem::eq(name, symbols[j]) { |
| 214 | throw binary::Error::Invalid; |
| 215 | } |
| 216 | } |
| 217 | set symbols[i] = name; |
| 218 | } |
| 219 | set input.symbols = (&symbols[..]) as *unsafe [*[u8]]; |
| 220 | let name = try reader::symbol(input); |
| 221 | let depCount = try reader::count(input, 4); |
| 222 | let dependencies = try reader::storage(input, @sizeOf(*[u8]), @alignOf(*[u8]), depCount) |
| 223 | as *mut [*[u8]]; |
| 224 | for i in 0..depCount { |
| 225 | set dependencies[i] = try reader::symbol(input); |
| 226 | } |
| 227 | let exportCount = try reader::count(input, 5); |
| 228 | let exports = try reader::storage(input, @sizeOf(binary::Export), @alignOf(binary::Export), exportCount) |
| 229 | as *mut [binary::Export]; |
| 230 | for i in 0..exportCount { |
| 231 | let symbol = try reader::symbol(input); |
| 232 | let kind = binary::ExportKind::Data if try reader::flag(input) else binary::ExportKind::Function; |
| 233 | set exports[i] = binary::Export { name: symbol, kind }; |
| 234 | } |
| 235 | let mut entry: ?*[u8] = nil; |
| 236 | if try reader::flag(input) { |
| 237 | set entry = try reader::symbol(input); |
| 238 | } |
| 239 | let data = try readData(input); |
| 240 | let fns = try readFunctions(input, limits); |
| 241 | if input.offset <> input.bytes.len { |
| 242 | throw binary::Error::Invalid; |
| 243 | } |
| 244 | 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 } }; |
| 245 | } |
| 246 | |
| 247 | /// Decode one package. Restore the arena offset on every failure. |
| 248 | /// The caller must retain the decoded allocations until the last package use. |
| 249 | export unsafe fn decode(bytes: &[u8], arena: &mut alloc::Arena, limits: binary::Limits) |
| 250 | -> binary::Package throws (binary::Error) |
| 251 | { |
| 252 | let saved = alloc::save(arena); |
| 253 | let mut input = reader::new(bytes, arena, &[]); |
| 254 | return try readPackage(&mut input, limits) catch err { |
| 255 | alloc::restore(arena, saved); |
| 256 | throw err; |
| 257 | }; |
| 258 | } |