mirror of
https://github.com/odin-lang/Odin.git
synced 2026-07-22 15:32:35 +00:00
186 lines
4.0 KiB
Odin
186 lines
4.0 KiB
Odin
// rexcode · Brendan Punsky (dotbmp@github), original author
|
|
// Ginger Bill (gingerBill@github)
|
|
|
|
package rexcode_wasm
|
|
|
|
// LEB128 + little-endian primitives (shared by encoder and decoder)
|
|
// =============================================================================
|
|
|
|
// Unsigned LEB128. Advances `*offset`. Caller guarantees buffer space.
|
|
write_uleb :: #force_inline proc "contextless" (code: []u8, offset: ^u32, value: u64) {
|
|
v := value
|
|
for {
|
|
b := u8(v & 0x7F)
|
|
v >>= 7
|
|
if v != 0 {
|
|
b |= 0x80
|
|
}
|
|
code[offset^] = b
|
|
offset^ += 1
|
|
if v == 0 {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// Signed LEB128. Advances `*offset`.
|
|
write_sleb :: #force_inline proc "contextless" (code: []u8, offset: ^u32, value: i64) {
|
|
v := value
|
|
for {
|
|
b := u8(v & 0x7F)
|
|
v >>= 7 // arithmetic shift on signed value sign-extends
|
|
done := (v == 0 && (b & 0x40) == 0) || (v == -1 && (b & 0x40) != 0)
|
|
if !done {
|
|
b |= 0x80
|
|
}
|
|
code[offset^] = b
|
|
offset^ += 1
|
|
if done {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fixed 5-byte unsigned LEB128 (relocatable placeholder for 32-bit indices).
|
|
write_uleb_padded5 :: #force_inline proc "contextless" (code: []u8, offset: ^u32, value: u64) {
|
|
v := value
|
|
for i := 0; i < 5 && offset^ < u32(len(code)); i += 1 {
|
|
b := u8(v & 0x7F)
|
|
v >>= 7
|
|
if i != 4 {
|
|
b |= 0x80
|
|
}
|
|
code[offset^] = b
|
|
offset^ += 1
|
|
}
|
|
}
|
|
|
|
@(require_results)
|
|
uleb_size :: #force_inline proc "contextless" (value: u64) -> u32 {
|
|
v := value
|
|
n: u32 = 1
|
|
for /**/; v >= 0x80; n += 1 {
|
|
v >>= 7
|
|
}
|
|
return n
|
|
}
|
|
|
|
@(require_results)
|
|
sleb_size :: #force_inline proc "contextless" (value: i64) -> u32 {
|
|
v := value
|
|
n := u32(0)
|
|
for {
|
|
b := u8(v & 0x7F)
|
|
v >>= 7
|
|
n += 1
|
|
if (v == 0 && (b & 0x40) == 0) || (v == -1 && (b & 0x40) != 0) {
|
|
break
|
|
}
|
|
}
|
|
return n
|
|
}
|
|
|
|
// Read unsigned LEB128 starting at `*offset`; advances it. `ok` is false on
|
|
// truncation. Reads at most `max` bytes (10 covers u64).
|
|
@(require_results)
|
|
read_uleb :: #force_inline proc "contextless" (data: []u8, offset: ^u32) -> (value: u64, ok: bool) {
|
|
shift := uint(0)
|
|
for i := 0; i < 10 && offset^ < u32(len(data)); i += 1 {
|
|
b := data[offset^]
|
|
offset^ += 1
|
|
value |= u64(b & 0x7F) << shift
|
|
if b & 0x80 == 0 {
|
|
return value, true
|
|
}
|
|
shift += 7
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
// Read signed LEB128 starting at `*offset`; advances it.
|
|
@(require_results)
|
|
read_sleb :: #force_inline proc "contextless" (data: []u8, offset: ^u32) -> (value: i64, ok: bool) {
|
|
shift := uint(0)
|
|
b := u8(0)
|
|
for i := 0; i < 10 && offset^ < u32(len(data)); i += 1 {
|
|
b = data[offset^]
|
|
offset^ += 1
|
|
value |= i64(b & 0x7F) << shift
|
|
shift += 7
|
|
if b & 0x80 == 0 {
|
|
break
|
|
}
|
|
}
|
|
if shift < 64 && (b & 0x40) != 0 {
|
|
value |= -(i64(1) << shift)
|
|
}
|
|
ok = true
|
|
return
|
|
}
|
|
|
|
write_u32_block :: #force_inline proc(code: []u8, offset: ^u32, v: u32) {
|
|
assert(offset^+4 <= u32(len(code)))
|
|
code[offset^+0] = u8(v)
|
|
code[offset^+1] = u8(v >> 8)
|
|
code[offset^+2] = u8(v >> 16)
|
|
code[offset^+3] = u8(v >> 24)
|
|
offset^ += 4
|
|
}
|
|
|
|
write_u64_block :: #force_inline proc(code: []u8, offset: ^u32, v: u64) {
|
|
assert(offset^+8 <= u32(len(code)))
|
|
for i in u32(0)..<8 {
|
|
code[offset^+i] = u8(v >> (8 * i))
|
|
}
|
|
offset^ += 8
|
|
}
|
|
|
|
@(require_results)
|
|
read_u32_block :: #force_inline proc "contextless" (data: []u8, offset: ^u32) -> (u32, bool) {
|
|
if offset^+4 > u32(len(data)) {
|
|
return 0, false
|
|
}
|
|
v := u32(data[offset^+0]) |
|
|
u32(data[offset^+1])<<8 |
|
|
u32(data[offset^+2])<<16 |
|
|
u32(data[offset^+3])<<24
|
|
offset^ += 4
|
|
return v, true
|
|
}
|
|
|
|
@(require_results)
|
|
read_u64_block :: #force_inline proc "contextless" (data: []u8, offset: ^u32) -> (u64, bool) {
|
|
if offset^+8 > u32(len(data)) {
|
|
return 0, false
|
|
}
|
|
v := u64(0)
|
|
for i in u32(0)..<8 {
|
|
v |= u64(data[offset^+i]) << (8 * i)
|
|
}
|
|
offset^ += 8
|
|
return v, true
|
|
}
|
|
|
|
|
|
// Unsigned LEB128, appended to a [dynamic]u8
|
|
append_uleb :: proc(b: ^[dynamic]u8, value: u64) {
|
|
v := value
|
|
for {
|
|
bb := u8(v & 0x7F)
|
|
v >>= 7
|
|
if v != 0 {
|
|
bb |= 0x80
|
|
}
|
|
append(b, bb)
|
|
if v == 0 {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
append_uleb_name :: proc(b: ^[dynamic]u8, s: string) {
|
|
append_uleb(b, u64(len(s)))
|
|
append(b, s)
|
|
}
|