quick and dirty pure lua webassembly interpreter
1
fork

Configure Feed

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

more instructions, memory

+309 -35
+2
constants.lua
··· 2 2 3 3 constants.I32_MAX = (1 << 32) - 1 4 4 5 + constants.WASM_PAGE_SIZE = 65536 6 + 5 7 constants.opcodes = { 6 8 -- Control 7 9 OP_UNREACHABLE = 0x00,
+25
intutil.lua
··· 1 1 local intutil = {} 2 2 3 + function intutil.fromle16(tab, idx) 4 + local n = tab[idx] 5 + n = n | tab[idx+1] << 8 6 + return n 7 + end 8 + 9 + function intutil.tole16(tab, idx, n) 10 + tab[idx] = n & 0xFF 11 + tab[idx+1] = (n >> 8) & 0xFF 12 + end 13 + 3 14 function intutil.fromle32(tab, idx) 4 15 local n = tab[idx] 5 16 n = n | tab[idx+1] << 8 ··· 41 52 function intutil.signexti32(n) 42 53 if (n & 0x80000000) ~= 0 then 43 54 n = n | 0xFFFFFFFF00000000 55 + end 56 + return n 57 + end 58 + 59 + function intutil.signexti16(n) 60 + if (n & 0x8000) ~= 0 then 61 + n = n | 0xFFFFFFFFFFFF0000 62 + end 63 + return n 64 + end 65 + 66 + function intutil.signexti8(n) 67 + if (n & 0x80) ~= 0 then 68 + n = n | 0xFFFFFFFFFFFFFF00 44 69 end 45 70 return n 46 71 end
+31
memory.lua
··· 1 + local memory = {} 2 + 3 + local constants = require("constants") 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 + }) 28 + return m 29 + end 30 + 31 + return memory
+14
ops.lua
··· 357 357 return ((a >> c) | (a << (32 - c))) & constants.I32_MAX 358 358 end 359 359 360 + --[[ int conversions ]] 361 + 362 + function ops.i32_wrap_i64(a) 363 + return a & constants.I32_MAX 364 + end 365 + 366 + function ops.i64_extend_i32_s(a) 367 + return intutil.signexti32(a) 368 + end 369 + 370 + function ops.i64_extend_i32_u(a) 371 + return a 372 + end 373 + 360 374 return ops
+237 -35
wasmlib.lua
··· 10 10 stackFrames = {}, 11 11 functions = {}, 12 12 types = {}, 13 + memory = {}, 14 + globals = {}, 13 15 } 14 - 15 - function wasmlib.VM:topFrame() 16 - return self.stackFrames[#self.stackFrames] 17 - end 18 16 19 17 function wasmlib.VM:new() 20 18 local vm = {} ··· 22 20 return vm 23 21 end 24 22 23 + function wasmlib.VM:topFrame() 24 + return self.stackFrames[#self.stackFrames] 25 + end 26 + 25 27 function wasmlib.VM:triop(f) 26 28 local c = table.remove(self.stack) 27 29 local b = table.remove(self.stack) ··· 43 45 function wasmlib.VM:readarg8() 44 46 local curFrame = self.topFrame() 45 47 local body = self.functions[curFrame.funcIndex].body 46 - local result = body[curFrame.pc + 1] 48 + local result = body[curFrame.pc] 47 49 curFrame.pc = curFrame.pc + 1 48 50 return result 49 51 end ··· 51 53 function wasmlib.VM:readarg32() 52 54 local curFrame = self:topFrame() 53 55 local body = self.functions[curFrame.funcIndex].body 54 - local result = intutil.fromle32(body, curFrame.pc + 1) 56 + local result = intutil.fromle32(body, curFrame.pc) 55 57 curFrame.pc = curFrame.pc + 4 56 58 return result 57 59 end 58 60 61 + function wasmlib.VM:readarg64() 62 + local curFrame = self:topFrame() 63 + local body = self.functions[curFrame.funcIndex].body 64 + local result = intutil.fromle64(body, curFrame.pc) 65 + curFrame.pc = curFrame.pc + 8 66 + return result 67 + end 68 + 59 69 function wasmlib.VM:local_get() 60 70 local curFrame = self:topFrame() 61 71 local localIdx = self:readarg32() ··· 73 83 curFrame.locals[localIdx] = localVal 74 84 end 75 85 86 + function wasmlib.VM:local_tee() 87 + local curFrame = self:topFrame() 88 + local localIdx = self:readarg32() 89 + local localVal = self.stack[#self.stack] 90 + curFrame.locals[localIdx] = localVal 91 + end 92 + 93 + function wasmlib.VM:global_get() 94 + local globalIdx = self:readarg32() 95 + local globalVal = self.globals[globalIdx] 96 + if globalVal == nil then 97 + error("read invalid global") 98 + end 99 + table.insert(self.stack, globalVal) 100 + end 101 + 102 + function wasmlib.VM:global_set() 103 + local globalIdx = self:readarg32() 104 + local globalVal = table.remove(self.stack) 105 + self.globals[globalIdx] = globalVal 106 + end 107 + 76 108 function wasmlib.VM:call() 77 109 local funcIdx = self:readarg32() 78 110 self:invoke(funcIdx) 79 111 end 80 112 113 + function wasmlib.VM:memory_size() 114 + self:readarg8() -- always zero in WASM 1.0 115 + return #self.memory 116 + end 117 + 118 + function wasmlib.VM:memory_grow() 119 + self:readarg8() -- always zero in WASM 1.0 120 + local amount = table.remove(self.stack) 121 + if ( 122 + (self.memory.maxpages ~= nil) and (#self.memory + amount > self.memory.maxpages) 123 + ) or (#self.memory + amount > constants.I32_MAX) 124 + then 125 + table.insert(self.stack, constants.I32_MAX) -- i32 -1 126 + else 127 + self.memory.pages = #self.memory + amount 128 + table.insert(self.stack, #self.memory) 129 + end 130 + end 131 + 132 + function wasmlib.VM:i32_load() 133 + self:readarg32() -- alignment, ignored for now 134 + local offset = self:readarg32() 135 + local value = intutil.fromle32(self.memory, offset) 136 + table.insert(self.stack, value) 137 + end 138 + 139 + function wasmlib.VM:i64_load() 140 + self:readarg32() -- alignment, ignored for now 141 + local offset = self:readarg32() 142 + local value = intutil.fromle64(self.memory, offset) 143 + table.insert(self.stack, value) 144 + end 145 + 146 + function wasmlib.VM:i32_load8_s() 147 + self:readarg32() -- alignment, ignored for now 148 + local offset = self:readarg32() 149 + local value = intutil.signexti8(self.memory[offset]) & constants.I32_MAX 150 + table.insert(self.stack, value) 151 + end 152 + 153 + function wasmlib.VM:i32_load8_u() 154 + self:readarg32() -- alignment, ignored for now 155 + local offset = self:readarg32() 156 + local value = self.memory[offset] 157 + table.insert(self.stack, value) 158 + end 159 + 160 + function wasmlib.VM:i32_load16_s() 161 + self:readarg32() -- alignment, ignored for now 162 + local offset = self:readarg32() 163 + local value = intutil.signexti16(intutil.fromle16(self.memory, offset)) & constants.I32_MAX 164 + table.insert(self.stack, value) 165 + end 166 + 167 + function wasmlib.VM:i32_load16_u() 168 + self:readarg32() -- alignment, ignored for now 169 + local offset = self:readarg32() 170 + local value = intutil.fromle16(self.memory, offset) 171 + table.insert(self.stack, value) 172 + end 173 + 174 + function wasmlib.VM:i64_load8_s() 175 + self:readarg32() -- alignment, ignored for now 176 + local offset = self:readarg32() 177 + local value = intutil.signexti8(self.memory[offset]) 178 + table.insert(self.stack, value) 179 + end 180 + 181 + function wasmlib.VM:i64_load8_u() 182 + self:readarg32() -- alignment, ignored for now 183 + local offset = self:readarg32() 184 + local value = self.memory[offset] 185 + table.insert(self.stack, value) 186 + end 187 + 188 + function wasmlib.VM:i64_load16_s() 189 + self:readarg32() -- alignment, ignored for now 190 + local offset = self:readarg32() 191 + local value = intutil.signexti16(intutil.fromle16(self.memory, offset)) 192 + table.insert(self.stack, value) 193 + end 194 + 195 + function wasmlib.VM:i64_load16_u() 196 + self:readarg32() -- alignment, ignored for now 197 + local offset = self:readarg32() 198 + local value = intutil.fromle16(self.memory, offset) 199 + table.insert(self.stack, value) 200 + end 201 + 202 + function wasmlib.VM:i64_load32_s() 203 + self:readarg32() -- alignment, ignored for now 204 + local offset = self:readarg32() 205 + local value = intutil.signexti32(intutil.fromle32(self.memory, offset)) 206 + table.insert(self.stack, value) 207 + end 208 + 209 + function wasmlib.VM:i64_load32_u() 210 + self:readarg32() -- alignment, ignored for now 211 + local offset = self:readarg32() 212 + local value = intutil.fromle32(self.memory, offset) 213 + table.insert(self.stack, value) 214 + end 215 + 216 + function wasmlib.VM:i64_load() 217 + self:readarg32() -- alignment, ignored for now 218 + local offset = self:readarg32() 219 + local value = intutil.signexti16(intutil.fromle16(self.memory, offset)) 220 + table.insert(self.stack, value) 221 + end 222 + 223 + function wasmlib.VM:i32_store() 224 + self:readarg32() -- alignment, ignored for now 225 + local offset = self:readarg32() 226 + local value = table.remove(self.stack) 227 + intutil.tole32(self.memory, offset, value) 228 + end 229 + 230 + function wasmlib.VM:i64_store() 231 + self:readarg32() -- alignment, ignored for now 232 + local offset = self:readarg32() 233 + local value = table.remove(self.stack) 234 + intutil.tole64(self.memory, offset, value) 235 + end 236 + 237 + function wasmlib.VM:i32_store8() 238 + self:readarg32() -- alignment, ignored for now 239 + local offset = self:readarg32() 240 + local value = table.remove(self.stack) 241 + self.memory[offset] = value & 0xFF 242 + end 243 + 244 + function wasmlib.VM:i32_store16() 245 + self:readarg32() -- alignment, ignored for now 246 + local offset = self:readarg32() 247 + local value = table.remove(self.stack) 248 + intutil.tole16(self.memory, offset, value) 249 + end 250 + 251 + function wasmlib.VM:i64_store8() 252 + self:readarg32() -- alignment, ignored for now 253 + local offset = self:readarg32() 254 + local value = table.remove(self.stack) 255 + self.memory[offset] = value & 0xFF 256 + end 257 + 258 + function wasmlib.VM:i64_store16() 259 + self:readarg32() -- alignment, ignored for now 260 + local offset = self:readarg32() 261 + local value = table.remove(self.stack) 262 + intutil.tole16(self.memory, offset, value) 263 + end 264 + 265 + function wasmlib.VM:i64_store32() 266 + self:readarg32() -- alignment, ignored for now 267 + local offset = self:readarg32() 268 + local value = table.remove(self.stack) 269 + intutil.tole32(self.memory, offset, value) 270 + end 271 + 272 + function wasmlib.VM:i32_const() 273 + table.insert(self.stack, self:readarg32()) 274 + end 275 + 276 + function wasmlib.VM:i64_const() 277 + table.insert(self.stack, self:readarg64()) 278 + end 279 + 81 280 function wasmlib.VM:step() 82 281 local curFrame = self:topFrame() 83 282 local body = self.functions[curFrame.funcIndex].body 84 283 local opcode = body[curFrame.pc] 284 + curFrame.pc = curFrame.pc + 1 85 285 86 286 local c = constants.opcodes 87 287 local optable = { ··· 105 305 -- variable 106 306 [c.OP_LOCAL_GET] = function() self:local_get() end, 107 307 [c.OP_LOCAL_SET] = function() self:local_set() end, 108 - -- LOCAL_TEE 109 - -- GLOBAL_GET 110 - -- GLOBAL_SET 308 + [c.OP_LOCAL_TEE] = function() self:local_tee() end, 309 + [c.OP_GLOBAL_GET] = function() self:global_get() end, 310 + [c.OP_GLOBAL_SET] = function() self:global_set() end, 111 311 -- memory 112 - -- I32_LOAD 113 - -- I64_LOAD 312 + [c.OP_I32_LOAD] = function() self:i32_load() end, 313 + [c.OP_I64_LOAD] = function() self:i64_load() end, 114 314 -- [float instrs] 115 - -- I32_LOAD8_S 116 - -- I32_LOAD8_U 117 - -- I32_LOAD16_S 118 - -- I32_LOAD16_U 119 - -- I64_LOAD8_S 120 - -- I64_LOAD8_U 121 - -- I64_LOAD16_S 122 - -- I64_LOAD16_U 123 - -- I64_LOAD32_S 124 - -- I64_LOAD32_U 125 - -- I32_STORE 126 - -- I64_STORE 315 + [c.OP_I32_LOAD8_S] = function() self:i32_load8_s() end, 316 + [c.OP_I32_LOAD8_U] = function() self:i32_load8_u() end, 317 + [c.OP_I32_LOAD16_S] = function() self:i32_load16_s() end, 318 + [c.OP_I32_LOAD16_U] = function() self:i32_load16_u() end, 319 + [c.OP_I64_LOAD8_S] = function() self:i64_load8_s() end, 320 + [c.OP_I64_LOAD8_U] = function() self:i64_load8_u() end, 321 + [c.OP_I64_LOAD16_S] = function() self:i64_load16_s() end, 322 + [c.OP_I64_LOAD16_U] = function() self:i64_load16_u() end, 323 + [c.OP_I64_LOAD32_S] = function() self:i64_load32_s() end, 324 + [c.OP_I64_LOAD32_U] = function() self:i64_load32_u() end, 325 + [c.OP_I32_STORE] = function() self:i32_store() end, 326 + [c.OP_I64_STORE] = function() self:i64_store() end, 127 327 -- [floart instrs] 128 - -- I32_STORE8 129 - -- I32_STORE16 130 - -- I64_STORE8 131 - -- I64_STORE16 132 - -- I64_STORE32 133 - -- MEMORY_SIZE 134 - -- MEMORY_GROW 328 + [c.OP_I32_STORE8] = function() self:i32_store8() end, 329 + [c.OP_I32_STORE16] = function() self:i32_store16() end, 330 + [c.OP_I64_STORE8] = function() self:i64_store8() end, 331 + [c.OP_I64_STORE16] = function() self:i64_store16() end, 332 + [c.OP_I64_STORE32] = function() self:i64_store32() end, 333 + [c.OP_MEMORY_SIZE] = function() self:memory_size() end, 334 + [c.OP_MEMORY_GROW] = function() self:memory_grow() end, 335 + -- constants 336 + [c.OP_I32_CONST] = function() self:i32_const() end, 337 + [c.OP_I64_CONST] = function() self:i64_const() end, 338 + -- [float consts] 135 339 -- i32 comparisons 136 340 [c.OP_I32_EQZ] = function() self:unop (ops.i32_eqz) end, 137 341 [c.OP_I32_EQ] = function() self:binop(ops.i32_eq) end, ··· 195 399 [c.OP_I64_ROTR] = function() self:binop(ops.i64_rotr) end, 196 400 -- [float operations] 197 401 -- conversions 198 - -- I32_WRAP_I64 402 + [c.OP_I32_WRAP_I64] = function() self:unop(ops.i32_wrap_i64) end, 199 403 -- [float stuff] 200 - -- I64_EXTEND_I32_S 201 - -- I64_EXTEND_I32_U 404 + [c.OP_I64_EXTEND_I32_S] = function() self:unop(ops.i64_extend_i32_s) end, 405 + [c.OP_I64_EXTEND_I32_U] = function() self:unop(ops.i64_extend_i32_u) end, 202 406 -- [float stuff] 203 407 } 204 408 ··· 207 411 error("unimplemented") 208 412 end 209 413 opfunc() 210 - 211 - curFrame.pc = curFrame.pc + 1 212 414 end 213 415 214 416 function wasmlib.VM:invoke(funcIndex)