lib/std/lang/il/binary/program.rad 10.9 KiB 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 (&params[..]) 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
}