quick and dirty pure lua webassembly interpreter
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

final fixes and changes for submission

+273 -104
+14 -1
constants.lua
··· 3 3 constants.I32_MAX = (1 << 32) - 1 4 4 5 5 constants.WASM_PAGE_SIZE = 65536 6 + constants.MAX_PAGES = 65536 6 7 7 8 constants.opcodes = { 8 9 -- Control ··· 192 193 OP_I64_REINTERPRET_F64 = 0xBD, 193 194 OP_F32_REINTERPRET_I32 = 0xBE, 194 195 OP_F64_REINTERPRET_I64 = 0xBF, 196 + -- sign extension 197 + OP_I32_EXTEND8_S = 0xC0, 198 + OP_I32_EXTEND16_S = 0xC1, 199 + OP_I64_EXTEND8_S = 0xC2, 200 + OP_I64_EXTEND16_S = 0xC3, 201 + OP_I64_EXTEND32_S = 0xC4, 195 202 } 196 203 197 204 local c = constants.opcodes ··· 257 264 -- all remaining instructions are arithmetic instructions with no operands 258 265 } 259 266 260 - -- Lengths of each instruction in bytes 267 + -- Lengths of each instruction 261 268 -- (zero represents variable length) 262 269 constants.ilengths = { 263 270 -- control ··· 381 388 [c.OP_I64_EXTEND_I32_S] = 1, 382 389 [c.OP_I64_EXTEND_I32_U] = 1, 383 390 -- [float stuff] 391 + -- sign extension 392 + [c.OP_I32_EXTEND8_S] = 1, 393 + [c.OP_I32_EXTEND16_S] = 1, 394 + [c.OP_I64_EXTEND8_S] = 1, 395 + [c.OP_I64_EXTEND16_S] = 1, 396 + [c.OP_I64_EXTEND32_S] = 1, 384 397 } 385 398 386 399 constants.valtypes = {
+4 -2
frame.lua
··· 2 2 3 3 frame.StackFrame = { 4 4 funcIndex = 0, 5 - locals = {}, 6 5 pc = 0, -- program counter 7 6 } 8 7 9 8 function frame.StackFrame:new(funcIndex) 10 - local f = {} 9 + local f = { 10 + locals = {}, 11 + labelStack = {}, 12 + } 11 13 setmetatable(f, {__index = self}) 12 14 f.funcIndex = funcIndex 13 15 return f
+2 -2
intutil.lua
··· 38 38 return n 39 39 end 40 40 41 - function intutil.fromle64(tab, idx, n) 41 + function intutil.tole64(tab, idx, n) 42 42 tab[idx] = n & 0xFF 43 43 tab[idx+1] = (n >> 8) & 0xFF 44 44 tab[idx+2] = (n >> 16) & 0xFF ··· 99 99 if (shift < bits) and ((tab[idx+len-1] & 0x40) ~= 0) then 100 100 result = result | (((1 << bits) - 1) << shift) 101 101 end 102 - return len, result 102 + return len, result & ((1 << bits) - 1) 103 103 end 104 104 105 105 return intutil
+18 -23
memory.lua
··· 2 2 3 3 local constants = require("constants") 4 4 5 - function memory.new(pages) 6 - local m = { 7 - mem = {}, 8 - pages = pages, 9 - } 10 - setmetatable(m, { 11 - __index = function(self, key) 12 - if key >= (self.pages * constants.WASM_PAGE_SIZE) then 13 - error("out of bounds memory access") 14 - end 15 - return self.mem[key] or 0 16 - end, 17 - __newindex = function(self, key, value) 18 - if key < (self.pages * constants.WASM_PAGE_SIZE) then 19 - self.mem[key] = value 20 - else 21 - error("out of bounds memory access") 22 - end 23 - end, 24 - __len = function(self) 25 - return self.pages 26 - end, 27 - }) 5 + memory.Memory = { 6 + pages = 0, 7 + maxpages = -1, 8 + } 9 + 10 + function memory.Memory:new(pages) 11 + local m = {} 12 + setmetatable(m, {__index = self}) 13 + m:grow(pages) 28 14 return m 15 + end 16 + 17 + function memory.Memory:grow(pages) 18 + local initStart = self.pages * constants.WASM_PAGE_SIZE 19 + local initEnd = ((self.pages + pages) * constants.WASM_PAGE_SIZE) - 1 20 + for i = initStart, initEnd do 21 + self[i] = 0 22 + end 23 + self.pages = self.pages + pages 29 24 end 30 25 31 26 return memory
+36 -6
ops.lua
··· 148 148 return a << b 149 149 end 150 150 151 - function ops.i64_shr_s(a, b) 151 + function ops.i64_shr_u(a, b) 152 152 return a >> b 153 153 end 154 154 ··· 337 337 return (a << b) & constants.I32_MAX 338 338 end 339 339 340 - function ops.i32_shr_s(a, b) 341 - a = intutil.signexti32(a) 342 - b = intutil.signexti32(b) 340 + function ops.i32_shr_u(a, b) 343 341 return (a >> b) & constants.I32_MAX 344 342 end 345 343 346 - function ops.i32_shr_u(a, b) 347 - return (a >> b) & constants.I32_MAX 344 + function ops.i32_shr_s(a, b) 345 + if b >= 32 then 346 + if (a & 0x80000000) == 0 then 347 + return 0 348 + else 349 + return constants.I32_MAX 350 + end 351 + end 352 + 353 + local result = a >> b 354 + if (a & 0x80000000) ~= 0 then 355 + result = result | (((1 << b) - 1) << (32 - b)) 356 + end 357 + return result 348 358 end 349 359 350 360 function ops.i32_rotl(a, b) ··· 369 379 370 380 function ops.i64_extend_i32_u(a) 371 381 return a 382 + end 383 + 384 + function ops.i32_extend8_s(a) 385 + return intutil.signexti8(a) & constants.I32_MAX 386 + end 387 + 388 + function ops.i32_extend16_s(a) 389 + return intutil.signexti16(a) & constants.I32_MAX 390 + end 391 + 392 + function ops.i64_extend8_s(a) 393 + return intutil.signexti8(a) 394 + end 395 + 396 + function ops.i64_extend16_s(a) 397 + return intutil.signexti16(a) 398 + end 399 + 400 + function ops.i64_extend32_s(a) 401 + return intutil.signexti32(a) 372 402 end 373 403 374 404 return ops
+199 -70
wasmlib.lua
··· 14 14 15 15 wasmlib.VM = { 16 16 numImportedFuncs = 0, 17 - stack = {}, 18 - stackFrames = {}, 19 - labelStack = {}, 20 - functions = {}, 21 - types = {}, 22 - memory = {}, 23 - globals = {}, 24 - imports = {}, 25 17 } 26 18 27 19 function wasmlib.VM:new() 28 - local vm = {} 20 + local vm = { 21 + stack = {}, 22 + stackFrames = {}, 23 + functions = {}, 24 + table = {}, 25 + types = {}, 26 + memory = {}, 27 + globals = {}, 28 + imports = {}, 29 + exports = {}, 30 + } 29 31 setmetatable(vm, {__index = self}) 30 32 return vm 31 33 end ··· 68 70 69 71 function wasmlib.VM:local_get() 70 72 local localIdx = self:nextArg() 71 - local localVal = self:curLocals()[localIdx] 72 - if localVal == nil then 73 - error("read uninitialised or out of bounds local") 74 - end 73 + local localVal = self:curLocals()[localIdx] or 0 -- FIXME bounds check 75 74 table.insert(self.stack, localVal) 76 75 end 77 76 ··· 107 106 self:invoke(funcIdx) 108 107 end 109 108 109 + function wasmlib.VM:call_indirect() 110 + local tabOffset = table.remove(self.stack) 111 + self:nextArg() -- FIXME ignoring typeIdx 112 + self:nextArg() -- always zero in wasm 1.0 113 + local funcIdx = self.table[tabOffset] 114 + if funcIdx == nil then 115 + error("invalid call_indirect") 116 + end 117 + self:invoke(funcIdx) 118 + end 119 + 110 120 function wasmlib.VM:memory_size() 111 121 if self:nextArg() ~= 0 then 112 122 error("memory.size operand must be zero") 113 123 end 114 124 115 - return #self.memory 125 + table.insert(self.stack, self.memory.pages) 116 126 end 117 127 118 128 function wasmlib.VM:memory_grow() ··· 122 132 123 133 local amount = table.remove(self.stack) 124 134 if ( 125 - (self.memory.maxpages ~= nil) and (#self.memory + amount > self.memory.maxpages) 126 - ) or (#self.memory + amount > constants.I32_MAX) 135 + (self.memory.maxpages > 0) and (self.memory.pages + amount > self.memory.maxpages) 136 + ) or (self.memory.pages + amount > constants.MAX_PAGES) 127 137 then 128 138 table.insert(self.stack, constants.I32_MAX) -- i32 -1 129 139 else 130 - self.memory.pages = #self.memory + amount 131 - table.insert(self.stack, #self.memory) 140 + table.insert(self.stack, self.memory.pages) 141 + self.memory:grow(amount) 132 142 end 133 143 end 134 144 ··· 137 147 local offset = self:nextArg() 138 148 local argument = table.remove(self.stack) 139 149 local value = intutil.fromle32(self.memory, offset + argument) 150 + trace("i32 loaded "..value.." from "..(offset+argument)) 140 151 table.insert(self.stack, value) 141 152 end 142 153 ··· 145 156 local offset = self:nextArg() 146 157 local argument = table.remove(self.stack) 147 158 local value = intutil.fromle64(self.memory, offset + argument) 159 + trace("i64 loaded "..value.." from "..(offset+argument)) 148 160 table.insert(self.stack, value) 149 161 end 150 162 ··· 153 165 local offset = self:nextArg() 154 166 local argument = table.remove(self.stack) 155 167 local value = intutil.signexti8(self.memory[offset + argument]) & constants.I32_MAX 168 + trace("i32 8s loaded "..value.." from "..(offset+argument)) 156 169 table.insert(self.stack, value) 157 170 end 158 171 ··· 161 174 local offset = self:nextArg() 162 175 local argument = table.remove(self.stack) 163 176 local value = self.memory[offset + argument] 177 + trace("i32 8u loaded "..value.." from "..(offset+argument)) 164 178 table.insert(self.stack, value) 165 179 end 166 180 ··· 169 183 local offset = self:nextArg() 170 184 local argument = table.remove(self.stack) 171 185 local value = intutil.signexti16(intutil.fromle16(self.memory, offset + argument)) & constants.I32_MAX 186 + trace("i32 16s loaded "..value.." from "..(offset+argument)) 172 187 table.insert(self.stack, value) 173 188 end 174 189 ··· 177 192 local offset = self:nextArg() 178 193 local argument = table.remove(self.stack) 179 194 local value = intutil.fromle16(self.memory, offset + argument) 195 + trace("i32 16u loaded "..value.." from "..(offset+argument)) 180 196 table.insert(self.stack, value) 181 197 end 182 198 ··· 185 201 local offset = self:nextArg() 186 202 local argument = table.remove(self.stack) 187 203 local value = intutil.signexti8(self.memory[offset + argument]) 204 + trace("i64 8s loaded "..value.." from "..(offset+argument)) 188 205 table.insert(self.stack, value) 189 206 end 190 207 ··· 193 210 local offset = self:nextArg() 194 211 local argument = table.remove(self.stack) 195 212 local value = self.memory[offset + argument] 213 + trace("i64 8u loaded "..value.." from "..(offset+argument)) 196 214 table.insert(self.stack, value) 197 215 end 198 216 ··· 201 219 local offset = self:nextArg() 202 220 local argument = table.remove(self.stack) 203 221 local value = intutil.signexti16(intutil.fromle16(self.memory, offset + argument)) 222 + trace("i64 16s loaded "..value.." from "..(offset+argument)) 204 223 table.insert(self.stack, value) 205 224 end 206 225 ··· 209 228 local offset = self:nextArg() 210 229 local argument = table.remove(self.stack) 211 230 local value = intutil.fromle16(self.memory, offset + argument) 231 + trace("i64 16u loaded "..value.." from "..(offset+argument)) 212 232 table.insert(self.stack, value) 213 233 end 214 234 ··· 217 237 local offset = self:nextArg() 218 238 local argument = table.remove(self.stack) 219 239 local value = intutil.signexti32(intutil.fromle32(self.memory, offset + argument)) 240 + trace("i64 32s loaded "..value.." from "..(offset+argument)) 220 241 table.insert(self.stack, value) 221 242 end 222 243 ··· 225 246 local offset = self:nextArg() 226 247 local argument = table.remove(self.stack) 227 248 local value = intutil.fromle32(self.memory, offset + argument) 228 - table.insert(self.stack, value) 229 - end 230 - 231 - function wasmlib.VM:i64_load() 232 - self:nextArg() -- alignment, ignored for now 233 - local offset = self:nextArg() 234 - local argument = table.remove(self.stack) 235 - local value = intutil.signexti16(intutil.fromle16(self.memory, offset + argument)) 249 + trace("i64 32u loaded "..value.." from "..(offset+argument)) 236 250 table.insert(self.stack, value) 237 251 end 238 252 239 253 function wasmlib.VM:i32_store() 240 254 self:nextArg() -- alignment, ignored for now 241 255 local offset = self:nextArg() 256 + local value = table.remove(self.stack) 242 257 local argument = table.remove(self.stack) 243 - local value = table.remove(self.stack) 258 + trace("i32 stored "..value.." at "..(offset+argument)) 244 259 intutil.tole32(self.memory, offset + argument, value) 245 260 end 246 261 247 262 function wasmlib.VM:i64_store() 248 263 self:nextArg() -- alignment, ignored for now 249 264 local offset = self:nextArg() 265 + local value = table.remove(self.stack) 250 266 local argument = table.remove(self.stack) 251 - local value = table.remove(self.stack) 267 + trace("i64 stored "..value.." at "..(offset+argument)) 252 268 intutil.tole64(self.memory, offset + argument, value) 253 269 end 254 270 255 271 function wasmlib.VM:i32_store8() 256 272 self:nextArg() -- alignment, ignored for now 257 273 local offset = self:nextArg() 274 + local value = table.remove(self.stack) 258 275 local argument = table.remove(self.stack) 259 - local value = table.remove(self.stack) 276 + trace("i32 8 stored "..value.." at "..(offset+argument)) 260 277 self.memory[offset + argument] = value & 0xFF 261 278 end 262 279 263 280 function wasmlib.VM:i32_store16() 264 281 self:nextArg() -- alignment, ignored for now 265 282 local offset = self:nextArg() 283 + local value = table.remove(self.stack) 266 284 local argument = table.remove(self.stack) 267 - local value = table.remove(self.stack) 285 + trace("i32 16 stored "..value.." at "..(offset+argument)) 268 286 intutil.tole16(self.memory, offset + argument, value) 269 287 end 270 288 271 289 function wasmlib.VM:i64_store8() 272 290 self:nextArg() -- alignment, ignored for now 273 291 local offset = self:nextArg() 292 + local value = table.remove(self.stack) 274 293 local argument = table.remove(self.stack) 275 - local value = table.remove(self.stack) 294 + trace("i64 8 stored "..value.." at "..(offset+argument)) 276 295 self.memory[offset + argument] = value & 0xFF 277 296 end 278 297 279 298 function wasmlib.VM:i64_store16() 280 299 self:nextArg() -- alignment, ignored for now 281 300 local offset = self:nextArg() 301 + local value = table.remove(self.stack) 282 302 local argument = table.remove(self.stack) 283 - local value = table.remove(self.stack) 303 + trace("i64 16 stored "..value.." at "..(offset+argument)) 284 304 intutil.tole16(self.memory, offset + argument, value) 285 305 end 286 306 287 307 function wasmlib.VM:i64_store32() 288 308 self:nextArg() -- alignment, ignored for now 289 309 local offset = self:nextArg() 290 - local argument = table.remove(self.stack) 291 310 local value = table.remove(self.stack) 311 + local argument = table.remove(self.stack) 312 + trace("i64 32 stored "..value.." at "..(offset+argument)) 292 313 intutil.tole32(self.memory, offset + argument, value) 293 314 end 294 315 ··· 303 324 function wasmlib.VM:invoke(funcIndex) 304 325 local f = self.functions[funcIndex] 305 326 local sig = self.types[f.typeidx] 327 + trace(funcIndex, f.typeidx, table.unpack(sig.arguments)) 328 + trace(sig.ret) 306 329 307 330 if f.import ~= nil then 308 331 local args = {} ··· 349 372 350 373 function wasmlib.VM:block() 351 374 local curFrame = self:curFrame() 352 - local startIdx = curFrame.pc - 1 -- pc has already been incremented in step 375 + local startIdx = curFrame.pc 353 376 self:nextArg() -- block result type, ignored for now 354 377 local endIdx = findMatchingEndOrElse(self:curBody(), startIdx) 355 - table.insert(self.labelStack, endIdx) 378 + table.insert(curFrame.labelStack, endIdx + 1) 356 379 end 357 380 358 381 function wasmlib.VM:loop() 359 382 local curFrame = self:curFrame() 360 - local startIdx = curFrame.pc - 1 -- pc has already been incremented in step 383 + local startIdx = curFrame.pc 361 384 self:nextArg() -- block result type, ignored for now 362 - table.insert(self.labelStack, startIdx) 385 + table.insert(curFrame.labelStack, startIdx) 363 386 end 364 387 365 388 function wasmlib.VM:_if() 389 + local curFrame = self:curFrame() 390 + local pc = curFrame.pc 391 + 366 392 self:nextArg() -- block result type, ignored for now 367 393 local c = table.remove(self.stack) 368 - local curFrame = self:curFrame() 369 394 local body = self.functions[curFrame.funcIndex].body 370 - local endOrElse = findMatchingEndOrElse(body, curFrame.pc - 1) -- pc has already been incremented in step 395 + local endOrElse = findMatchingEndOrElse(body, pc) 371 396 372 397 if body[endOrElse] == constants.opcodes.OP_ELSE then 373 398 local elseIdx = endOrElse 374 399 local endIdx = findMatchingEndOrElse(body, endOrElse) 375 400 if c == 0 then 376 - curFrame.pc = elseIdx 401 + curFrame.pc = elseIdx -- instruction after ELSE 377 402 end 378 - table.insert(self.labelStack, endIdx) 403 + table.insert(curFrame.labelStack, endIdx + 1) 379 404 else 380 405 local endIdx = endOrElse 381 406 if c == 0 then 382 - curFrame.pc = endIdx + 1 407 + curFrame.pc = endIdx -- instruction after END 383 408 else 384 - table.insert(self.labelStack, endIdx) 409 + table.insert(curFrame.labelStack, endIdx + 1) 385 410 end 386 411 end 387 412 end 388 413 414 + function wasmlib.VM:_else() 415 + -- jump to label on top of stack 416 + local curFrame = self:curFrame() 417 + local label = table.remove(curFrame.labelStack) 418 + self:curFrame().pc = label - 1 419 + end 420 + 389 421 function wasmlib.VM:brInner(labelIdx) 390 - local label = self.labelStack[#self.labelStack - labelIdx] 422 + local curFrame = self:curFrame() 423 + local label = curFrame.labelStack[#curFrame.labelStack - labelIdx] 391 424 for _ = 1, labelIdx + 1 do 392 - table.remove(self.labelStack) 425 + table.remove(curFrame.labelStack) 393 426 end 394 - self:curFrame().pc = label 427 + self:curFrame().pc = label - 1 395 428 end 396 429 397 430 function wasmlib.VM:br() ··· 408 441 end 409 442 410 443 function wasmlib.VM:br_table() 411 - local table = self:nextArg() 444 + local tab = self:nextArg() 412 445 local other = self:nextArg() 413 446 local i = table.remove(self.stack) 414 447 415 448 if i < #table then 416 - self:brInner(table[i + 1]) 449 + self:brInner(tab[i + 1]) 417 450 else 418 451 self:brInner(other) 419 452 end 420 453 end 421 454 455 + function wasmlib.VM:_end() 456 + local curFrame = self:curFrame() 457 + table.remove(curFrame.labelStack) 458 + end 459 + 422 460 function wasmlib.VM:step() 423 461 if self:curFrame().pc >= #self:curBody() then 462 + trace("returning", self:curFrame().pc, #self:curBody()) 424 463 self:ret() 425 464 return 426 465 end 427 466 428 467 local opcode = self:nextArg() 429 - trace(self:curFrame().pc,opcode,"###",table.unpack(self.stack)) 430 - trace(#self.labelStack,"---",table.unpack(self.labelStack)) 468 + trace(self:curFrame().funcIndex, self:curFrame().pc,opcode, "###", table.unpack(self.stack)) 469 + trace(#self:curFrame().labelStack, "---", table.unpack(self:curFrame().labelStack)) 431 470 432 471 local c = constants.opcodes 433 472 local optable = { ··· 437 476 [c.OP_BLOCK] = function() self:block() end, 438 477 [c.OP_LOOP] = function() self:loop() end, 439 478 [c.OP_IF] = function() self:_if() end, 440 - [c.OP_ELSE] = function() table.remove(self.labelStack) end, 441 - [c.OP_END] = function() table.remove(self.labelStack) end, 479 + [c.OP_ELSE] = function() self:_else() end, 480 + [c.OP_END] = function() self:_end() end, 442 481 [c.OP_BR] = function() self:br() end, 443 482 [c.OP_BR_IF] = function() self:br_if() end, 444 483 [c.OP_BR_TABLE] = function() self:br_table() end, 445 484 [c.OP_RETURN] = function() self:ret() end, 446 485 [c.OP_CALL] = function() self:call() end, 447 - -- CALL_INDIRECT 486 + [c.OP_CALL_INDIRECT] = function() self:call_indirect() end, 448 487 -- parametric 449 488 [c.OP_DROP] = function() table.remove(self.stack) end, 450 489 [c.OP_SELECT] = function() self:triop(ops.select) end, ··· 492 531 [c.OP_I32_GT_U] = function() self:binop(ops.i32_gt_u) end, 493 532 [c.OP_I32_LE_S] = function() self:binop(ops.i32_le_s) end, 494 533 [c.OP_I32_LE_U] = function() self:binop(ops.i32_le_u) end, 534 + [c.OP_I32_GE_S] = function() self:binop(ops.i32_ge_s) end, 535 + [c.OP_I32_GE_U] = function() self:binop(ops.i32_ge_u) end, 495 536 -- i64 comparisons 496 537 [c.OP_I64_EQZ] = function() self:unop (ops.i64_eqz) end, 497 538 [c.OP_I64_EQ] = function() self:binop(ops.i64_eq) end, ··· 539 580 [c.OP_I64_OR] = function() self:binop(ops.i64_or) end, 540 581 [c.OP_I64_XOR] = function() self:binop(ops.i64_xor) end, 541 582 [c.OP_I64_SHL] = function() self:binop(ops.i64_shl) end, 542 - [c.OP_I64_SHR_S] = function() self:binop(ops.i64_shr_s) end, 543 - -- I64_SHR_U 583 + -- I64_SHR_S 584 + [c.OP_I64_SHR_U] = function() self:binop(ops.i64_shr_u) end, 544 585 [c.OP_I64_ROTL] = function() self:binop(ops.i64_rotl) end, 545 586 [c.OP_I64_ROTR] = function() self:binop(ops.i64_rotr) end, 546 587 -- [float operations] 547 588 -- conversions 548 - [c.OP_I32_WRAP_I64] = function() self:unop(ops.i32_wrap_i64) end, 589 + [c.OP_I32_WRAP_I64] = function() self:unop (ops.i32_wrap_i64) end, 549 590 -- [float stuff] 550 - [c.OP_I64_EXTEND_I32_S] = function() self:unop(ops.i64_extend_i32_s) end, 551 - [c.OP_I64_EXTEND_I32_U] = function() self:unop(ops.i64_extend_i32_u) end, 591 + [c.OP_I64_EXTEND_I32_S] = function() self:unop (ops.i64_extend_i32_s) end, 592 + [c.OP_I64_EXTEND_I32_U] = function() self:unop (ops.i64_extend_i32_u) end, 552 593 -- [float stuff] 594 + -- sign ext 595 + [c.OP_I32_EXTEND8_S] = function() self:unop (ops.i32_extend8_s) end, 596 + [c.OP_I32_EXTEND16_S] = function() self:unop (ops.i32_extend16_s) end, 597 + [c.OP_I64_EXTEND8_S] = function() self:unop (ops.i64_extend8_s) end, 598 + [c.OP_I64_EXTEND16_S] = function() self:unop (ops.i64_extend16_s) end, 599 + [c.OP_I64_EXTEND32_S] = function() self:unop (ops.i64_extend32_s) end, 553 600 } 554 601 555 602 local opfunc = optable[opcode] ··· 627 674 end 628 675 629 676 function wasmlib.VM:parseImports(bytes, idx, imports) 677 + trace("parsing imports section") 630 678 local szlen, _ = intutil.fromuleb128(bytes, idx) 631 679 idx = idx + szlen 632 680 local nilen, numImports = intutil.fromuleb128(bytes, idx) ··· 668 716 end 669 717 670 718 function wasmlib.VM:parseFunctions(bytes, idx) 719 + trace("parsing functions section") 671 720 local szlen, _ = intutil.fromuleb128(bytes, idx) 672 721 idx = idx + szlen 673 722 local nflen, numFuncs = intutil.fromuleb128(bytes, idx) ··· 682 731 return idx 683 732 end 684 733 685 - function wasmlib.VM:parseTables(bytes, idx, imports) -- luacheck: no unused args 686 - print("warning: skipping tables section") 734 + function wasmlib.VM:parseTables(bytes, idx) -- luacheck: no unused args 735 + -- FIXME: we just assume there is always a table, and don't check the size/types at all 687 736 local szlen, size = intutil.fromuleb128(bytes, idx) 688 737 return idx + szlen + size 689 738 end 690 739 691 740 function wasmlib.VM:parseMemory(bytes, idx) 741 + trace("parsing memory section") 692 742 local szlen, _ = intutil.fromuleb128(bytes, idx) 693 743 idx = idx + szlen 694 744 local nmlen, numMems = intutil.fromuleb128(bytes, idx) ··· 702 752 703 753 local minlen, min = intutil.fromuleb128(bytes, idx) 704 754 idx = idx + minlen 705 - self.memory = memory.new(min) 755 + self.memory = memory.Memory:new(min) 706 756 707 757 if limitFlag == 1 then 708 758 local maxlen, max = intutil.fromuleb128(bytes, idx) ··· 741 791 end 742 792 743 793 function wasmlib.VM:parseGlobals(bytes, idx) 794 + trace("parsing globals section") 744 795 local szlen, _ = intutil.fromuleb128(bytes, idx) 745 796 idx = idx + szlen 746 797 local nglen, numGlobs = intutil.fromuleb128(bytes, idx) ··· 757 808 return idx 758 809 end 759 810 760 - function wasmlib.VM:parseExports(bytes, idx) -- luacheck: no unused args 761 - print("warning: skipping exports section") 762 - local szlen, size = intutil.fromuleb128(bytes, idx) 763 - return idx + szlen + size 811 + function wasmlib.VM:parseExports(bytes, idx) 812 + trace("parsing exports section") 813 + local szlen, _ = intutil.fromuleb128(bytes, idx) 814 + idx = idx + szlen 815 + local nelen, numExports = intutil.fromuleb128(bytes, idx) 816 + idx = idx + nelen 817 + 818 + for _ = 1, numExports do 819 + local nllen, nameLen = intutil.fromuleb128(bytes, idx) 820 + idx = idx + nllen 821 + local exportName = strutil.bytestostr(bytes, idx, nameLen) 822 + idx = idx + nameLen 823 + 824 + local exportDesc = bytes[idx] 825 + idx = idx + 1 826 + if exportDesc == 0x00 then 827 + local funcIdx = bytes[idx] + 1 828 + idx = idx + 1 829 + 830 + self.exports[exportName] = function(...) 831 + trace("called export "..exportName) 832 + local args = {...} 833 + local nargs = #self.types[self.functions[funcIdx].typeidx].arguments 834 + if #args ~= nargs then 835 + error("exported function "..exportName.." called with incorrect number of arguments") 836 + end 837 + 838 + for i = 1, nargs do 839 + table.insert(self.stack, args[i]) 840 + end 841 + self:invoke(funcIdx) 842 + while #self.stackFrames > 0 do 843 + self:step() 844 + end 845 + 846 + if self.types[self.functions[funcIdx].typeidx].ret ~= nil then 847 + return table.remove(self.stack) 848 + end 849 + end 850 + elseif exportDesc == 0x01 then 851 + idx = idx + 1 852 + print("warning: ignoring table export") 853 + elseif exportDesc == 0x02 then 854 + idx = idx + 1 855 + print("warning: ignoring memory export") 856 + elseif exportDesc == 0x03 then 857 + idx = idx + 1 858 + print("warning: ignoring global export") 859 + else 860 + error("invalid export type "..exportDesc) 861 + end 862 + end 863 + 864 + return idx 764 865 end 765 866 766 867 function wasmlib.VM:parseStart(bytes, idx) -- luacheck: no unused args ··· 769 870 return idx + szlen + size 770 871 end 771 872 772 - function wasmlib.VM:parseElements(bytes, idx) -- luacheck: no unused args 773 - print("warning: skipping elements section") 774 - local szlen, size = intutil.fromuleb128(bytes, idx) 775 - return idx + szlen + size 873 + function wasmlib.VM:parseElements(bytes, idx) 874 + local szlen, _ = intutil.fromuleb128(bytes, idx) 875 + idx = idx + szlen 876 + local nelen, numElems = intutil.fromuleb128(bytes, idx) 877 + idx = idx + nelen 878 + 879 + for _ = 1, numElems do 880 + local tilen, tabIdx = intutil.fromuleb128(bytes, idx) 881 + idx = idx + tilen 882 + if tabIdx ~= 0 then 883 + error("tableidx must be zero") 884 + end 885 + 886 + local nidx, offset = parseConstexpr(bytes, idx) 887 + idx = nidx 888 + 889 + local nflen, numFunctions = intutil.fromuleb128(bytes, idx) 890 + idx = idx + nflen 891 + for i = 0, numFunctions - 1 do 892 + local filen, funcIdx = intutil.fromuleb128(bytes, idx) 893 + idx = idx + filen 894 + self.table[offset+i] = funcIdx + 1 895 + end 896 + end 897 + 898 + return idx 776 899 end 777 900 778 901 function wasmlib.VM:parseCode(bytes, idx) 902 + trace("parsing code section") 779 903 local szlen, _ = intutil.fromuleb128(bytes, idx) 780 904 idx = idx + szlen 781 905 local nclen, numCode = intutil.fromuleb128(bytes, idx) ··· 845 969 idx = idx + alen 846 970 table.insert(body, a) 847 971 elseif operand:sub(1,1) == "V" then 972 + local v = {} 848 973 local vecType = operand:sub(2,2) 849 974 if vecType ~= "u" then 850 975 error("unimplemented") ··· 856 981 for _ = 1, vecLen do 857 982 local alen, a = intutil.fromuleb128(bytes, idx) 858 983 idx = idx + alen 859 - table.insert(body, a) 984 + table.insert(v, a) 860 985 end 986 + 987 + table.insert(body, v) 861 988 end 862 989 end 863 990 until nestDepth == -1 -- expr is terminated with an END opcode which isn't part of any control flow structure, 864 991 -- therefore the nestDepth should end up at -1 992 + body[#body] = nil -- remove the END terminator 865 993 self.functions[i].body = body 866 994 end 867 995 ··· 869 997 end 870 998 871 999 function wasmlib.VM:parseData(bytes, idx) 1000 + trace("parsing data section") 872 1001 local szlen, _ = intutil.fromuleb128(bytes, idx) 873 1002 idx = idx + szlen 874 1003 local ndlen, numData = intutil.fromuleb128(bytes, idx)