···11+local fileutil = {}
22+33+function fileutil.readBytes(path)
44+ local file = assert(io.open(path, "rb"))
55+ local bytes = {}
66+77+ repeat
88+ local s = file:read(4096)
99+ for c in (s or ""):gmatch(".") do
1010+ table.insert(bytes, c:byte())
1111+ end
1212+ until not s
1313+ file:close()
1414+ return bytes
1515+end
1616+1717+return fileutil
+1-1
frame.lua
···33frame.StackFrame = {
44 funcIndex = 0,
55 locals = {},
66- pc = 1, -- program counter
66+ pc = 0, -- program counter
77}
8899function frame.StackFrame:new(funcIndex)
+32
intutil.lua
···7070 return n
7171end
72727373+function intutil.fromuleb128(tab, idx)
7474+ local result = 0
7575+ local shift = 0
7676+ local len = 0
7777+ repeat
7878+ local byte = tab[idx+len]
7979+ result = result | ((byte & 0x7F) << shift)
8080+ shift = shift + 7
8181+ len = len + 1
8282+ until (byte & 0x80) == 0
8383+ return len, result
8484+end
8585+8686+function intutil.fromsleb128(tab, idx, bits)
8787+ bits = bits or 64
8888+ local result = 0
8989+ local shift = 0
9090+ local len = 0
9191+9292+ repeat
9393+ local byte = tab[idx+len]
9494+ result = result | ((byte & 0x7F) << shift)
9595+ shift = shift + 7
9696+ len = len + 1
9797+ until (byte & 0x80) == 0
9898+9999+ if (shift < bits) and ((tab[idx+len-1] & 0x40) ~= 0) then
100100+ result = result | (((1 << bits) - 1) << shift)
101101+ end
102102+ return len, result
103103+end
104104+73105return intutil
+433-118
wasmlib.lua
···33local constants = require("constants")
44local ops = require("ops")
55local frame = require("frame")
66+local memory = require("memory")
67local intutil = require("intutil")
88+local fileutil = require("fileutil")
79810wasmlib.VM = {
911 stack = {},
···2123 return vm
2224end
23252424-function wasmlib.VM:topFrame()
2626+function wasmlib.VM:curFrame()
2527 return self.stackFrames[#self.stackFrames]
2628end
27293030+function wasmlib.VM:curBody()
3131+ return self.functions[self:curFrame().funcIndex].body
3232+end
3333+3434+function wasmlib.VM:curLocals()
3535+ return self:curFrame().locals
3636+end
3737+2838function wasmlib.VM:triop(f)
2939 local c = table.remove(self.stack)
3040 local b = table.remove(self.stack)
···4353 table.insert(self.stack, f(a))
4454end
45554646-function wasmlib.VM:readarg8()
4747- local curFrame = self:topFrame()
4848- local body = self.functions[curFrame.funcIndex].body
4949- local result = body[curFrame.pc]
5656+function wasmlib.VM:nextArg()
5757+ local curFrame = self:curFrame()
5058 curFrame.pc = curFrame.pc + 1
5151- return result
5252-end
5353-5454-function wasmlib.VM:readarg32()
5555- local curFrame = self:topFrame()
5656- local body = self.functions[curFrame.funcIndex].body
5757- local result = intutil.fromle32(body, curFrame.pc)
5858- curFrame.pc = curFrame.pc + 4
5959- return result
6060-end
6161-6262-function wasmlib.VM:readarg64()
6363- local curFrame = self:topFrame()
6464- local body = self.functions[curFrame.funcIndex].body
6565- local result = intutil.fromle64(body, curFrame.pc)
6666- curFrame.pc = curFrame.pc + 8
6767- return result
5959+ return self:curBody()[curFrame.pc]
6860end
69617062function wasmlib.VM:local_get()
7171- local curFrame = self:topFrame()
7272- local localIdx = self:readarg32()
7373- local localVal = curFrame.locals[localIdx]
6363+ local localIdx = self:nextArg()
6464+ local localVal = self:curLocals()[localIdx]
7465 if localVal == nil then
7566 error("read uninitialised or out of bounds local")
7667 end
···7869end
79708071function wasmlib.VM:local_set()
8181- local curFrame = self:topFrame()
8282- local localIdx = self:readarg32()
7272+ local localIdx = self:nextArg()
8373 local localVal = table.remove(self.stack)
8484- curFrame.locals[localIdx] = localVal
7474+ self:curFrame().locals[localIdx] = localVal
8575end
86768777function wasmlib.VM:local_tee()
8888- local curFrame = self:topFrame()
8989- local localIdx = self:readarg32()
7878+ local localIdx = self:nextArg()
9079 local localVal = self.stack[#self.stack]
9191- curFrame.locals[localIdx] = localVal
8080+ self:curFrame().locals[localIdx] = localVal
9281end
93829483function wasmlib.VM:global_get()
9595- local globalIdx = self:readarg32()
8484+ local globalIdx = self:nextArg()
9685 local globalVal = self.globals[globalIdx]
9786 if globalVal == nil then
9887 error("read invalid global")
···10190end
1029110392function wasmlib.VM:global_set()
104104- local globalIdx = self:readarg32()
9393+ local globalIdx = self:nextArg()
10594 local globalVal = table.remove(self.stack)
10695 self.globals[globalIdx] = globalVal
10796end
1089710998function wasmlib.VM:call()
110110- local funcIdx = self:readarg32()
9999+ local funcIdx = self:nextArg()
111100 self:invoke(funcIdx)
112101end
113102114103function wasmlib.VM:memory_size()
115115- self:readarg8() -- always zero in WASM 1.0
104104+ if self:nextArg() ~= 0 then
105105+ error("memory.size operand must be zero")
106106+ end
107107+116108 return #self.memory
117109end
118110119111function wasmlib.VM:memory_grow()
120120- self:readarg8() -- always zero in WASM 1.0
112112+ if self:nextArg() ~= 0 then
113113+ error("memory.grow operand must be zero")
114114+ end
115115+121116 local amount = table.remove(self.stack)
122117 if (
123118 (self.memory.maxpages ~= nil) and (#self.memory + amount > self.memory.maxpages)
···131126end
132127133128function wasmlib.VM:i32_load()
134134- self:readarg32() -- alignment, ignored for now
135135- local offset = self:readarg32()
129129+ self:nextArg() -- alignment, ignored for now
130130+ local offset = self:nextArg()
136131 local argument = table.remove(self.stack)
137132 local value = intutil.fromle32(self.memory, offset + argument)
138133 table.insert(self.stack, value)
139134end
140135141136function wasmlib.VM:i64_load()
142142- self:readarg32() -- alignment, ignored for now
143143- local offset = self:readarg32()
137137+ self:nextArg() -- alignment, ignored for now
138138+ local offset = self:nextArg()
144139 local argument = table.remove(self.stack)
145140 local value = intutil.fromle64(self.memory, offset + argument)
146141 table.insert(self.stack, value)
147142end
148143149144function wasmlib.VM:i32_load8_s()
150150- self:readarg32() -- alignment, ignored for now
151151- local offset = self:readarg32()
145145+ self:nextArg() -- alignment, ignored for now
146146+ local offset = self:nextArg()
152147 local argument = table.remove(self.stack)
153148 local value = intutil.signexti8(self.memory[offset + argument]) & constants.I32_MAX
154149 table.insert(self.stack, value)
155150end
156151157152function wasmlib.VM:i32_load8_u()
158158- self:readarg32() -- alignment, ignored for now
159159- local offset = self:readarg32()
153153+ self:nextArg() -- alignment, ignored for now
154154+ local offset = self:nextArg()
160155 local argument = table.remove(self.stack)
161156 local value = self.memory[offset + argument]
162157 table.insert(self.stack, value)
163158end
164159165160function wasmlib.VM:i32_load16_s()
166166- self:readarg32() -- alignment, ignored for now
167167- local offset = self:readarg32()
161161+ self:nextArg() -- alignment, ignored for now
162162+ local offset = self:nextArg()
168163 local argument = table.remove(self.stack)
169164 local value = intutil.signexti16(intutil.fromle16(self.memory, offset + argument)) & constants.I32_MAX
170165 table.insert(self.stack, value)
171166end
172167173168function wasmlib.VM:i32_load16_u()
174174- self:readarg32() -- alignment, ignored for now
175175- local offset = self:readarg32()
169169+ self:nextArg() -- alignment, ignored for now
170170+ local offset = self:nextArg()
176171 local argument = table.remove(self.stack)
177172 local value = intutil.fromle16(self.memory, offset + argument)
178173 table.insert(self.stack, value)
179174end
180175181176function wasmlib.VM:i64_load8_s()
182182- self:readarg32() -- alignment, ignored for now
183183- local offset = self:readarg32()
177177+ self:nextArg() -- alignment, ignored for now
178178+ local offset = self:nextArg()
184179 local argument = table.remove(self.stack)
185180 local value = intutil.signexti8(self.memory[offset + argument])
186181 table.insert(self.stack, value)
187182end
188183189184function wasmlib.VM:i64_load8_u()
190190- self:readarg32() -- alignment, ignored for now
191191- local offset = self:readarg32()
185185+ self:nextArg() -- alignment, ignored for now
186186+ local offset = self:nextArg()
192187 local argument = table.remove(self.stack)
193188 local value = self.memory[offset + argument]
194189 table.insert(self.stack, value)
195190end
196191197192function wasmlib.VM:i64_load16_s()
198198- self:readarg32() -- alignment, ignored for now
199199- local offset = self:readarg32()
193193+ self:nextArg() -- alignment, ignored for now
194194+ local offset = self:nextArg()
200195 local argument = table.remove(self.stack)
201196 local value = intutil.signexti16(intutil.fromle16(self.memory, offset + argument))
202197 table.insert(self.stack, value)
203198end
204199205200function wasmlib.VM:i64_load16_u()
206206- self:readarg32() -- alignment, ignored for now
207207- local offset = self:readarg32()
201201+ self:nextArg() -- alignment, ignored for now
202202+ local offset = self:nextArg()
208203 local argument = table.remove(self.stack)
209204 local value = intutil.fromle16(self.memory, offset + argument)
210205 table.insert(self.stack, value)
211206end
212207213208function wasmlib.VM:i64_load32_s()
214214- self:readarg32() -- alignment, ignored for now
215215- local offset = self:readarg32()
209209+ self:nextArg() -- alignment, ignored for now
210210+ local offset = self:nextArg()
216211 local argument = table.remove(self.stack)
217212 local value = intutil.signexti32(intutil.fromle32(self.memory, offset + argument))
218213 table.insert(self.stack, value)
219214end
220215221216function wasmlib.VM:i64_load32_u()
222222- self:readarg32() -- alignment, ignored for now
223223- local offset = self:readarg32()
217217+ self:nextArg() -- alignment, ignored for now
218218+ local offset = self:nextArg()
224219 local argument = table.remove(self.stack)
225220 local value = intutil.fromle32(self.memory, offset + argument)
226221 table.insert(self.stack, value)
227222end
228223229224function wasmlib.VM:i64_load()
230230- self:readarg32() -- alignment, ignored for now
231231- local offset = self:readarg32()
225225+ self:nextArg() -- alignment, ignored for now
226226+ local offset = self:nextArg()
232227 local argument = table.remove(self.stack)
233228 local value = intutil.signexti16(intutil.fromle16(self.memory, offset + argument))
234229 table.insert(self.stack, value)
235230end
236231237232function wasmlib.VM:i32_store()
238238- self:readarg32() -- alignment, ignored for now
239239- local offset = self:readarg32()
233233+ self:nextArg() -- alignment, ignored for now
234234+ local offset = self:nextArg()
240235 local argument = table.remove(self.stack)
241236 local value = table.remove(self.stack)
242237 intutil.tole32(self.memory, offset + argument, value)
243238end
244239245240function wasmlib.VM:i64_store()
246246- self:readarg32() -- alignment, ignored for now
247247- local offset = self:readarg32()
241241+ self:nextArg() -- alignment, ignored for now
242242+ local offset = self:nextArg()
248243 local argument = table.remove(self.stack)
249244 local value = table.remove(self.stack)
250245 intutil.tole64(self.memory, offset + argument, value)
251246end
252247253248function wasmlib.VM:i32_store8()
254254- self:readarg32() -- alignment, ignored for now
255255- local offset = self:readarg32()
249249+ self:nextArg() -- alignment, ignored for now
250250+ local offset = self:nextArg()
256251 local argument = table.remove(self.stack)
257252 local value = table.remove(self.stack)
258253 self.memory[offset + argument] = value & 0xFF
259254end
260255261256function wasmlib.VM:i32_store16()
262262- self:readarg32() -- alignment, ignored for now
263263- local offset = self:readarg32()
257257+ self:nextArg() -- alignment, ignored for now
258258+ local offset = self:nextArg()
264259 local argument = table.remove(self.stack)
265260 local value = table.remove(self.stack)
266261 intutil.tole16(self.memory, offset + argument, value)
267262end
268263269264function wasmlib.VM:i64_store8()
270270- self:readarg32() -- alignment, ignored for now
271271- local offset = self:readarg32()
265265+ self:nextArg() -- alignment, ignored for now
266266+ local offset = self:nextArg()
272267 local argument = table.remove(self.stack)
273268 local value = table.remove(self.stack)
274269 self.memory[offset + argument] = value & 0xFF
275270end
276271277272function wasmlib.VM:i64_store16()
278278- self:readarg32() -- alignment, ignored for now
279279- local offset = self:readarg32()
273273+ self:nextArg() -- alignment, ignored for now
274274+ local offset = self:nextArg()
280275 local argument = table.remove(self.stack)
281276 local value = table.remove(self.stack)
282277 intutil.tole16(self.memory, offset + argument, value)
283278end
284279285280function wasmlib.VM:i64_store32()
286286- self:readarg32() -- alignment, ignored for now
287287- local offset = self:readarg32()
281281+ self:nextArg() -- alignment, ignored for now
282282+ local offset = self:nextArg()
288283 local argument = table.remove(self.stack)
289284 local value = table.remove(self.stack)
290285 intutil.tole32(self.memory, offset + argument, value)
291286end
292287293288function wasmlib.VM:i32_const()
294294- table.insert(self.stack, self:readarg32())
289289+ table.insert(self.stack, self:nextArg())
295290end
296291297292function wasmlib.VM:i64_const()
298298- table.insert(self.stack, self:readarg64())
293293+ table.insert(self.stack, self:nextArg())
299294end
300295301296function wasmlib.VM:invoke(funcIndex)
302302- local fr = frame.StackFrame:new(funcIndex)
303297 local f = self.functions[funcIndex]
304298 local sig = self.types[f.typeidx]
305299306306- -- NOTE: sig.arguments is zero-indexed, so #sig.arguments is one less than the real length
307300 if f.import ~= nil then
308301 local args = {}
309309- for i = 1, #sig.arguments + 1 do
310310- args[#sig.arguments + 2 - i] = table.remove(self.stack)
302302+ for i = 1, #sig.arguments do
303303+ args[#sig.arguments + 1 - i] = table.remove(self.stack)
311304 end
312305 local ret = f.import(table.unpack(args))
313306 if sig.ret ~= nil then
···316309 return
317310 end
318311319319- for i = 1, #sig.arguments + 1 do
312312+ local fr = frame.StackFrame:new(funcIndex)
313313+ for i = 1, #sig.arguments do
320314 fr.locals[#sig.arguments + 1 - i] = table.remove(self.stack)
321315 end
322316 table.insert(self.stackFrames, fr)
···328322329323-- Get the index of the next occurence of the instruction with opcode `target`
330324-- starting from `i` at the same level of nesting
331331-function wasmlib.VM:findMatchingEndOrElse(i, depth)
325325+local function findMatchingEndOrElse(body, i, depth)
332326 depth = depth or 0
333333- local curFrame = self:topFrame()
334334- local body = self.functions[curFrame.funcIndex].body
335327 repeat
336328 local opcode = body[i]
337329 local length = constants.ilengths[opcode]
338330 if length == 0 then
339339- if (opcode == constants.opcodes.OP_BLOCK)
340340- or (opcode == constants.opcodes.OP_LOOP)
341341- or (opcode == constants.opcodes.OP_IF)
342342- then
343343- i = self:findMatchingEndOrElse(i + 1, depth + 1) + (depth > 0 and 1 or 0)
331331+ if constants.blockOpcodes[opcode] ~= nil then
332332+ i = findMatchingEndOrElse(body, i + 1, depth + 1) + (depth > 0 and 1 or 0)
344333 elseif opcode == constants.opcodes.OP_ELSE then
345334 i = i + 1
346346- elseif opcode == constants.opcodes.OP_BR_TABLE then
347347- local vecLen = intutil.fromle32(body, i + 1)
348348- i = i + (1 + 4 * (vecLen + 1)) -- 1 byte opcode, (vecLen + 1) 4-byte label indices
349335 end
350336 else
351337 i = i + length
···355341end
356342357343function wasmlib.VM:block()
358358- local curFrame = self:topFrame()
344344+ local curFrame = self:curFrame()
359345 local startIdx = curFrame.pc - 1 -- pc has already been incremented in step
360360- self:readarg8() -- block result type, ignored for now
361361- local endIdx = self:findMatchingEndOrElse(startIdx)
346346+ self:nextArg() -- block result type, ignored for now
347347+ local endIdx = findMatchingEndOrElse(self:curBody(), startIdx)
362348 table.insert(self.labelStack, endIdx)
363349end
364350365351function wasmlib.VM:loop()
366366- local curFrame = self:topFrame()
352352+ local curFrame = self:curFrame()
367353 local startIdx = curFrame.pc - 1 -- pc has already been incremented in step
368368- self:readarg8() -- block result type, ignored for now
354354+ self:nextArg() -- block result type, ignored for now
369355 table.insert(self.labelStack, startIdx)
370356end
371357372358function wasmlib.VM:_if()
373373- self:readarg8() -- block result type, ignored for now
359359+ self:nextArg() -- block result type, ignored for now
374360 local c = table.remove(self.stack)
375375- local curFrame = self:topFrame()
361361+ local curFrame = self:curFrame()
376362 local body = self.functions[curFrame.funcIndex].body
377377- local endOrElse = self:findMatchingEndOrElse(curFrame.pc - 1) -- pc has already been incremented in step
363363+ local endOrElse = findMatchingEndOrElse(body, curFrame.pc - 1) -- pc has already been incremented in step
378364379365 if body[endOrElse] == constants.opcodes.OP_ELSE then
380366 local elseIdx = endOrElse
381381- local endIdx = self:findMatchingEndOrElse(endOrElse)
367367+ local endIdx = findMatchingEndOrElse(body, endOrElse)
382368 if c == 0 then
383369 curFrame.pc = elseIdx
384370 end
···398384 for _ = 1, labelIdx + 1 do
399385 table.remove(self.labelStack)
400386 end
401401- self:topFrame().pc = label
387387+ self:curFrame().pc = label
402388end
403389404390function wasmlib.VM:br()
405405- local labelIdx = self:readarg32()
391391+ local labelIdx = self:nextArg()
406392 self:brInner(labelIdx)
407393end
408394409395function wasmlib.VM:br_if()
410410- local labelIdx = self:readarg32()
396396+ local labelIdx = self:nextArg()
411397 local c = table.remove(self.stack)
412398 if c ~= 0 then
413399 self:brInner(labelIdx)
···415401end
416402417403function wasmlib.VM:br_table()
418418- local curFrame = self:topFrame()
419419- local body = self.functions[curFrame.funcIndex].body
420420- local vLen = self:readarg32()
404404+ local table = self:nextArg()
405405+ local other = self:nextArg()
421406 local i = table.remove(self.stack)
422407423423- if i < vLen then
424424- local labelIdx = intutil.fromle32(body, curFrame.pc + i * 4)
425425- self:brInner(labelIdx)
408408+ if i < #table then
409409+ self:brInner(table[i + 1])
426410 else
427427- local labelIdx = intutil.fromle32(body, curFrame.pc + vLen * 4)
428428- self:brInner(labelIdx)
411411+ self:brInner(other)
429412 end
430413end
431414432415function wasmlib.VM:step()
433433- local curFrame = self:topFrame()
434434- local body = self.functions[curFrame.funcIndex].body
435435- local opcode = body[curFrame.pc]
436436- curFrame.pc = curFrame.pc + 1
416416+ local opcode = self:nextArg()
437417438418 local c = constants.opcodes
439419 local optable = {
···563543 error("unimplemented")
564544 end
565545 opfunc()
546546+end
547547+548548+--[[ Binary format parsing ]]
549549+550550+local function checkMagic(bytes, idx)
551551+ if (bytes[idx ] ~= 0x00)
552552+ or (bytes[idx+1] ~= 0x61)
553553+ or (bytes[idx+2] ~= 0x73)
554554+ or (bytes[idx+3] ~= 0x6D)
555555+ then
556556+ error("invalid magic")
557557+ end
558558+ return idx + 4
559559+end
560560+561561+local function checkVersion(bytes, idx)
562562+ if (bytes[idx ] ~= 0x01)
563563+ or (bytes[idx+1] ~= 0x00)
564564+ or (bytes[idx+2] ~= 0x00)
565565+ or (bytes[idx+3] ~= 0x00)
566566+ then
567567+ error("invalid format version")
568568+ end
569569+ return idx + 4
570570+end
571571+572572+function wasmlib.VM:parseCustom(bytes, idx)
573573+ -- ignore custom sections
574574+ local szlen, size = intutil.fromuleb128(bytes, idx)
575575+ return idx + szlen + size
576576+end
577577+578578+function wasmlib.VM:parseTypes(bytes, idx)
579579+ local szlen, _ = intutil.fromuleb128(bytes, idx)
580580+ idx = idx + szlen
581581+ local ntlen, numTypes = intutil.fromuleb128(bytes, idx)
582582+ idx = idx + ntlen
583583+584584+ for i = 1, numTypes do
585585+ if bytes[idx] ~= 0x60 then
586586+ error("types section contained a type that is not a function type")
587587+ end
588588+ idx = idx + 1
589589+590590+ local type = {}
591591+592592+ local nalen, numArgs = intutil.fromuleb128(bytes, idx)
593593+ idx = idx + nalen
594594+ type.arguments = {}
595595+ for j = 1, numArgs do
596596+ type.arguments[j] = bytes[idx]
597597+ idx = idx + 1
598598+ end
599599+600600+ local nrlen, numReturns = intutil.fromuleb128(bytes, idx)
601601+ idx = idx + nrlen
602602+ if numReturns > 1 then
603603+ error("more than 1 return value")
604604+ elseif numReturns == 1 then
605605+ type.ret = bytes[idx]
606606+ idx = idx + 1
607607+ end
608608+609609+ self.types[i] = type
610610+ end
611611+612612+ return idx
613613+end
614614+615615+function wasmlib.VM:parseImports(bytes, idx) -- TODO
616616+ print("warning: skipping imports section")
617617+ local szlen, size = intutil.fromuleb128(bytes, idx)
618618+ return idx + szlen + size
619619+end
620620+621621+function wasmlib.VM:parseFunctions(bytes, idx)
622622+ local szlen, _ = intutil.fromuleb128(bytes, idx)
623623+ idx = idx + szlen
624624+ local nflen, numFuncs = intutil.fromuleb128(bytes, idx)
625625+ idx = idx + nflen
626626+627627+ for i = 1, numFuncs do -- TODO handle imported functions
628628+ local tilen, typeidx = intutil.fromuleb128(bytes, idx)
629629+ idx = idx + tilen
630630+ self.functions[i] = { typeidx = typeidx }
631631+ end
632632+633633+ return idx
634634+end
635635+636636+function wasmlib.VM:parseTables(bytes, idx) -- TODO
637637+ print("warning: skipping tables section")
638638+ local szlen, size = intutil.fromuleb128(bytes, idx)
639639+ return idx + szlen + size
640640+end
641641+642642+function wasmlib.VM:parseMemory(bytes, idx)
643643+ local szlen, _ = intutil.fromuleb128(bytes, idx)
644644+ idx = idx + szlen
645645+ local nmlen, numMems = intutil.fromuleb128(bytes, idx)
646646+ idx = idx + nmlen
647647+648648+ if numMems > 1 then
649649+ error("more than one memory")
650650+ elseif numMems == 1 then
651651+ local limitFlag = bytes[idx]
652652+ idx = idx + 1
653653+654654+ local minlen, min = intutil.fromuleb128(bytes, idx)
655655+ idx = idx + minlen
656656+ self.memory = memory.new(min)
657657+658658+ if limitFlag == 1 then
659659+ local maxlen, max = intutil.fromuleb128(bytes, idx)
660660+ idx = idx + maxlen
661661+ self.memory.maxpages = max
662662+ end
663663+ end
664664+665665+ return idx
666666+end
667667+668668+local function parseConstexpr(bytes, idx)
669669+ -- FIXME we assume that the initialiser will only be one instruction
670670+ local result
671671+ local initOpcode = bytes[idx]
672672+ idx = idx + 1
673673+674674+ if initOpcode == constants.opcodes.OP_I32_CONST then
675675+ local reslen, res = intutil.fromsleb128(bytes, idx, 32)
676676+ idx = idx + reslen
677677+ result = res
678678+ elseif initOpcode == constants.opcodes.OP_I64_CONST then
679679+ local reslen, res = intutil.fromsleb128(bytes, idx)
680680+ idx = idx + reslen
681681+ result = res
682682+ else
683683+ error("invalid global initialiser instruction")
684684+ end
685685+686686+ if bytes[idx] ~= constants.opcodes.OP_END then
687687+ error("END instruction not found in global initialiser")
688688+ end
689689+ idx = idx + 1
690690+691691+ return idx, result
692692+end
693693+694694+function wasmlib.VM:parseGlobals(bytes, idx)
695695+ local szlen, _ = intutil.fromuleb128(bytes, idx)
696696+ idx = idx + szlen
697697+ local nglen, numGlobs = intutil.fromuleb128(bytes, idx)
698698+ idx = idx + nglen
699699+700700+ for i = 1, numGlobs do
701701+ -- TODO type and mutability ignored for now
702702+ idx = idx + 2
703703+ local nidx, result = parseConstexpr(bytes, idx)
704704+ idx = nidx
705705+ self.globals[i] = result
706706+ end
707707+708708+ return idx
709709+end
710710+711711+function wasmlib.VM:parseExports(bytes, idx) -- TODO
712712+ print("warning: skipping exports section")
713713+ local szlen, size = intutil.fromuleb128(bytes, idx)
714714+ return idx + szlen + size
715715+end
716716+717717+function wasmlib.VM:parseStart(bytes, idx) -- TODO
718718+ print("warning: skipping start section")
719719+ local szlen, size = intutil.fromuleb128(bytes, idx)
720720+ return idx + szlen + size
721721+end
722722+723723+function wasmlib.VM:parseElements(bytes, idx) -- TODO
724724+ print("warning: skipping elements section")
725725+ local szlen, size = intutil.fromuleb128(bytes, idx)
726726+ return idx + szlen + size
727727+end
728728+729729+function wasmlib.VM:parseCode(bytes, idx) -- TODO
730730+ local szlen, _ = intutil.fromuleb128(bytes, idx)
731731+ idx = idx + szlen
732732+ local nclen, numCode = intutil.fromuleb128(bytes, idx)
733733+ idx = idx + nclen
734734+735735+ for i = 1, numCode do -- TODO handle imported functions
736736+ -- size (ignored, not needed for decoding)
737737+ local cszlen, _ = intutil.fromuleb128(bytes, idx)
738738+ idx = idx + cszlen
739739+740740+ -- locals
741741+ local nllen, numLocals = intutil.fromuleb128(bytes, idx)
742742+ idx = idx + nllen
743743+744744+ local locals = {}
745745+ local args = self.types[self.functions[i].typeidx].arguments
746746+ for j = 1, #args do
747747+ locals[j] = args[j]
748748+ end
749749+ local localIdx = #args
750750+ for _ = 1, numLocals do
751751+ local nlen, n = intutil.fromuleb128(bytes, idx)
752752+ idx = idx + nlen
753753+ local valtype = bytes[idx]
754754+ idx = idx + 1
755755+756756+ for _ = 1, n do
757757+ localIdx = localIdx + 1
758758+ locals[localIdx] = valtype
759759+ end
760760+ end
761761+762762+ self.functions[i].locals = locals
763763+764764+ -- code
765765+ local body = {}
766766+ local nestDepth = 0
767767+ repeat
768768+ local opcode = bytes[idx]
769769+ idx = idx + 1
770770+ table.insert(body, opcode)
771771+772772+ if constants.blockOpcodes[opcode] ~= nil then
773773+ nestDepth = nestDepth + 1
774774+ elseif opcode == constants.opcodes.OP_END then
775775+ nestDepth = nestDepth - 1
776776+ end
777777+778778+ local operands = constants.operandTypes[opcode] or {}
779779+ for _ = 1, #operands do
780780+ local operand = operands[i]
781781+ if operand == "b" then
782782+ local a = bytes[idx]
783783+ idx = idx + 1
784784+ table.insert(body, a)
785785+ elseif operand == "u" or operand == "U" then
786786+ local alen, a = intutil.fromuleb128(bytes, idx)
787787+ idx = idx + alen
788788+ table.insert(body, a)
789789+ elseif operand == "i" then
790790+ local alen, a = intutil.fromsleb128(bytes, idx, 32)
791791+ idx = idx + alen
792792+ table.insert(body, a)
793793+ elseif operand == "I" then
794794+ local alen, a = intutil.fromsleb128(bytes, idx)
795795+ idx = idx + alen
796796+ table.insert(body, a)
797797+ elseif operand:sub(1,1) == "V" then
798798+ local vecType = operand:sub(2,2)
799799+ if vecType ~= "u" then
800800+ error("unimplemented")
801801+ end
802802+803803+ local vllen, vecLen = intutil.fromuleb128(bytes, idx)
804804+ idx = idx + vllen
805805+806806+ for _ = 1, vecLen do
807807+ local alen, a = intutil.fromuleb128(bytes, idx)
808808+ idx = idx + alen
809809+ table.insert(body, a)
810810+ end
811811+ end
812812+ end
813813+ until nestDepth == -1 -- expr is terminated with an END opcode which isn't part of any control flow structure,
814814+ -- therefore the nestDepth should end up at -1
815815+ end
816816+817817+ return idx
818818+end
819819+820820+function wasmlib.VM:parseData(bytes, idx) -- TODO
821821+ local szlen, _ = intutil.fromuleb128(bytes, idx)
822822+ idx = idx + szlen
823823+ local ndlen, numData = intutil.fromuleb128(bytes, idx)
824824+ idx = idx + ndlen
825825+826826+ for _ = 1, numData do
827827+ local milen, memIdx = intutil.fromuleb128(bytes, idx)
828828+ idx = idx + milen
829829+ if memIdx ~= 0 then
830830+ error("memidx must be zero")
831831+ end
832832+833833+ local nidx, offset = parseConstexpr(bytes, idx)
834834+ idx = nidx
835835+836836+ local nblen, numBytes = intutil.fromuleb128(bytes, idx)
837837+ idx = idx + nblen
838838+ for i = 0, numBytes - 1 do
839839+ self.memory[offset+i] = bytes[idx]
840840+ idx = idx + 1
841841+ end
842842+ end
843843+844844+ return idx
845845+end
846846+847847+function wasmlib.VM:instantiate(bytes)
848848+ local idx = 1
849849+ idx = checkMagic(bytes, idx)
850850+ idx = checkVersion(bytes, idx)
851851+852852+ local s = constants.sectionIds
853853+ local sectParsers = {
854854+ [s.SECT_CUSTOM] = self.parseCustom,
855855+ [s.SECT_TYPE] = self.parseTypes,
856856+ [s.SECT_IMPORT] = self.parseImports,
857857+ [s.SECT_FUNC] = self.parseFunctions,
858858+ [s.SECT_TABLE] = self.parseTables,
859859+ [s.SECT_MEM] = self.parseMemory,
860860+ [s.SECT_GLOBAL] = self.parseGlobals,
861861+ [s.SECT_EXPORT] = self.parseExports,
862862+ [s.SECT_START] = self.parseStart,
863863+ [s.SECT_ELEM] = self.parseElements,
864864+ [s.SECT_CODE] = self.parseCode,
865865+ [s.SECT_DATA] = self.parseData,
866866+ }
867867+868868+ while idx < #bytes do
869869+ local sectId = bytes[idx]
870870+ idx = idx + 1
871871+ local sectParser = sectParsers[sectId]
872872+ if sectParser == nil then
873873+ error("unsupported section type " .. sectId)
874874+ end
875875+ idx = sectParser(self, bytes, idx)
876876+ end
877877+end
878878+879879+function wasmlib.VM:instantiateFile(path)
880880+ self:instantiate(fileutil.readBytes(path))
566881end
567882568883return wasmlib