Add buffer skeleton
This commit is contained in:
parent
b18365a7e4
commit
49d2456fca
@ -2,7 +2,6 @@ local module = {}
|
||||
|
||||
local to_u32 = bit32.band
|
||||
|
||||
local bit_or = bit32.bor
|
||||
local bit_and = bit32.band
|
||||
local bit_lshift = bit32.lshift
|
||||
local bit_rshift = bit32.rshift
|
||||
@ -139,14 +138,18 @@ do
|
||||
end
|
||||
end
|
||||
|
||||
function copysign.f32(lhs, rhs)
|
||||
local packed = string_pack("<d", rhs)
|
||||
local sign = string_byte(packed, 8)
|
||||
local CP_INSTANCE = buffer.create(8)
|
||||
|
||||
if sign >= 0x80 then
|
||||
return -math_abs(lhs)
|
||||
local buffer_write_f64 = buffer.writef64
|
||||
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
|
||||
return math_abs(lhs)
|
||||
return -math_abs(lhs)
|
||||
end
|
||||
end
|
||||
|
||||
@ -154,11 +157,11 @@ do
|
||||
local result = math_round(num)
|
||||
|
||||
if (math_abs(num) + 0.5) % 2 == 1 then
|
||||
result = result - math_sign(result)
|
||||
end
|
||||
|
||||
return result - math_sign(result)
|
||||
else
|
||||
return result
|
||||
end
|
||||
end
|
||||
|
||||
neg.f64 = neg.f32
|
||||
min.f64 = min.f32
|
||||
@ -376,9 +379,6 @@ do
|
||||
local math_floor = math.floor
|
||||
local math_clamp = math.clamp
|
||||
|
||||
local string_pack = string.pack
|
||||
local string_unpack = string.unpack
|
||||
|
||||
local NUM_ZERO = Integer.ZERO
|
||||
local NUM_MIN_I64 = num_from_u32(0, 0x80000000)
|
||||
local NUM_MAX_I64 = num_from_u32(0xFFFFFFFF, 0x7FFFFFFF)
|
||||
@ -576,30 +576,44 @@ do
|
||||
|
||||
promote.f64_f32 = no_op
|
||||
|
||||
function reinterpret.i32_f32(num)
|
||||
local packed = string_pack("f", num)
|
||||
local RE_INSTANCE = buffer.create(8)
|
||||
|
||||
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
|
||||
|
||||
function reinterpret.i64_f64(num)
|
||||
local packed = string_pack("d", num)
|
||||
local data_1, data_2 = string_unpack("I4I4", packed)
|
||||
buffer_write_f64(RE_INSTANCE, 0, num)
|
||||
|
||||
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)
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
function reinterpret.f64_i64(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
|
||||
|
||||
module.wrap = wrap
|
||||
@ -617,357 +631,214 @@ do
|
||||
local store = {}
|
||||
local allocator = {}
|
||||
|
||||
local bit_extract = bit32.extract
|
||||
local bit_replace = bit32.replace
|
||||
local string_sub = string.sub
|
||||
|
||||
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 string_char = string.char
|
||||
local string_unpack = string.unpack
|
||||
local buffer_len = buffer.len
|
||||
local buffer_copy = buffer.copy
|
||||
local buffer_fill = buffer.fill
|
||||
|
||||
local reinterpret_f32_i32 = module.reinterpret.f32_i32
|
||||
local reinterpret_f64_i64 = module.reinterpret.f64_i64
|
||||
local reinterpret_i32_f32 = module.reinterpret.i32_f32
|
||||
local reinterpret_i64_f64 = module.reinterpret.i64_f64
|
||||
local buffer_read_i8 = buffer.readi8
|
||||
local buffer_read_u8 = buffer.readu8
|
||||
local buffer_read_i16 = buffer.readi16
|
||||
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 value = data[math_floor(addr / 4)] or 0
|
||||
|
||||
return bit_extract(value, addr % 4 * 8, 8)
|
||||
end
|
||||
|
||||
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
|
||||
local buffer_write_u8 = buffer.writeu8
|
||||
local buffer_write_u16 = buffer.writeu16
|
||||
local buffer_write_u32 = buffer.writeu32
|
||||
local buffer_write_f32 = buffer.writef32
|
||||
local buffer_write_f64 = buffer.writef64
|
||||
|
||||
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
|
||||
return to_u32(temp - 0x100)
|
||||
if value >= 0 then
|
||||
return value
|
||||
else
|
||||
return temp
|
||||
return value + 0x100000000
|
||||
end
|
||||
end
|
||||
|
||||
function load.i32_u8(memory, addr)
|
||||
return load_byte(memory.data, addr)
|
||||
return buffer_read_u8(memory.data, addr)
|
||||
end
|
||||
|
||||
function load.i32_i16(memory, addr)
|
||||
local data = memory.data
|
||||
local temp
|
||||
local value = buffer_read_i16(memory.data, addr)
|
||||
|
||||
if addr % 4 == 0 then
|
||||
temp = bit_and(data[addr / 4] or 0, 0xFFFF)
|
||||
if value >= 0 then
|
||||
return value
|
||||
else
|
||||
local b1 = load_byte(data, addr)
|
||||
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
|
||||
return value + 0x100000000
|
||||
end
|
||||
end
|
||||
|
||||
function load.i32_u16(memory, addr)
|
||||
local data = memory.data
|
||||
|
||||
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
|
||||
return buffer_read_u16(memory.data, addr)
|
||||
end
|
||||
|
||||
function load.i32(memory, addr)
|
||||
local data = memory.data
|
||||
|
||||
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
|
||||
return buffer_read_u32(memory.data, addr)
|
||||
end
|
||||
|
||||
function load.i64_i8(memory, addr)
|
||||
local data_1 = load_byte(memory.data, addr)
|
||||
local data_2
|
||||
local value = buffer_read_i8(memory.data, addr)
|
||||
|
||||
if data_1 >= 0x80 then
|
||||
data_1 = to_u32(data_1 - 0x100)
|
||||
data_2 = 0xFFFFFFFF
|
||||
if value >= 0 then
|
||||
return num_from_u32(value, 0)
|
||||
else
|
||||
data_2 = 0
|
||||
return num_from_u32(value + 0x100000000, 0xFFFFFFFF)
|
||||
end
|
||||
|
||||
return num_from_u32(data_1, data_2)
|
||||
end
|
||||
|
||||
function load.i64_u8(memory, addr)
|
||||
local temp = load_byte(memory.data, addr)
|
||||
|
||||
return num_from_u32(temp, 0)
|
||||
return num_from_u32(buffer_read_u8(memory.data, addr), 0)
|
||||
end
|
||||
|
||||
function load.i64_i16(memory, addr)
|
||||
local data = memory.data
|
||||
local data_1, data_2
|
||||
local value = buffer_read_i16(memory.data, addr)
|
||||
|
||||
if addr % 4 == 0 then
|
||||
data_1 = bit_and(data[addr / 4] or 0, 0xFFFF)
|
||||
if value >= 0 then
|
||||
return num_from_u32(value, 0)
|
||||
else
|
||||
local b1 = load_byte(data, addr)
|
||||
local b2 = bit_lshift(load_byte(data, addr + 1), 8)
|
||||
|
||||
data_1 = bit_or(b1, b2)
|
||||
return num_from_u32(value + 0x100000000, 0xFFFFFFFF)
|
||||
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
|
||||
|
||||
function load.i64_u16(memory, addr)
|
||||
local data = memory.data
|
||||
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)
|
||||
return num_from_u32(buffer_read_u16(memory.data, addr), 0)
|
||||
end
|
||||
|
||||
function load.i64_i32(memory, addr)
|
||||
local data = memory.data
|
||||
local data_1, data_2
|
||||
local value = buffer_read_i32(memory.data, addr)
|
||||
|
||||
if addr % 4 == 0 then
|
||||
data_1 = data[addr / 4] or 0
|
||||
if value >= 0 then
|
||||
return num_from_u32(value, 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)
|
||||
|
||||
data_1 = bit_or(b1, b2, b3, b4)
|
||||
return num_from_u32(value + 0x100000000, 0xFFFFFFFF)
|
||||
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
|
||||
|
||||
function load.i64_u32(memory, addr)
|
||||
local data = memory.data
|
||||
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)
|
||||
return num_from_u32(buffer_read_u32(memory.data, addr), 0)
|
||||
end
|
||||
|
||||
return num_from_u32(temp, 0)
|
||||
end
|
||||
|
||||
local load_i32 = load.i32
|
||||
|
||||
function load.i64(memory, addr)
|
||||
local data_1 = load_i32(memory, addr)
|
||||
local data_2 = load_i32(memory, addr + 4)
|
||||
local data = memory.data
|
||||
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
|
||||
|
||||
local load_i64 = load.i64
|
||||
|
||||
function load.f32(memory, addr)
|
||||
local raw = load_i32(memory, addr)
|
||||
|
||||
return reinterpret_f32_i32(raw)
|
||||
return buffer_read_f32(memory.data, addr)
|
||||
end
|
||||
|
||||
function load.f64(memory, addr)
|
||||
local raw = load_i64(memory, addr)
|
||||
|
||||
return reinterpret_f64_i64(raw)
|
||||
return buffer_read_f64(memory.data, addr)
|
||||
end
|
||||
|
||||
function load.string(memory, addr, len)
|
||||
local buffer = table.create(len)
|
||||
local data = memory.data
|
||||
local temp = buffer_create(len)
|
||||
|
||||
for i = 1, len do
|
||||
local raw = load_byte(data, addr + i - 1)
|
||||
buffer_copy(temp, 0, memory.data, addr, len)
|
||||
|
||||
buffer[i] = string_char(raw)
|
||||
end
|
||||
|
||||
return table.concat(buffer)
|
||||
return buffer_to_string(temp)
|
||||
end
|
||||
|
||||
function store.i32_n8(memory, addr, value)
|
||||
store_byte(memory.data, addr, value)
|
||||
buffer_write_u8(memory.data, addr, value)
|
||||
end
|
||||
|
||||
function store.i32_n16(memory, addr, value)
|
||||
store_byte(memory.data, addr, value)
|
||||
store_byte(memory.data, addr + 1, bit_rshift(value, 8))
|
||||
buffer_write_u16(memory.data, addr, value)
|
||||
end
|
||||
|
||||
function store.i32(memory, addr, value)
|
||||
local data = memory.data
|
||||
|
||||
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))
|
||||
buffer_write_u32(memory.data, addr, value)
|
||||
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)
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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)
|
||||
store_i32(memory, addr + 4, data_2)
|
||||
buffer_write_u32(data, addr, value_1)
|
||||
buffer_write_u32(data, addr + 4, value_2)
|
||||
end
|
||||
|
||||
local store_i64 = store.i64
|
||||
|
||||
function store.f32(memory, addr, value)
|
||||
store_i32(memory, addr, reinterpret_i32_f32(value))
|
||||
buffer_write_f32(memory.data, addr, value)
|
||||
end
|
||||
|
||||
function store.f64(memory, addr, value)
|
||||
store_i64(memory, addr, reinterpret_i64_f64(value))
|
||||
buffer_write_f64(memory.data, addr, value)
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
for i = 1, len - rem, 4 do
|
||||
local v = string_unpack("<I4", data, i)
|
||||
|
||||
store_i32(memory, addr + i - 1, v)
|
||||
buffer_copy(memory.data, addr, temp)
|
||||
end
|
||||
|
||||
for i = len - rem + 1, len do
|
||||
local v = string_byte(data, i)
|
||||
|
||||
store_i32_n8(memory, addr + i - 1, v)
|
||||
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)
|
||||
local data_1 = memory_1.data
|
||||
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
|
||||
buffer_copy(memory_1.data, addr_1, memory_2.data, addr_2, len)
|
||||
end
|
||||
|
||||
function store.fill(memory, addr, len, value)
|
||||
local data = memory.data
|
||||
buffer_fill(memory.data, addr, value, len)
|
||||
end
|
||||
|
||||
for i = 1, len do
|
||||
store_byte(data, addr + i - 1, value)
|
||||
end
|
||||
end
|
||||
local WASM_PAGE_SIZE = 65536
|
||||
|
||||
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
|
||||
|
||||
function allocator.grow(memory, num)
|
||||
local old = memory.min
|
||||
local old = allocator.size(memory)
|
||||
local new = old + num
|
||||
|
||||
if new > memory.max then
|
||||
return to_u32(-1)
|
||||
else
|
||||
memory.min = new
|
||||
if new <= memory.max then
|
||||
local reallocated = buffer_create(new * WASM_PAGE_SIZE)
|
||||
|
||||
buffer_copy(reallocated, 0, memory.data)
|
||||
|
||||
memory.data = reallocated
|
||||
|
||||
return old
|
||||
else
|
||||
return 0xFFFFFFFF
|
||||
end
|
||||
end
|
||||
|
||||
@ -977,4 +848,3 @@ do
|
||||
end
|
||||
|
||||
return module
|
||||
|
||||
|
@ -85,7 +85,7 @@ impl Driver for LoadAt {
|
||||
|
||||
impl Driver for MemorySize {
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ do
|
||||
local WASM_PAGE_SIZE = 65536
|
||||
|
||||
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
|
||||
|
||||
local function load_checked(name, size)
|
||||
|
Loading…
x
Reference in New Issue
Block a user