···11local intutil = {}
2233+function intutil.fromle16(tab, idx)
44+ local n = tab[idx]
55+ n = n | tab[idx+1] << 8
66+ return n
77+end
88+99+function intutil.tole16(tab, idx, n)
1010+ tab[idx] = n & 0xFF
1111+ tab[idx+1] = (n >> 8) & 0xFF
1212+end
1313+314function intutil.fromle32(tab, idx)
415 local n = tab[idx]
516 n = n | tab[idx+1] << 8
···4152function intutil.signexti32(n)
4253 if (n & 0x80000000) ~= 0 then
4354 n = n | 0xFFFFFFFF00000000
5555+ end
5656+ return n
5757+end
5858+5959+function intutil.signexti16(n)
6060+ if (n & 0x8000) ~= 0 then
6161+ n = n | 0xFFFFFFFFFFFF0000
6262+ end
6363+ return n
6464+end
6565+6666+function intutil.signexti8(n)
6767+ if (n & 0x80) ~= 0 then
6868+ n = n | 0xFFFFFFFFFFFFFF00
4469 end
4570 return n
4671end
+31
memory.lua
···11+local memory = {}
22+33+local constants = require("constants")
44+55+function memory.new(pages)
66+ local m = {
77+ mem = {},
88+ pages = pages,
99+ }
1010+ setmetatable(m, {
1111+ __index = function(self, key)
1212+ if key >= (self.pages * constants.WASM_PAGE_SIZE) then
1313+ error("out of bounds memory access")
1414+ end
1515+ return self.mem[key] or 0
1616+ end,
1717+ __newindex = function(self, key, value)
1818+ if key < (self.pages * constants.WASM_PAGE_SIZE) then
1919+ self.mem[key] = value
2020+ else
2121+ error("out of bounds memory access")
2222+ end
2323+ end,
2424+ __len = function(self)
2525+ return self.pages
2626+ end,
2727+ })
2828+ return m
2929+end
3030+3131+return memory
+14
ops.lua
···357357 return ((a >> c) | (a << (32 - c))) & constants.I32_MAX
358358end
359359360360+--[[ int conversions ]]
361361+362362+function ops.i32_wrap_i64(a)
363363+ return a & constants.I32_MAX
364364+end
365365+366366+function ops.i64_extend_i32_s(a)
367367+ return intutil.signexti32(a)
368368+end
369369+370370+function ops.i64_extend_i32_u(a)
371371+ return a
372372+end
373373+360374return ops
+237-35
wasmlib.lua
···1010 stackFrames = {},
1111 functions = {},
1212 types = {},
1313+ memory = {},
1414+ globals = {},
1315}
1414-1515-function wasmlib.VM:topFrame()
1616- return self.stackFrames[#self.stackFrames]
1717-end
18161917function wasmlib.VM:new()
2018 local vm = {}
···2220 return vm
2321end
24222323+function wasmlib.VM:topFrame()
2424+ return self.stackFrames[#self.stackFrames]
2525+end
2626+2527function wasmlib.VM:triop(f)
2628 local c = table.remove(self.stack)
2729 local b = table.remove(self.stack)
···4345function wasmlib.VM:readarg8()
4446 local curFrame = self.topFrame()
4547 local body = self.functions[curFrame.funcIndex].body
4646- local result = body[curFrame.pc + 1]
4848+ local result = body[curFrame.pc]
4749 curFrame.pc = curFrame.pc + 1
4850 return result
4951end
···5153function wasmlib.VM:readarg32()
5254 local curFrame = self:topFrame()
5355 local body = self.functions[curFrame.funcIndex].body
5454- local result = intutil.fromle32(body, curFrame.pc + 1)
5656+ local result = intutil.fromle32(body, curFrame.pc)
5557 curFrame.pc = curFrame.pc + 4
5658 return result
5759end
58606161+function wasmlib.VM:readarg64()
6262+ local curFrame = self:topFrame()
6363+ local body = self.functions[curFrame.funcIndex].body
6464+ local result = intutil.fromle64(body, curFrame.pc)
6565+ curFrame.pc = curFrame.pc + 8
6666+ return result
6767+end
6868+5969function wasmlib.VM:local_get()
6070 local curFrame = self:topFrame()
6171 local localIdx = self:readarg32()
···7383 curFrame.locals[localIdx] = localVal
7484end
75858686+function wasmlib.VM:local_tee()
8787+ local curFrame = self:topFrame()
8888+ local localIdx = self:readarg32()
8989+ local localVal = self.stack[#self.stack]
9090+ curFrame.locals[localIdx] = localVal
9191+end
9292+9393+function wasmlib.VM:global_get()
9494+ local globalIdx = self:readarg32()
9595+ local globalVal = self.globals[globalIdx]
9696+ if globalVal == nil then
9797+ error("read invalid global")
9898+ end
9999+ table.insert(self.stack, globalVal)
100100+end
101101+102102+function wasmlib.VM:global_set()
103103+ local globalIdx = self:readarg32()
104104+ local globalVal = table.remove(self.stack)
105105+ self.globals[globalIdx] = globalVal
106106+end
107107+76108function wasmlib.VM:call()
77109 local funcIdx = self:readarg32()
78110 self:invoke(funcIdx)
79111end
80112113113+function wasmlib.VM:memory_size()
114114+ self:readarg8() -- always zero in WASM 1.0
115115+ return #self.memory
116116+end
117117+118118+function wasmlib.VM:memory_grow()
119119+ self:readarg8() -- always zero in WASM 1.0
120120+ local amount = table.remove(self.stack)
121121+ if (
122122+ (self.memory.maxpages ~= nil) and (#self.memory + amount > self.memory.maxpages)
123123+ ) or (#self.memory + amount > constants.I32_MAX)
124124+ then
125125+ table.insert(self.stack, constants.I32_MAX) -- i32 -1
126126+ else
127127+ self.memory.pages = #self.memory + amount
128128+ table.insert(self.stack, #self.memory)
129129+ end
130130+end
131131+132132+function wasmlib.VM:i32_load()
133133+ self:readarg32() -- alignment, ignored for now
134134+ local offset = self:readarg32()
135135+ local value = intutil.fromle32(self.memory, offset)
136136+ table.insert(self.stack, value)
137137+end
138138+139139+function wasmlib.VM:i64_load()
140140+ self:readarg32() -- alignment, ignored for now
141141+ local offset = self:readarg32()
142142+ local value = intutil.fromle64(self.memory, offset)
143143+ table.insert(self.stack, value)
144144+end
145145+146146+function wasmlib.VM:i32_load8_s()
147147+ self:readarg32() -- alignment, ignored for now
148148+ local offset = self:readarg32()
149149+ local value = intutil.signexti8(self.memory[offset]) & constants.I32_MAX
150150+ table.insert(self.stack, value)
151151+end
152152+153153+function wasmlib.VM:i32_load8_u()
154154+ self:readarg32() -- alignment, ignored for now
155155+ local offset = self:readarg32()
156156+ local value = self.memory[offset]
157157+ table.insert(self.stack, value)
158158+end
159159+160160+function wasmlib.VM:i32_load16_s()
161161+ self:readarg32() -- alignment, ignored for now
162162+ local offset = self:readarg32()
163163+ local value = intutil.signexti16(intutil.fromle16(self.memory, offset)) & constants.I32_MAX
164164+ table.insert(self.stack, value)
165165+end
166166+167167+function wasmlib.VM:i32_load16_u()
168168+ self:readarg32() -- alignment, ignored for now
169169+ local offset = self:readarg32()
170170+ local value = intutil.fromle16(self.memory, offset)
171171+ table.insert(self.stack, value)
172172+end
173173+174174+function wasmlib.VM:i64_load8_s()
175175+ self:readarg32() -- alignment, ignored for now
176176+ local offset = self:readarg32()
177177+ local value = intutil.signexti8(self.memory[offset])
178178+ table.insert(self.stack, value)
179179+end
180180+181181+function wasmlib.VM:i64_load8_u()
182182+ self:readarg32() -- alignment, ignored for now
183183+ local offset = self:readarg32()
184184+ local value = self.memory[offset]
185185+ table.insert(self.stack, value)
186186+end
187187+188188+function wasmlib.VM:i64_load16_s()
189189+ self:readarg32() -- alignment, ignored for now
190190+ local offset = self:readarg32()
191191+ local value = intutil.signexti16(intutil.fromle16(self.memory, offset))
192192+ table.insert(self.stack, value)
193193+end
194194+195195+function wasmlib.VM:i64_load16_u()
196196+ self:readarg32() -- alignment, ignored for now
197197+ local offset = self:readarg32()
198198+ local value = intutil.fromle16(self.memory, offset)
199199+ table.insert(self.stack, value)
200200+end
201201+202202+function wasmlib.VM:i64_load32_s()
203203+ self:readarg32() -- alignment, ignored for now
204204+ local offset = self:readarg32()
205205+ local value = intutil.signexti32(intutil.fromle32(self.memory, offset))
206206+ table.insert(self.stack, value)
207207+end
208208+209209+function wasmlib.VM:i64_load32_u()
210210+ self:readarg32() -- alignment, ignored for now
211211+ local offset = self:readarg32()
212212+ local value = intutil.fromle32(self.memory, offset)
213213+ table.insert(self.stack, value)
214214+end
215215+216216+function wasmlib.VM:i64_load()
217217+ self:readarg32() -- alignment, ignored for now
218218+ local offset = self:readarg32()
219219+ local value = intutil.signexti16(intutil.fromle16(self.memory, offset))
220220+ table.insert(self.stack, value)
221221+end
222222+223223+function wasmlib.VM:i32_store()
224224+ self:readarg32() -- alignment, ignored for now
225225+ local offset = self:readarg32()
226226+ local value = table.remove(self.stack)
227227+ intutil.tole32(self.memory, offset, value)
228228+end
229229+230230+function wasmlib.VM:i64_store()
231231+ self:readarg32() -- alignment, ignored for now
232232+ local offset = self:readarg32()
233233+ local value = table.remove(self.stack)
234234+ intutil.tole64(self.memory, offset, value)
235235+end
236236+237237+function wasmlib.VM:i32_store8()
238238+ self:readarg32() -- alignment, ignored for now
239239+ local offset = self:readarg32()
240240+ local value = table.remove(self.stack)
241241+ self.memory[offset] = value & 0xFF
242242+end
243243+244244+function wasmlib.VM:i32_store16()
245245+ self:readarg32() -- alignment, ignored for now
246246+ local offset = self:readarg32()
247247+ local value = table.remove(self.stack)
248248+ intutil.tole16(self.memory, offset, value)
249249+end
250250+251251+function wasmlib.VM:i64_store8()
252252+ self:readarg32() -- alignment, ignored for now
253253+ local offset = self:readarg32()
254254+ local value = table.remove(self.stack)
255255+ self.memory[offset] = value & 0xFF
256256+end
257257+258258+function wasmlib.VM:i64_store16()
259259+ self:readarg32() -- alignment, ignored for now
260260+ local offset = self:readarg32()
261261+ local value = table.remove(self.stack)
262262+ intutil.tole16(self.memory, offset, value)
263263+end
264264+265265+function wasmlib.VM:i64_store32()
266266+ self:readarg32() -- alignment, ignored for now
267267+ local offset = self:readarg32()
268268+ local value = table.remove(self.stack)
269269+ intutil.tole32(self.memory, offset, value)
270270+end
271271+272272+function wasmlib.VM:i32_const()
273273+ table.insert(self.stack, self:readarg32())
274274+end
275275+276276+function wasmlib.VM:i64_const()
277277+ table.insert(self.stack, self:readarg64())
278278+end
279279+81280function wasmlib.VM:step()
82281 local curFrame = self:topFrame()
83282 local body = self.functions[curFrame.funcIndex].body
84283 local opcode = body[curFrame.pc]
284284+ curFrame.pc = curFrame.pc + 1
8528586286 local c = constants.opcodes
87287 local optable = {
···105305 -- variable
106306 [c.OP_LOCAL_GET] = function() self:local_get() end,
107307 [c.OP_LOCAL_SET] = function() self:local_set() end,
108108- -- LOCAL_TEE
109109- -- GLOBAL_GET
110110- -- GLOBAL_SET
308308+ [c.OP_LOCAL_TEE] = function() self:local_tee() end,
309309+ [c.OP_GLOBAL_GET] = function() self:global_get() end,
310310+ [c.OP_GLOBAL_SET] = function() self:global_set() end,
111311 -- memory
112112- -- I32_LOAD
113113- -- I64_LOAD
312312+ [c.OP_I32_LOAD] = function() self:i32_load() end,
313313+ [c.OP_I64_LOAD] = function() self:i64_load() end,
114314 -- [float instrs]
115115- -- I32_LOAD8_S
116116- -- I32_LOAD8_U
117117- -- I32_LOAD16_S
118118- -- I32_LOAD16_U
119119- -- I64_LOAD8_S
120120- -- I64_LOAD8_U
121121- -- I64_LOAD16_S
122122- -- I64_LOAD16_U
123123- -- I64_LOAD32_S
124124- -- I64_LOAD32_U
125125- -- I32_STORE
126126- -- I64_STORE
315315+ [c.OP_I32_LOAD8_S] = function() self:i32_load8_s() end,
316316+ [c.OP_I32_LOAD8_U] = function() self:i32_load8_u() end,
317317+ [c.OP_I32_LOAD16_S] = function() self:i32_load16_s() end,
318318+ [c.OP_I32_LOAD16_U] = function() self:i32_load16_u() end,
319319+ [c.OP_I64_LOAD8_S] = function() self:i64_load8_s() end,
320320+ [c.OP_I64_LOAD8_U] = function() self:i64_load8_u() end,
321321+ [c.OP_I64_LOAD16_S] = function() self:i64_load16_s() end,
322322+ [c.OP_I64_LOAD16_U] = function() self:i64_load16_u() end,
323323+ [c.OP_I64_LOAD32_S] = function() self:i64_load32_s() end,
324324+ [c.OP_I64_LOAD32_U] = function() self:i64_load32_u() end,
325325+ [c.OP_I32_STORE] = function() self:i32_store() end,
326326+ [c.OP_I64_STORE] = function() self:i64_store() end,
127327 -- [floart instrs]
128128- -- I32_STORE8
129129- -- I32_STORE16
130130- -- I64_STORE8
131131- -- I64_STORE16
132132- -- I64_STORE32
133133- -- MEMORY_SIZE
134134- -- MEMORY_GROW
328328+ [c.OP_I32_STORE8] = function() self:i32_store8() end,
329329+ [c.OP_I32_STORE16] = function() self:i32_store16() end,
330330+ [c.OP_I64_STORE8] = function() self:i64_store8() end,
331331+ [c.OP_I64_STORE16] = function() self:i64_store16() end,
332332+ [c.OP_I64_STORE32] = function() self:i64_store32() end,
333333+ [c.OP_MEMORY_SIZE] = function() self:memory_size() end,
334334+ [c.OP_MEMORY_GROW] = function() self:memory_grow() end,
335335+ -- constants
336336+ [c.OP_I32_CONST] = function() self:i32_const() end,
337337+ [c.OP_I64_CONST] = function() self:i64_const() end,
338338+ -- [float consts]
135339 -- i32 comparisons
136340 [c.OP_I32_EQZ] = function() self:unop (ops.i32_eqz) end,
137341 [c.OP_I32_EQ] = function() self:binop(ops.i32_eq) end,
···195399 [c.OP_I64_ROTR] = function() self:binop(ops.i64_rotr) end,
196400 -- [float operations]
197401 -- conversions
198198- -- I32_WRAP_I64
402402+ [c.OP_I32_WRAP_I64] = function() self:unop(ops.i32_wrap_i64) end,
199403 -- [float stuff]
200200- -- I64_EXTEND_I32_S
201201- -- I64_EXTEND_I32_U
404404+ [c.OP_I64_EXTEND_I32_S] = function() self:unop(ops.i64_extend_i32_s) end,
405405+ [c.OP_I64_EXTEND_I32_U] = function() self:unop(ops.i64_extend_i32_u) end,
202406 -- [float stuff]
203407 }
204408···207411 error("unimplemented")
208412 end
209413 opfunc()
210210-211211- curFrame.pc = curFrame.pc + 1
212414end
213415214416function wasmlib.VM:invoke(funcIndex)