Refactor Luau runtime

This commit is contained in:
Rerumu 2021-11-17 00:36:25 -05:00
parent 3e9bb2986b
commit 3cd41fbb08

View File

@ -1,26 +1,29 @@
local module = {}
local function no_op(x) return x end
do
local div = {}
module.div = div
function div.i32(lhs, rhs)
if rhs == 0 then error('division by zero') end
return math.floor(lhs / rhs)
end
end
do
local le = {}
local lt = {}
local ge = {}
local gt = {}
local band = {}
local bor = {}
local bxor = {}
local bnot = {}
local shl = {}
local shr = {}
local extend = {}
local wrap = {}
local load = {}
local store = {}
-- Helper functions
local function no_op(x) return x end
module.le = le
module.lt = lt
module.ge = ge
module.gt = gt
local function unsign_i32(x)
if x < 0 then x = x + 0x100000000 end
@ -34,6 +37,73 @@ local function unsign_i64(x)
return x
end
function ge.u32(lhs, rhs) return unsign_i32(lhs) >= unsign_i32(rhs) and 1 or 0 end
function ge.u64(lhs, rhs) return unsign_i64(lhs) >= unsign_i64(rhs) and 1 or 0 end
function gt.u32(lhs, rhs) return unsign_i32(lhs) > unsign_i32(rhs) and 1 or 0 end
function gt.u64(lhs, rhs) return unsign_i64(lhs) > unsign_i64(rhs) and 1 or 0 end
function le.u32(lhs, rhs) return unsign_i32(lhs) <= unsign_i32(rhs) and 1 or 0 end
function le.u64(lhs, rhs) return unsign_i64(lhs) <= unsign_i64(rhs) and 1 or 0 end
function lt.u32(lhs, rhs) return unsign_i32(lhs) < unsign_i32(rhs) and 1 or 0 end
function lt.u64(lhs, rhs) return unsign_i64(lhs) < unsign_i64(rhs) and 1 or 0 end
end
do
local band = {}
local bor = {}
local bxor = {}
local bnot = {}
module.band = band
module.bor = bor
module.bxor = bxor
module.bnot = bnot
band.i32 = bit32.band
band.i64 = bit32.band
bnot.i32 = bit32.bnot
bnot.i64 = bit32.bnot
bor.i32 = bit32.bor
bor.i64 = bit32.bor
bxor.i32 = bit32.bxor
bxor.i64 = bit32.bxor
end
do
local shl = {}
local shr = {}
module.shl = shl
module.shr = shr
shl.i32 = bit32.lshift
shl.i64 = bit32.lshift
shl.u32 = bit32.lshift
shl.u64 = bit32.lshift
shr.i32 = bit32.rshift
shr.i64 = bit32.rshift
shr.u32 = bit32.rshift
shr.u64 = bit32.rshift
end
do
local extend = {}
local wrap = {}
module.extend = extend
module.wrap = wrap
extend.i32_u64 = no_op
function wrap.i64_i32(i) return i % 2 ^ 32 end
end
do
local load = {}
local store = {}
module.load = load
module.store = store
local function rip_u64(x) return math.floor(x / 0x100000000), x % 0x100000000 end
local function merge_u64(hi, lo) return hi * 0x100000000 + lo end
@ -54,69 +124,13 @@ end
local function store_byte(memory, addr, value)
local offset = addr % 4
local adjust = (addr - offset) / 4
local lhs = bit32.lshift(value, offset * 8)
local lhs = bit32.lshift(bit32.band(value, 0xFF), offset * 8)
local rhs = black_mask_byte(memory.data[adjust] or 0, offset)
memory.data[adjust] = bit32.bor(lhs, rhs)
end
-- Runtime functions
local function grow_page_num(memory, num)
local old = memory.min
local new = old + num
if memory.max and new > memory.max then
return -1
else
memory.min = new
return old
end
end
function div.i32(lhs, rhs)
if rhs == 0 then error('division by zero') end
return math.floor(lhs / rhs)
end
function le.u32(lhs, rhs) return unsign_i32(lhs) <= unsign_i32(rhs) and 1 or 0 end
function lt.u32(lhs, rhs) return unsign_i32(lhs) < unsign_i32(rhs) and 1 or 0 end
function ge.u32(lhs, rhs) return unsign_i32(lhs) >= unsign_i32(rhs) and 1 or 0 end
function gt.u32(lhs, rhs) return unsign_i32(lhs) > unsign_i32(rhs) and 1 or 0 end
function le.u64(lhs, rhs) return unsign_i64(lhs) <= unsign_i64(rhs) and 1 or 0 end
function lt.u64(lhs, rhs) return unsign_i64(lhs) < unsign_i64(rhs) and 1 or 0 end
function ge.u64(lhs, rhs) return unsign_i64(lhs) >= unsign_i64(rhs) and 1 or 0 end
function gt.u64(lhs, rhs) return unsign_i64(lhs) > unsign_i64(rhs) and 1 or 0 end
band.i32 = bit32.band
bor.i32 = bit32.bor
bxor.i32 = bit32.bxor
bnot.i32 = bit32.bnot
band.i64 = bit32.band
bor.i64 = bit32.bor
bxor.i64 = bit32.bxor
bnot.i64 = bit32.bnot
shl.u32 = bit32.lshift
shr.u32 = bit32.rshift
shl.i32 = bit32.lshift
shr.i32 = bit32.rshift
shl.u64 = bit32.lshift
shr.u64 = bit32.rshift
shl.i64 = bit32.lshift
shr.i64 = bit32.rshift
extend.i32_u64 = no_op
function wrap.i64_i32(i) return i % 2 ^ 32 end
load.i32_u8 = load_byte
function load.i32(memory, addr)
if addr % 4 == 0 then
@ -133,12 +147,6 @@ function load.i32(memory, addr)
end
end
function load.i32_u8(memory, addr)
local value = load.i32(memory, addr)
return bit32.band(value, 0xFF)
end
function load.i64(memory, addr)
local hi = load.i32(memory, addr + 4)
local lo = load.i32(memory, addr)
@ -146,6 +154,8 @@ function load.i64(memory, addr)
return merge_u64(hi, lo)
end
store.i32_n8 = store_byte
function store.i32(memory, addr, value)
if addr % 4 == 0 then
-- aligned write
@ -159,30 +169,59 @@ function store.i32(memory, addr, value)
end
end
function store.i32_n8(memory, addr, value) store_byte(memory, addr, bit32.band(value, 0xFF)) end
function store.i64(memory, addr, value)
local hi, lo = rip_u64(value)
store.i32(memory, addr, lo)
store.i32(memory, addr + 4, hi)
end
end
return {
grow_page_num = grow_page_num,
div = div,
le = le,
lt = lt,
ge = ge,
gt = gt,
band = band,
bor = bor,
bxor = bxor,
bnot = bnot,
shl = shl,
shr = shr,
extend = extend,
wrap = wrap,
load = load,
store = store,
}
do
local memory = {}
module.memory = memory
function memory.new(min, max) return {min = min, max = max, data = {}} end
function memory.init(memory, offset, data)
local store_i8 = module.memory.store.i32_n8
local store_i32 = module.memory.store.i32
local len = #data
local rem = len % 4
if len >= 4 then
for i = 1, len, 4 do
local v = string.unpack('<I4', data, i)
store_i32(memory, offset + i - 1, v)
end
end
if rem ~= 0 then
for i = len - rem + 1, len do
local v = string.byte(data, i)
store_i8(memory, offset + i - 1, v)
end
end
end
function memory.size(memory) return memory.min end
function memory.grow(memory, num)
local old = memory.min
local new = old + num
if memory.max and new > memory.max then
return -1
else
memory.min = new
return old
end
end
end
return module