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/tests.rad
raw
| 1 | //! Binary RIL encoding fixtures. |
| 2 | |
| 3 | use std::testing; |
| 4 | use std::lang::il; |
| 5 | use std::lang::il::binary::writer; |
| 6 | use std::lang::il::binary; |
| 7 | use std::lang::il::binary::reader; |
| 8 | use std::lang::alloc; |
| 9 | |
| 10 | /// Decode arena backing storage. Tests reset it before each use. |
| 11 | static MEMORY: [u8; 512] = [0; 512]; |
| 12 | |
| 13 | /// Check little-endian encoding for every integer width. |
| 14 | @test unsafe fn integers() throws (testing::TestError) { |
| 15 | let mut buffer: [u8; 15] = [0; 15]; |
| 16 | let mut out = writer::new(&mut buffer[..], &[]); |
| 17 | try writer::integer(&mut out, 0x12, 1) catch { |
| 18 | throw testing::TestError::Failed; |
| 19 | }; |
| 20 | try writer::integer(&mut out, 0x3456, 2) catch { |
| 21 | throw testing::TestError::Failed; |
| 22 | }; |
| 23 | try writer::integer(&mut out, 0x789abcde, 4) catch { |
| 24 | throw testing::TestError::Failed; |
| 25 | }; |
| 26 | try writer::integer(&mut out, 0x0123456789abcdef, 8) catch { |
| 27 | throw testing::TestError::Failed; |
| 28 | }; |
| 29 | try testing::expectBytesEq(&buffer[..], &[0x12, 0x56, 0x34, 0xde, 0xbc, 0x9a, 0x78, 0xef, 0xcd, |
| 30 | 0xab, 0x89, 0x67, 0x45, 0x23, 0x01]); |
| 31 | } |
| 32 | |
| 33 | /// Compare one instruction with its fixed wire representation. |
| 34 | unsafe fn instruction(item: il::Instr, expected: &[u8]) throws (testing::TestError) { |
| 35 | let mut buffer: [u8; 256] = [0; 256]; |
| 36 | let mut out = writer::new(&mut buffer[..], &["data", "fn"]); |
| 37 | try writer::instr(&mut out, item) catch { |
| 38 | throw testing::TestError::Failed; |
| 39 | }; |
| 40 | try testing::expectBytesEq(&buffer[..out.offset], expected); |
| 41 | for capacity in 0..expected.len { |
| 42 | let mut short = writer::new(&mut buffer[..capacity], &["data", "fn"]); |
| 43 | let mut failed = false; |
| 44 | try writer::instr(&mut short, item) catch err { |
| 45 | try testing::expect(err == binary::Error::Capacity); |
| 46 | set failed = true; |
| 47 | }; |
| 48 | try testing::expect(failed); |
| 49 | try testing::expect(short.offset <= capacity); |
| 50 | } |
| 51 | let memory = &mut MEMORY[..512]; |
| 52 | let mut arena = alloc::new(&mut memory[..]); |
| 53 | let mut input = reader::new(expected, &mut arena, &["data", "fn"]); |
| 54 | set input.registers = 16; |
| 55 | set input.blocks = 4; |
| 56 | let decoded = try reader::instr(&mut input) catch { |
| 57 | throw testing::TestError::Failed; |
| 58 | }; |
| 59 | try testing::expect(input.offset == expected.len); |
| 60 | set out.offset = 0; |
| 61 | try writer::instr(&mut out, decoded) catch { |
| 62 | throw testing::TestError::Failed; |
| 63 | }; |
| 64 | try testing::expectBytesEq(&buffer[..out.offset], expected); |
| 65 | for length in 0..expected.len { |
| 66 | alloc::reset(&mut arena); |
| 67 | set input = reader::new(&expected[..length], &mut arena, &["data", "fn"]); |
| 68 | set input.registers = 16; |
| 69 | set input.blocks = 4; |
| 70 | let mut failed = false; |
| 71 | try reader::instr(&mut input) catch err { |
| 72 | try testing::expect(err == binary::Error::Truncated); |
| 73 | set failed = true; |
| 74 | }; |
| 75 | try testing::expect(failed); |
| 76 | } |
| 77 | |
| 78 | } |
| 79 | |
| 80 | /// Check all instruction tags and their field order. |
| 81 | @test unsafe fn instructions() throws (testing::TestError) { |
| 82 | let mut args: [il::Val; 1] = [il::Val::Undef]; |
| 83 | let mut cases: [il::SwitchCase; 1] = [il::SwitchCase { |
| 84 | value: -1, target: 2, args: &mut args[..], |
| 85 | }]; |
| 86 | try instruction(il::Instr::Reserve { |
| 87 | dst: il::Reg { n: 1 }, size: il::Val::Undef, alignment: 16, |
| 88 | }, &[0, 1, 0, 0, 0, 4, 16, 0, 0, 0]); |
| 89 | try instruction(il::Instr::Load { |
| 90 | typ: il::Type::W8, dst: il::Reg { n: 1 }, src: il::Reg { n: 2 }, offset: -1, |
| 91 | }, &[1, 1, 1, 0, 0, 0, 2, 0, 0, 0, 255, 255, 255, 255]); |
| 92 | try instruction(il::Instr::Sload { |
| 93 | typ: il::Type::W16, dst: il::Reg { n: 1 }, src: il::Reg { n: 2 }, offset: 3, |
| 94 | }, &[2, 2, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0]); |
| 95 | try instruction(il::Instr::Store { |
| 96 | typ: il::Type::W32, src: il::Val::Undef, dst: il::Reg { n: 2 }, offset: 3, |
| 97 | }, &[3, 4, 4, 2, 0, 0, 0, 3, 0, 0, 0]); |
| 98 | try instruction(il::Instr::Blit { |
| 99 | dst: il::Reg { n: 1 }, src: il::Reg { n: 2 }, size: il::Val::Undef, |
| 100 | }, &[4, 1, 0, 0, 0, 2, 0, 0, 0, 4]); |
| 101 | try instruction(il::Instr::Copy { |
| 102 | dst: il::Reg { n: 1 }, val: il::Val::Undef, |
| 103 | }, &[5, 1, 0, 0, 0, 4]); |
| 104 | try instruction(il::Instr::BinOp { |
| 105 | op: il::BinOp::Add, typ: il::Type::W64, dst: il::Reg { n: 1 }, a: il::Val::Undef, |
| 106 | b: il::Val::Undef, |
| 107 | }, &[6, 0, 8, 1, 0, 0, 0, 4, 4]); |
| 108 | try instruction(il::Instr::UnOp { |
| 109 | op: il::UnOp::Neg, typ: il::Type::W64, dst: il::Reg { n: 1 }, a: il::Val::Undef, |
| 110 | }, &[7, 0, 8, 1, 0, 0, 0, 4]); |
| 111 | try instruction(il::Instr::Zext { |
| 112 | typ: il::Type::W8, dst: il::Reg { n: 1 }, val: il::Val::Undef, |
| 113 | }, &[8, 1, 1, 0, 0, 0, 4]); |
| 114 | try instruction(il::Instr::Sext { |
| 115 | typ: il::Type::W16, dst: il::Reg { n: 1 }, val: il::Val::Undef, |
| 116 | }, &[9, 2, 1, 0, 0, 0, 4]); |
| 117 | try instruction(il::Instr::Call { |
| 118 | retTy: il::Type::W64, dst: nil, func: il::Val::FnAddr("fn"), args: &[], |
| 119 | }, &[10, 8, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0]); |
| 120 | try instruction(il::Instr::Call { |
| 121 | retTy: il::Type::W64, dst: il::Reg { n: 2 }, func: il::Val::FnAddr("fn"), args: &args[..], |
| 122 | }, &[10, 8, 1, 2, 0, 0, 0, 3, 1, 0, 0, 0, 1, 0, 0, 0, 4]); |
| 123 | try instruction(il::Instr::Ret { |
| 124 | val: nil, |
| 125 | }, &[11, 0]); |
| 126 | try instruction(il::Instr::Ret { |
| 127 | val: il::Val::Undef, |
| 128 | }, &[11, 1, 4]); |
| 129 | try instruction(il::Instr::Jmp { |
| 130 | target: 2, args: &mut args[..], |
| 131 | }, &[12, 2, 0, 0, 0, 1, 0, 0, 0, 4]); |
| 132 | try instruction(il::Instr::Br { |
| 133 | op: il::CmpOp::Eq, typ: il::Type::W32, a: il::Val::Undef, b: il::Val::Undef, thenTarget: 1, |
| 134 | thenArgs: &mut args[..], elseTarget: 2, elseArgs: &mut args[..], |
| 135 | }, &[13, 0, 4, 4, 4, 1, 0, 0, 0, 1, 0, 0, 0, 4, 2, 0, 0, 0, 1, 0, 0, 0, 4]); |
| 136 | try instruction(il::Instr::Switch { |
| 137 | val: il::Val::Undef, defaultTarget: 1, defaultArgs: &mut args[..], cases: &mut cases[..], |
| 138 | }, &[ |
| 139 | 14, 4, 1, 0, 0, 0, 1, 0, 0, 0, 4, 1, |
| 140 | 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 2, |
| 141 | 0, 0, 0, 1, 0, 0, 0, 4, |
| 142 | ]); |
| 143 | try instruction(il::Instr::Unreachable, &[15]); |
| 144 | try instruction(il::Instr::Ecall { |
| 145 | dst: il::Reg { n: 1 }, num: il::Val::Undef, a0: il::Val::Undef, a1: il::Val::Undef, |
| 146 | a2: il::Val::Undef, a3: il::Val::Undef, |
| 147 | }, &[16, 1, 0, 0, 0, 4, 4, 4, 4, 4]); |
| 148 | try instruction(il::Instr::Ebreak, &[17]); |
| 149 | try instruction(il::Instr::MemoryFence, &[18]); |
| 150 | for typ in [il::Type::W8, il::Type::W16, il::Type::W32, il::Type::W64] { |
| 151 | let mut read: [u8; 8] = [19, 0, 1, 0, 0, 0, 4, 4]; |
| 152 | let mut write: [u8; 5] = [20, 0, 4, 4, 4]; |
| 153 | set read[1] = il::typeSize(typ) as u8; |
| 154 | set write[1] = il::typeSize(typ) as u8; |
| 155 | try instruction(il::Instr::DeviceRead { |
| 156 | typ, dst: il::Reg { n: 1 }, handle: il::Val::Undef, offset: il::Val::Undef, |
| 157 | }, &read[..]); |
| 158 | try instruction(il::Instr::DeviceWrite { |
| 159 | typ, handle: il::Val::Undef, offset: il::Val::Undef, value: il::Val::Undef, |
| 160 | }, &write[..]); |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | /// Check every value tag and empty and nonempty sequences. |
| 165 | @test unsafe fn values() throws (testing::TestError) { |
| 166 | let mut buffer: [u8; 64] = [0; 64]; |
| 167 | let mut out = writer::new(&mut buffer[..], &["data", "fn"]); |
| 168 | try writer::values(&mut out, &[]) catch { |
| 169 | throw testing::TestError::Failed; |
| 170 | }; |
| 171 | try writer::values(&mut out, &[ |
| 172 | il::Val::Reg(il::Reg { n: 0x12345678 }), |
| 173 | il::Val::Imm(-2), il::Val::DataSym("data"), |
| 174 | il::Val::FnAddr("fn"), il::Val::Undef, |
| 175 | ]) catch { |
| 176 | throw testing::TestError::Failed; |
| 177 | }; |
| 178 | try testing::expectBytesEq(&buffer[..out.offset], &[ |
| 179 | 0, 0, 0, 0, 5, 0, 0, 0, |
| 180 | 0, 0x78, 0x56, 0x34, 0x12, |
| 181 | 1, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
| 182 | 2, 0, 0, 0, 0, 3, 1, 0, 0, 0, 4, |
| 183 | ]); |
| 184 | let memory = &mut MEMORY[..256]; |
| 185 | let mut arena = alloc::new(&mut memory[..]); |
| 186 | let mut input = reader::new(&buffer[..out.offset], &mut arena, &["data", "fn"]); |
| 187 | set input.registers = 0x12345679; |
| 188 | let empty = try reader::values(&mut input) catch { |
| 189 | throw testing::TestError::Failed; |
| 190 | }; |
| 191 | let decoded = try reader::values(&mut input) catch { |
| 192 | throw testing::TestError::Failed; |
| 193 | }; |
| 194 | try testing::expect(empty.len == 0); |
| 195 | try testing::expect(decoded.len == 5); |
| 196 | try testing::expect(input.offset == out.offset); |
| 197 | let mut repeated: [u8; 64] = [0; 64]; |
| 198 | let mut copy = writer::new(&mut repeated[..], &["data", "fn"]); |
| 199 | try writer::values(&mut copy, empty) catch { |
| 200 | throw testing::TestError::Failed; |
| 201 | }; |
| 202 | try writer::values(&mut copy, decoded) catch { |
| 203 | throw testing::TestError::Failed; |
| 204 | }; |
| 205 | try testing::expectBytesEq(&buffer[..out.offset], &repeated[..copy.offset]); |
| 206 | |
| 207 | } |
| 208 | |
| 209 | /// Check initializer bytes and repetition counts. |
| 210 | @test unsafe fn initializers() throws (testing::TestError) { |
| 211 | let mut buffer: [u8; 128] = [0; 128]; |
| 212 | let mut out = writer::new(&mut buffer[..], &["data", "fn"]); |
| 213 | try writer::dataValue(&mut out, il::DataValue { item: il::DataItem::Val { typ: il::Type::W8, |
| 214 | val: -1 }, count: 0 }) catch { |
| 215 | throw testing::TestError::Failed; |
| 216 | }; |
| 217 | try writer::dataValue(&mut out, il::DataValue { item: il::DataItem::Val { typ: il::Type::W16, |
| 218 | val: -2 }, count: 1 }) catch { |
| 219 | throw testing::TestError::Failed; |
| 220 | }; |
| 221 | try writer::dataValue(&mut out, il::DataValue { item: il::DataItem::Val { typ: il::Type::W32, |
| 222 | val: -3 }, count: 2 }) catch { |
| 223 | throw testing::TestError::Failed; |
| 224 | }; |
| 225 | try writer::dataValue(&mut out, il::DataValue { item: il::DataItem::Val { typ: il::Type::W64, |
| 226 | val: -4 }, count: 3 }) catch { |
| 227 | throw testing::TestError::Failed; |
| 228 | }; |
| 229 | try writer::dataValue(&mut out, il::DataValue { item: il::DataItem::Sym("data"), count: 4 }) |
| 230 | catch { |
| 231 | throw testing::TestError::Failed; |
| 232 | }; |
| 233 | try writer::dataValue(&mut out, il::DataValue { item: il::DataItem::Fn("fn"), count: 5 }) catch |
| 234 | { |
| 235 | throw testing::TestError::Failed; |
| 236 | }; |
| 237 | try writer::dataValue(&mut out, il::DataValue { item: il::DataItem::Str("ab"), count: 6 }) catch |
| 238 | { |
| 239 | throw testing::TestError::Failed; |
| 240 | }; |
| 241 | try writer::dataValue(&mut out, il::DataValue { item: il::DataItem::Str(""), count: 7 }) catch { |
| 242 | throw testing::TestError::Failed; }; |
| 243 | try writer::dataValue(&mut out, il::DataValue { item: il::DataItem::Undef, count: 8 }) catch { |
| 244 | throw testing::TestError::Failed; }; |
| 245 | try testing::expectBytesEq(&buffer[..out.offset], &[0, 1, 255, 0, 0, 0, 0, 0, 2, 254, 255, 1, 0, |
| 246 | 0, 0, 0, 4, 253, 255, 255, 255, 2, 0, 0, 0, 0, 8, 252, 255, 255, 255, 255, 255, 255, 255, 3, |
| 247 | 0, 0, 0, 1, 0, 0, 0, 0, 4, 0, 0, 0, 2, 1, 0, 0, 0, 5, 0, 0, 0, 3, 2, 0, 0, 0, 97, 98, 6, 0, |
| 248 | 0, 0, 3, 0, 0, 0, 0, 7, 0, 0, 0, 4, 8, 0, 0, 0]); |
| 249 | } |
| 250 | |
| 251 | /// Reject invalid widths, insufficient storage, and absent symbols. |
| 252 | @test unsafe fn errors() throws (testing::TestError) { |
| 253 | let mut buffer: [u8; 8] = [0; 8]; |
| 254 | let mut out = writer::new(&mut buffer[..], &[]); |
| 255 | let mut failures: u32 = 0; |
| 256 | try writer::integer(&mut out, 1, 3) catch err { |
| 257 | try testing::expect(err == binary::Error::Invalid); |
| 258 | set failures += 1; |
| 259 | }; |
| 260 | try writer::symbol(&mut out, "absent") catch err { |
| 261 | try testing::expect(err == binary::Error::Symbol); |
| 262 | set failures += 1; |
| 263 | }; |
| 264 | try testing::expect(out.offset == 0); |
| 265 | try writer::integer(&mut out, 0, 8) catch { |
| 266 | throw testing::TestError::Failed; |
| 267 | }; |
| 268 | try writer::integer(&mut out, 1, 1) catch err { |
| 269 | try testing::expect(err == binary::Error::Capacity); |
| 270 | set failures += 1; |
| 271 | }; |
| 272 | try testing::expect(failures == 3); |
| 273 | try testing::expect(out.offset == 8); |
| 274 | } |
| 275 | |
| 276 | /// Check operation tags independently of the native union representation. |
| 277 | @test unsafe fn operations() throws (testing::TestError) { |
| 278 | let binaryOps = &[ |
| 279 | il::BinOp::Add, il::BinOp::Sub, il::BinOp::Mul, |
| 280 | il::BinOp::Sdiv, il::BinOp::Udiv, il::BinOp::Srem, |
| 281 | il::BinOp::Urem, il::BinOp::Eq, il::BinOp::Ne, |
| 282 | il::BinOp::Slt, il::BinOp::Sge, il::BinOp::Ult, |
| 283 | il::BinOp::Uge, il::BinOp::And, il::BinOp::Or, |
| 284 | il::BinOp::Xor, il::BinOp::Shl, il::BinOp::Sshr, |
| 285 | il::BinOp::Ushr, |
| 286 | ]; |
| 287 | for op, tag in binaryOps { |
| 288 | try instruction(il::Instr::BinOp { |
| 289 | op, typ: il::Type::W64, dst: il::Reg { n: 1 }, |
| 290 | a: il::Val::Undef, b: il::Val::Undef, |
| 291 | }, &[6, tag as u8, 8, 1, 0, 0, 0, 4, 4]); |
| 292 | } |
| 293 | for op, tag in &[il::UnOp::Neg, il::UnOp::Not] { |
| 294 | try instruction(il::Instr::UnOp { |
| 295 | op, typ: il::Type::W64, dst: il::Reg { n: 1 }, |
| 296 | a: il::Val::Undef, |
| 297 | }, &[7, tag as u8, 8, 1, 0, 0, 0, 4]); |
| 298 | } |
| 299 | let mut empty: [il::Val; 0] = []; |
| 300 | for op, tag in &[il::CmpOp::Eq, il::CmpOp::Ne, il::CmpOp::Slt, il::CmpOp::Ult] { |
| 301 | try instruction(il::Instr::Br { |
| 302 | op, typ: il::Type::W8, a: il::Val::Undef, b: il::Val::Undef, |
| 303 | thenTarget: 1, thenArgs: &mut empty[..], |
| 304 | elseTarget: 2, elseArgs: &mut empty[..], |
| 305 | }, &[13, tag as u8, 1, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0]); |
| 306 | } |
| 307 | } |
| 308 | |
| 309 | /// Check byte-sequence bounds at every output size. |
| 310 | @test unsafe fn byteCapacity() throws (testing::TestError) { |
| 311 | let mut buffer: [u8; 7] = [0; 7]; |
| 312 | for capacity in 0..7 { |
| 313 | let mut out = writer::new(&mut buffer[..capacity], &[]); |
| 314 | let mut failed = false; |
| 315 | try writer::bytes(&mut out, "abc") catch err { |
| 316 | try testing::expect(err == binary::Error::Capacity); |
| 317 | set failed = true; |
| 318 | }; |
| 319 | try testing::expect(failed); |
| 320 | try testing::expect(out.offset <= capacity); |
| 321 | } |
| 322 | let mut out = writer::new(&mut buffer[..], &[]); |
| 323 | try writer::bytes(&mut out, "abc") catch { |
| 324 | throw testing::TestError::Failed; |
| 325 | }; |
| 326 | try testing::expectBytesEq(&buffer[..], &[3, 0, 0, 0, 97, 98, 99]); |
| 327 | } |