146 lines
3.2 KiB
Lua
146 lines
3.2 KiB
Lua
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
|
|
end
|
|
|
|
local function load_checked(name, size)
|
|
local old = assert(rt.load[name], "Missing load function " .. name)
|
|
|
|
rt.load[name] = function(memory, addr)
|
|
assert(is_valid_address(memory, addr, size), "Invalid memory read")
|
|
|
|
return old(memory, addr)
|
|
end
|
|
end
|
|
|
|
local function store_checked(name, size)
|
|
local old = assert(rt.store[name], "Missing store function " .. name)
|
|
|
|
rt.store[name] = function(memory, addr, value)
|
|
assert(is_valid_address(memory, addr, size), "Invalid memory write")
|
|
|
|
return old(memory, addr, value)
|
|
end
|
|
end
|
|
|
|
do
|
|
local old = rt.store.string
|
|
|
|
function rt.store.string(memory, addr, data, len)
|
|
assert(is_valid_address(memory, addr, #data), "Invalid memory write")
|
|
|
|
return old(memory, addr, data, len)
|
|
end
|
|
end
|
|
|
|
load_checked("i32_i8", 1)
|
|
load_checked("i32_u8", 1)
|
|
load_checked("i32_i16", 2)
|
|
load_checked("i32_u16", 2)
|
|
load_checked("i32", 4)
|
|
load_checked("i64_i8", 1)
|
|
load_checked("i64_u8", 1)
|
|
load_checked("i64_i16", 2)
|
|
load_checked("i64_u16", 2)
|
|
load_checked("i64_i32", 4)
|
|
load_checked("i64_u32", 4)
|
|
load_checked("i64", 8)
|
|
load_checked("f32", 4)
|
|
load_checked("f64", 8)
|
|
|
|
store_checked("i32_n8", 1)
|
|
store_checked("i32_n16", 2)
|
|
store_checked("i32", 4)
|
|
store_checked("i64_n8", 1)
|
|
store_checked("i64_n16", 2)
|
|
store_checked("i64_n32", 4)
|
|
store_checked("i64", 8)
|
|
store_checked("f32", 4)
|
|
store_checked("f64", 8)
|
|
end
|
|
|
|
local loaded = {}
|
|
local linked = {}
|
|
|
|
local LUA_NAN_ARITHMETIC = -(0 / 0)
|
|
local LUA_NAN_CANONICAL = -(0 / 0)
|
|
local LUA_NAN_DEFAULT = -(0 / 0)
|
|
local LUA_INFINITY = math.huge
|
|
|
|
local function is_number_equal(lhs, rhs)
|
|
if type(lhs) ~= "number" or type(rhs) ~= "number" then
|
|
return false
|
|
end
|
|
|
|
return math.abs(lhs - rhs) < 0.00001 or string.format("%.3g", lhs) == string.format("%.3g", rhs)
|
|
end
|
|
|
|
local function assert_eq(lhs, rhs, level)
|
|
if lhs == rhs or is_number_equal(lhs, rhs) then
|
|
return
|
|
end
|
|
|
|
lhs = tostring(lhs)
|
|
rhs = tostring(rhs)
|
|
level = (level or 1) + 1
|
|
|
|
error(lhs .. " ~= " .. rhs, level)
|
|
end
|
|
|
|
local function assert_neq(lhs, rhs, level)
|
|
if lhs ~= rhs and not is_number_equal(lhs, rhs) then
|
|
return
|
|
end
|
|
|
|
lhs = tostring(lhs)
|
|
rhs = tostring(rhs)
|
|
level = (level or 1) + 1
|
|
|
|
error(lhs .. " == " .. rhs, level)
|
|
end
|
|
|
|
local function raw_invoke(func, ...)
|
|
return func(...)
|
|
end
|
|
|
|
local function assert_trap(func, ...)
|
|
if pcall(func, ...) then
|
|
local trace = debug.traceback("Failed to trap", 2)
|
|
|
|
io.stderr:write(trace, "\n")
|
|
end
|
|
end
|
|
|
|
local function assert_return(data, wanted)
|
|
for i, v in ipairs(wanted) do
|
|
assert_eq(data[i], v, 2)
|
|
end
|
|
end
|
|
|
|
local function assert_exhaustion(func, ...)
|
|
if pcall(func, ...) then
|
|
error("Failed to exhaust", 2)
|
|
end
|
|
end
|
|
|
|
linked.spectest = {
|
|
func_list = {
|
|
print = print,
|
|
print_f32 = print,
|
|
print_f64 = print,
|
|
print_f64_f64 = print,
|
|
print_i32 = print,
|
|
print_i32_f32 = print,
|
|
},
|
|
global_list = {
|
|
global_f32 = { value = 666 },
|
|
global_f64 = { value = 666 },
|
|
global_i32 = { value = 666 },
|
|
global_i64 = { value = 666LL },
|
|
},
|
|
table_list = { table = { data = {} } },
|
|
memory_list = { memory = rt.allocator.new(1, 2) },
|
|
}
|