Add buffer skeleton

This commit is contained in:
Rerumu 2023-11-05 14:51:40 -05:00
parent b18365a7e4
commit 49d2456fca
3 changed files with 129 additions and 259 deletions

View File

@ -2,7 +2,6 @@ local module = {}
local to_u32 = bit32.band local to_u32 = bit32.band
local bit_or = bit32.bor
local bit_and = bit32.band local bit_and = bit32.band
local bit_lshift = bit32.lshift local bit_lshift = bit32.lshift
local bit_rshift = bit32.rshift local bit_rshift = bit32.rshift
@ -139,14 +138,18 @@ do
end end
end end
function copysign.f32(lhs, rhs) local CP_INSTANCE = buffer.create(8)
local packed = string_pack("<d", rhs)
local sign = string_byte(packed, 8)
if sign >= 0x80 then local buffer_write_f64 = buffer.writef64
return -math_abs(lhs) local buffer_read_i8 = buffer.readi8
function copysign.f32(lhs, rhs)
buffer_write_f64(CP_INSTANCE, 0, rhs)
if buffer_read_i8(CP_INSTANCE, 7) >= 0 then
return (math_abs(lhs))
else else
return math_abs(lhs) return -math_abs(lhs)
end end
end end
@ -154,10 +157,10 @@ do
local result = math_round(num) local result = math_round(num)
if (math_abs(num) + 0.5) % 2 == 1 then if (math_abs(num) + 0.5) % 2 == 1 then
result = result - math_sign(result) return result - math_sign(result)
else
return result
end end
return result
end end
neg.f64 = neg.f32 neg.f64 = neg.f32
@ -376,9 +379,6 @@ do
local math_floor = math.floor local math_floor = math.floor
local math_clamp = math.clamp local math_clamp = math.clamp
local string_pack = string.pack
local string_unpack = string.unpack
local NUM_ZERO = Integer.ZERO local NUM_ZERO = Integer.ZERO
local NUM_MIN_I64 = num_from_u32(0, 0x80000000) local NUM_MIN_I64 = num_from_u32(0, 0x80000000)
local NUM_MAX_I64 = num_from_u32(0xFFFFFFFF, 0x7FFFFFFF) local NUM_MAX_I64 = num_from_u32(0xFFFFFFFF, 0x7FFFFFFF)
@ -576,30 +576,44 @@ do
promote.f64_f32 = no_op promote.f64_f32 = no_op
function reinterpret.i32_f32(num) local RE_INSTANCE = buffer.create(8)
local packed = string_pack("f", num)
return string_unpack("I4", packed) local buffer_read_f32 = buffer.readf32
local buffer_read_f64 = buffer.readf64
local buffer_read_u32 = buffer.readu32
local buffer_write_f32 = buffer.writef32
local buffer_write_f64 = buffer.writef64
local buffer_write_u32 = buffer.writeu32
function reinterpret.i32_f32(num)
buffer_write_f32(RE_INSTANCE, 0, num)
return buffer_read_u32(RE_INSTANCE, 0)
end end
function reinterpret.i64_f64(num) function reinterpret.i64_f64(num)
local packed = string_pack("d", num) buffer_write_f64(RE_INSTANCE, 0, num)
local data_1, data_2 = string_unpack("I4I4", packed)
local data_1 = buffer_read_u32(RE_INSTANCE, 0)
local data_2 = buffer_read_u32(RE_INSTANCE, 4)
return num_from_u32(data_1, data_2) return num_from_u32(data_1, data_2)
end end
function reinterpret.f32_i32(num) function reinterpret.f32_i32(num)
local packed = string_pack("I4", num) buffer_write_u32(RE_INSTANCE, 0, num)
return string_unpack("f", packed) return buffer_read_f32(RE_INSTANCE, 0)
end end
function reinterpret.f64_i64(num) function reinterpret.f64_i64(num)
local data_1, data_2 = num_into_u32(num) local data_1, data_2 = num_into_u32(num)
local packed = string_pack("I4I4", data_1, data_2)
return string_unpack("d", packed) buffer_write_u32(RE_INSTANCE, 0, data_1)
buffer_write_u32(RE_INSTANCE, 4, data_2)
return buffer_read_f64(RE_INSTANCE, 0)
end end
module.wrap = wrap module.wrap = wrap
@ -617,357 +631,214 @@ do
local store = {} local store = {}
local allocator = {} local allocator = {}
local bit_extract = bit32.extract local string_sub = string.sub
local bit_replace = bit32.replace
local math_floor = math.floor local buffer_create = buffer.create
local buffer_to_string = buffer.tostring
local buffer_from_string = buffer.fromstring
local string_byte = string.byte local buffer_len = buffer.len
local string_char = string.char local buffer_copy = buffer.copy
local string_unpack = string.unpack local buffer_fill = buffer.fill
local reinterpret_f32_i32 = module.reinterpret.f32_i32 local buffer_read_i8 = buffer.readi8
local reinterpret_f64_i64 = module.reinterpret.f64_i64 local buffer_read_u8 = buffer.readu8
local reinterpret_i32_f32 = module.reinterpret.i32_f32 local buffer_read_i16 = buffer.readi16
local reinterpret_i64_f64 = module.reinterpret.i64_f64 local buffer_read_u16 = buffer.readu16
local buffer_read_i32 = buffer.readi32
local buffer_read_u32 = buffer.readu32
local buffer_read_f32 = buffer.readf32
local buffer_read_f64 = buffer.readf64
local function load_byte(data, addr) local buffer_write_u8 = buffer.writeu8
local value = data[math_floor(addr / 4)] or 0 local buffer_write_u16 = buffer.writeu16
local buffer_write_u32 = buffer.writeu32
return bit_extract(value, addr % 4 * 8, 8) local buffer_write_f32 = buffer.writef32
end local buffer_write_f64 = buffer.writef64
local function store_byte(data, addr, value)
local adjust = math_floor(addr / 4)
data[adjust] = bit_replace(data[adjust] or 0, value, addr % 4 * 8, 8)
end
function load.i32_i8(memory, addr) function load.i32_i8(memory, addr)
local temp = load_byte(memory.data, addr) local value = buffer_read_i8(memory.data, addr)
if temp >= 0x80 then if value >= 0 then
return to_u32(temp - 0x100) return value
else else
return temp return value + 0x100000000
end end
end end
function load.i32_u8(memory, addr) function load.i32_u8(memory, addr)
return load_byte(memory.data, addr) return buffer_read_u8(memory.data, addr)
end end
function load.i32_i16(memory, addr) function load.i32_i16(memory, addr)
local data = memory.data local value = buffer_read_i16(memory.data, addr)
local temp
if addr % 4 == 0 then if value >= 0 then
temp = bit_and(data[addr / 4] or 0, 0xFFFF) return value
else else
local b1 = load_byte(data, addr) return value + 0x100000000
local b2 = bit_lshift(load_byte(data, addr + 1), 8)
temp = bit_or(b1, b2)
end
if temp >= 0x8000 then
return to_u32(temp - 0x10000)
else
return temp
end end
end end
function load.i32_u16(memory, addr) function load.i32_u16(memory, addr)
local data = memory.data return buffer_read_u16(memory.data, addr)
if addr % 4 == 0 then
return bit_and(data[addr / 4] or 0, 0xFFFF)
else
local b1 = load_byte(data, addr)
local b2 = bit_lshift(load_byte(data, addr + 1), 8)
return bit_or(b1, b2)
end
end end
function load.i32(memory, addr) function load.i32(memory, addr)
local data = memory.data return buffer_read_u32(memory.data, addr)
if addr % 4 == 0 then
-- aligned read
return data[addr / 4] or 0
else
-- unaligned read
local b1 = load_byte(data, addr)
local b2 = bit_lshift(load_byte(data, addr + 1), 8)
local b3 = bit_lshift(load_byte(data, addr + 2), 16)
local b4 = bit_lshift(load_byte(data, addr + 3), 24)
return bit_or(b1, b2, b3, b4)
end
end end
function load.i64_i8(memory, addr) function load.i64_i8(memory, addr)
local data_1 = load_byte(memory.data, addr) local value = buffer_read_i8(memory.data, addr)
local data_2
if data_1 >= 0x80 then if value >= 0 then
data_1 = to_u32(data_1 - 0x100) return num_from_u32(value, 0)
data_2 = 0xFFFFFFFF
else else
data_2 = 0 return num_from_u32(value + 0x100000000, 0xFFFFFFFF)
end end
return num_from_u32(data_1, data_2)
end end
function load.i64_u8(memory, addr) function load.i64_u8(memory, addr)
local temp = load_byte(memory.data, addr) return num_from_u32(buffer_read_u8(memory.data, addr), 0)
return num_from_u32(temp, 0)
end end
function load.i64_i16(memory, addr) function load.i64_i16(memory, addr)
local data = memory.data local value = buffer_read_i16(memory.data, addr)
local data_1, data_2
if addr % 4 == 0 then if value >= 0 then
data_1 = bit_and(data[addr / 4] or 0, 0xFFFF) return num_from_u32(value, 0)
else else
local b1 = load_byte(data, addr) return num_from_u32(value + 0x100000000, 0xFFFFFFFF)
local b2 = bit_lshift(load_byte(data, addr + 1), 8)
data_1 = bit_or(b1, b2)
end end
if data_1 >= 0x8000 then
data_1 = to_u32(data_1 - 0x10000)
data_2 = 0xFFFFFFFF
else
data_2 = 0
end
return num_from_u32(data_1, data_2)
end end
function load.i64_u16(memory, addr) function load.i64_u16(memory, addr)
local data = memory.data return num_from_u32(buffer_read_u16(memory.data, addr), 0)
local temp
if addr % 4 == 0 then
temp = bit_and(data[addr / 4] or 0, 0xFFFF)
else
local b1 = load_byte(data, addr)
local b2 = bit_lshift(load_byte(data, addr + 1), 8)
temp = bit_or(b1, b2)
end
return num_from_u32(temp, 0)
end end
function load.i64_i32(memory, addr) function load.i64_i32(memory, addr)
local data = memory.data local value = buffer_read_i32(memory.data, addr)
local data_1, data_2
if addr % 4 == 0 then if value >= 0 then
data_1 = data[addr / 4] or 0 return num_from_u32(value, 0)
else else
local b1 = load_byte(data, addr) return num_from_u32(value + 0x100000000, 0xFFFFFFFF)
local b2 = bit_lshift(load_byte(data, addr + 1), 8)
local b3 = bit_lshift(load_byte(data, addr + 2), 16)
local b4 = bit_lshift(load_byte(data, addr + 3), 24)
data_1 = bit_or(b1, b2, b3, b4)
end end
if data_1 >= 0x80000000 then
data_1 = to_u32(data_1 - 0x100000000)
data_2 = 0xFFFFFFFF
else
data_2 = 0
end
return num_from_u32(data_1, data_2)
end end
function load.i64_u32(memory, addr) function load.i64_u32(memory, addr)
local data = memory.data return num_from_u32(buffer_read_u32(memory.data, addr), 0)
local temp
if addr % 4 == 0 then
temp = data[addr / 4] or 0
else
local b1 = load_byte(data, addr)
local b2 = bit_lshift(load_byte(data, addr + 1), 8)
local b3 = bit_lshift(load_byte(data, addr + 2), 16)
local b4 = bit_lshift(load_byte(data, addr + 3), 24)
temp = bit_or(b1, b2, b3, b4)
end
return num_from_u32(temp, 0)
end end
local load_i32 = load.i32
function load.i64(memory, addr) function load.i64(memory, addr)
local data_1 = load_i32(memory, addr) local data = memory.data
local data_2 = load_i32(memory, addr + 4) local value_1 = buffer_read_u32(data, addr)
local value_2 = buffer_read_u32(data, addr + 4)
return num_from_u32(data_1, data_2) return num_from_u32(value_1, value_2)
end end
local load_i64 = load.i64
function load.f32(memory, addr) function load.f32(memory, addr)
local raw = load_i32(memory, addr) return buffer_read_f32(memory.data, addr)
return reinterpret_f32_i32(raw)
end end
function load.f64(memory, addr) function load.f64(memory, addr)
local raw = load_i64(memory, addr) return buffer_read_f64(memory.data, addr)
return reinterpret_f64_i64(raw)
end end
function load.string(memory, addr, len) function load.string(memory, addr, len)
local buffer = table.create(len) local temp = buffer_create(len)
local data = memory.data
for i = 1, len do buffer_copy(temp, 0, memory.data, addr, len)
local raw = load_byte(data, addr + i - 1)
buffer[i] = string_char(raw) return buffer_to_string(temp)
end
return table.concat(buffer)
end end
function store.i32_n8(memory, addr, value) function store.i32_n8(memory, addr, value)
store_byte(memory.data, addr, value) buffer_write_u8(memory.data, addr, value)
end end
function store.i32_n16(memory, addr, value) function store.i32_n16(memory, addr, value)
store_byte(memory.data, addr, value) buffer_write_u16(memory.data, addr, value)
store_byte(memory.data, addr + 1, bit_rshift(value, 8))
end end
function store.i32(memory, addr, value) function store.i32(memory, addr, value)
local data = memory.data buffer_write_u32(memory.data, addr, value)
if addr % 4 == 0 then
-- aligned write
data[addr / 4] = value
else
-- unaligned write
store_byte(data, addr, value)
store_byte(data, addr + 1, bit_rshift(value, 8))
store_byte(data, addr + 2, bit_rshift(value, 16))
store_byte(data, addr + 3, bit_rshift(value, 24))
end
end end
local store_i32 = store.i32
local store_i32_n8 = store.i32_n8
local store_i32_n16 = store.i32_n16
function store.i64_n8(memory, addr, value) function store.i64_n8(memory, addr, value)
local data_1, _ = num_into_u32(value) local value_1, _ = num_into_u32(value)
store_i32_n8(memory, addr, data_1) buffer_write_u8(memory.data, addr, value_1)
end end
function store.i64_n16(memory, addr, value) function store.i64_n16(memory, addr, value)
local data_1, _ = num_into_u32(value) local value_1, _ = num_into_u32(value)
store_i32_n16(memory, addr, data_1) buffer_write_u16(memory.data, addr, value_1)
end end
function store.i64_n32(memory, addr, value) function store.i64_n32(memory, addr, value)
local data_1, _ = num_into_u32(value) local value_1, _ = num_into_u32(value)
store_i32(memory, addr, data_1) buffer_write_u32(memory.data, addr, value_1)
end end
function store.i64(memory, addr, value) function store.i64(memory, addr, value)
local data_1, data_2 = num_into_u32(value) local data = memory.data
local value_1, value_2 = num_into_u32(value)
store_i32(memory, addr, data_1) buffer_write_u32(data, addr, value_1)
store_i32(memory, addr + 4, data_2) buffer_write_u32(data, addr + 4, value_2)
end end
local store_i64 = store.i64
function store.f32(memory, addr, value) function store.f32(memory, addr, value)
store_i32(memory, addr, reinterpret_i32_f32(value)) buffer_write_f32(memory.data, addr, value)
end end
function store.f64(memory, addr, value) function store.f64(memory, addr, value)
store_i64(memory, addr, reinterpret_i64_f64(value)) buffer_write_f64(memory.data, addr, value)
end end
function store.string(memory, addr, data, len) function store.string(memory, addr, data, len)
len = if len then len else #data local content = if not len or len == #data then data else string_sub(data, 1, len)
local temp = buffer_from_string(content)
local rem = len % 4 buffer_copy(memory.data, addr, temp)
for i = 1, len - rem, 4 do
local v = string_unpack("<I4", data, i)
store_i32(memory, addr + i - 1, v)
end
for i = len - rem + 1, len do
local v = string_byte(data, i)
store_i32_n8(memory, addr + i - 1, v)
end
end end
-- FIXME: `store.copy` and `store.fill` should be ideally using the same batched store as `store.string`
function store.copy(memory_1, addr_1, memory_2, addr_2, len) function store.copy(memory_1, addr_1, memory_2, addr_2, len)
local data_1 = memory_1.data buffer_copy(memory_1.data, addr_1, memory_2.data, addr_2, len)
local data_2 = memory_2.data
if addr_1 <= addr_2 then
for i = 1, len do
local v = load_byte(data_2, addr_2 + i - 1)
store_byte(data_1, addr_1 + i - 1, v)
end
else
for i = len, 1, -1 do
local v = load_byte(data_2, addr_2 + i - 1)
store_byte(data_1, addr_1 + i - 1, v)
end
end
end end
function store.fill(memory, addr, len, value) function store.fill(memory, addr, len, value)
local data = memory.data buffer_fill(memory.data, addr, value, len)
for i = 1, len do
store_byte(data, addr + i - 1, value)
end
end end
local WASM_PAGE_SIZE = 65536
function allocator.new(min, max) function allocator.new(min, max)
return { min = min, max = max, data = {} } return { max = max, data = buffer_create(min * WASM_PAGE_SIZE) }
end
function allocator.size(memory)
return buffer_len(memory.data) / WASM_PAGE_SIZE
end end
function allocator.grow(memory, num) function allocator.grow(memory, num)
local old = memory.min local old = allocator.size(memory)
local new = old + num local new = old + num
if new > memory.max then if new <= memory.max then
return to_u32(-1) local reallocated = buffer_create(new * WASM_PAGE_SIZE)
else
memory.min = new buffer_copy(reallocated, 0, memory.data)
memory.data = reallocated
return old return old
else
return 0xFFFFFFFF
end end
end end
@ -977,4 +848,3 @@ do
end end
return module return module

View File

@ -85,7 +85,7 @@ impl Driver for LoadAt {
impl Driver for MemorySize { impl Driver for MemorySize {
fn write(&self, _mng: &mut Manager, w: &mut dyn Write) -> Result<()> { fn write(&self, _mng: &mut Manager, w: &mut dyn Write) -> Result<()> {
write!(w, "memory_at_{}.min", self.memory()) write!(w, "rt.allocator.size(memory_at_{})", self.memory())
} }
} }

View File

@ -2,7 +2,7 @@ do
local WASM_PAGE_SIZE = 65536 local WASM_PAGE_SIZE = 65536
local function is_valid_address(memory, addr, size) local function is_valid_address(memory, addr, size)
return addr >= 0 and addr + size <= memory.min * WASM_PAGE_SIZE return addr >= 0 and addr + size <= rt.allocator.size(memory) * WASM_PAGE_SIZE
end end
local function load_checked(name, size) local function load_checked(name, size)