quick and dirty pure lua webassembly interpreter
1
fork

Configure Feed

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

function calls, more instructions

+479 -28
+18
constants.lua
··· 1 1 local constants = {} 2 2 3 + constants.I32_MAX = (1 << 32) - 1 4 + 3 5 constants.opcodes = { 4 6 -- Control 5 7 OP_UNREACHABLE = 0x00, ··· 188 190 OP_I64_REINTERPRET_F64 = 0xBD, 189 191 OP_F32_REINTERPRET_I32 = 0xBE, 190 192 OP_F64_REINTERPRET_I64 = 0xBF, 193 + } 194 + 195 + constants.valtypes = { 196 + VTY_I32 = 0x7F, 197 + VTY_I64 = 0x7E, 198 + VTY_F32 = 0x7D, 199 + VTY_F64 = 0x7C, 200 + } 201 + 202 + constants.blocktypes = { 203 + BTY_NONE = 0x40, 204 + BTY_I32 = constants.valtypes.VTY_I32, 205 + BTY_I64 = constants.valtypes.VTY_I64, 206 + BTY_F32 = constants.valtypes.VTY_F32, 207 + BTY_F64 = constants.valtypes.VTY_F64, 208 + 191 209 } 192 210 193 211 return constants
+16
frame.lua
··· 1 + local frame = {} 2 + 3 + frame.StackFrame = { 4 + funcIndex = 0, 5 + locals = {}, 6 + pc = 1, -- program counter 7 + } 8 + 9 + function frame.StackFrame:new(funcIndex) 10 + local f = {} 11 + setmetatable(f, {__index = self}) 12 + f.funcIndex = funcIndex 13 + return f 14 + end 15 + 16 + return frame
+48
intutil.lua
··· 1 + local intutil = {} 2 + 3 + function intutil.fromle32(tab, idx) 4 + local n = tab[idx] 5 + n = n | tab[idx+1] << 8 6 + n = n | tab[idx+2] << 16 7 + n = n | tab[idx+3] << 24 8 + return n 9 + end 10 + 11 + function intutil.tole32(tab, idx, n) 12 + tab[idx] = n & 0xFF 13 + tab[idx+1] = (n >> 8) & 0xFF 14 + tab[idx+2] = (n >> 16) & 0xFF 15 + tab[idx+3] = (n >> 24) & 0xFF 16 + end 17 + 18 + function intutil.fromle64(tab, idx) 19 + local n = tab[idx] 20 + n = n | tab[idx+1] << 8 21 + n = n | tab[idx+2] << 16 22 + n = n | tab[idx+3] << 24 23 + n = n | tab[idx+4] << 32 24 + n = n | tab[idx+5] << 40 25 + n = n | tab[idx+6] << 48 26 + n = n | tab[idx+7] << 56 27 + return n 28 + end 29 + 30 + function intutil.fromle64(tab, idx, n) 31 + tab[idx] = n & 0xFF 32 + tab[idx+1] = (n >> 8) & 0xFF 33 + tab[idx+2] = (n >> 16) & 0xFF 34 + tab[idx+3] = (n >> 24) & 0xFF 35 + tab[idx+4] = (n >> 32) & 0xFF 36 + tab[idx+5] = (n >> 40) & 0xFF 37 + tab[idx+6] = (n >> 48) & 0xFF 38 + tab[idx+7] = (n >> 56) & 0xFF 39 + end 40 + 41 + function intutil.signexti32(n) 42 + if (n & 0x80000000) ~= 0 then 43 + n = n | 0xFFFFFFFF00000000 44 + end 45 + return n 46 + end 47 + 48 + return intutil
+207 -4
ops.lua
··· 1 1 local ops = {} 2 2 3 + local constants = require("constants") 4 + local intutil = require("intutil") 5 + 6 + function ops.select(a, b, c) 7 + return (c ~= 0) and a or b 8 + end 9 + 10 + --[[ i64 ]] 11 + 3 12 function ops.i64_eqz(a) 4 13 return (a == 0) and 1 or 0 5 14 end ··· 57 66 if (a & 0x8000000000000000) == 0 then 58 67 n = n + 1 59 68 end 60 - 61 69 return n 62 70 end 63 71 ··· 117 125 end 118 126 119 127 function ops.i64_div_s(a, b) 120 - return a / b 128 + return a // b 121 129 end 122 130 123 131 function ops.i64_rem_s(a, b) ··· 137 145 end 138 146 139 147 function ops.i64_shl(a, b) 140 - return a >> b 148 + return a << b 141 149 end 142 150 143 151 function ops.i64_shr_s(a, b) 144 - return a << b 152 + return a >> b 145 153 end 146 154 147 155 function ops.i64_rotl(a, b) ··· 152 160 function ops.i64_rotr(a, b) 153 161 local c = b % 64 154 162 return (a >> c) | (a << (64 - c)) 163 + end 164 + 165 + --[[ i32 ]] 166 + 167 + function ops.i32_eqz(a) 168 + return (a == 0) and 1 or 0 169 + end 170 + 171 + function ops.i32_eq(a, b) 172 + return (a == b) and 1 or 0 173 + end 174 + 175 + function ops.i32_ne(a, b) 176 + return (a ~= b) and 1 or 0 177 + end 178 + 179 + function ops.i32_lt_s(a, b) 180 + a = intutil.signexti32(a) 181 + b = intutil.signexti32(b) 182 + return (a < b) and 1 or 0 183 + end 184 + 185 + function ops.i32_lt_s(a, b) 186 + a = intutil.signexti32(a) 187 + b = intutil.signexti32(b) 188 + return (a < b) and 1 or 0 189 + end 190 + 191 + function ops.i32_lt_u(a, b) 192 + return (a < b) and 1 or 0 193 + end 194 + 195 + function ops.i32_gt_s(a, b) 196 + a = intutil.signexti32(a) 197 + b = intutil.signexti32(b) 198 + return (a > b) and 1 or 0 199 + end 200 + 201 + function ops.i32_gt_u(a, b) 202 + return (a > b) and 1 or 0 203 + end 204 + 205 + function ops.i32_le_s(a, b) 206 + a = intutil.signexti32(a) 207 + b = intutil.signexti32(b) 208 + return (a <= b) and 1 or 0 209 + end 210 + 211 + function ops.i32_le_u(a, b) 212 + return (a <= b) and 1 or 0 213 + end 214 + 215 + function ops.i32_ge_s(a, b) 216 + a = intutil.signexti32(a) 217 + b = intutil.signexti32(b) 218 + return (a >= b) and 1 or 0 219 + end 220 + 221 + function ops.i32_ge_u(a, b) 222 + return (a >= b) and 1 or 0 223 + end 224 + 225 + function ops.i32_clz(a) 226 + if a == 0 then 227 + return 32 228 + end 229 + 230 + local n = 0 231 + if (a & 0xFFFF0000) == 0 then 232 + n = n + 16 233 + a = a << 16 234 + end 235 + if (a & 0xFF000000) == 0 then 236 + n = n + 8 237 + a = a << 8 238 + end 239 + if (a & 0xF0000000) == 0 then 240 + n = n + 4 241 + a = a << 4 242 + end 243 + if (a & 0xC0000000) == 0 then 244 + n = n + 2 245 + a = a << 2 246 + end 247 + if (a & 0x80000000) == 0 then 248 + n = n + 1 249 + end 250 + return n 251 + end 252 + 253 + function ops.i32_ctz(a) 254 + if a == 0 then 255 + return 64 256 + end 257 + 258 + local n = 0 259 + if (a & 0x0000FFFF) == 0 then 260 + n = n + 16 261 + a = a >> 16 262 + end 263 + if (a & 0x000000FF) == 0 then 264 + n = n + 8 265 + a = a >> 8 266 + end 267 + if (a & 0x0000000F) == 0 then 268 + n = n + 4 269 + a = a >> 4 270 + end 271 + if (a & 0x00000003) == 0 then 272 + n = n + 2 273 + a = a >> 2 274 + end 275 + if (a & 0x00000001) == 0 then 276 + n = n + 1 277 + end 278 + return n 279 + end 280 + 281 + function ops.i32_popcnt(a) 282 + local n = 0 283 + for _ = 1, 32 do 284 + if (a & 1) == 1 then 285 + n = n + 1 286 + end 287 + a = a >> 1 288 + end 289 + return n 290 + end 291 + 292 + function ops.i32_add(a, b) 293 + return (a + b) & constants.I32_MAX 294 + end 295 + 296 + function ops.i32_sub(a, b) 297 + return (a - b) & constants.I32_MAX 298 + end 299 + 300 + function ops.i32_mul(a, b) 301 + return (a * b) & constants.I32_MAX 302 + end 303 + 304 + function ops.i32_div_s(a, b) 305 + a = intutil.signexti32(a) 306 + b = intutil.signexti32(b) 307 + return (a // b) & constants.I32_MAX 308 + end 309 + 310 + function ops.i32_div_u(a, b) 311 + return (a // b) & constants.I32_MAX 312 + end 313 + 314 + function ops.i32_rem_s(a, b) 315 + a = intutil.signexti32(a) 316 + b = intutil.signexti32(b) 317 + return (a % b) & constants.I32_MAX 318 + end 319 + 320 + function ops.i32_rem_u(a, b) 321 + return (a % b) & constants.I32_MAX 322 + end 323 + 324 + function ops.i32_and(a, b) 325 + return a & b 326 + end 327 + 328 + function ops.i32_or(a, b) 329 + return a | b 330 + end 331 + 332 + function ops.i32_xor(a, b) 333 + return a ~ b 334 + end 335 + 336 + function ops.i32_shl(a, b) 337 + return (a << b) & constants.I32_MAX 338 + end 339 + 340 + function ops.i32_shr_s(a, b) 341 + a = intutil.signexti32(a) 342 + b = intutil.signexti32(b) 343 + return (a >> b) & constants.I32_MAX 344 + end 345 + 346 + function ops.i32_shr_u(a, b) 347 + return (a >> b) & constants.I32_MAX 348 + end 349 + 350 + function ops.i32_rotl(a, b) 351 + local c = b % 32 352 + return ((a << c) | (a >> (32 - c))) & constants.I32_MAX 353 + end 354 + 355 + function ops.i32_rotr(a, b) 356 + local c = b % 32 357 + return ((a >> c) | (a << (32 - c))) & constants.I32_MAX 155 358 end 156 359 157 360 return ops
+190 -24
wasmlib.lua
··· 2 2 3 3 local constants = require("constants") 4 4 local ops = require("ops") 5 + local frame = require("frame") 6 + local intutil = require("intutil") 5 7 6 8 wasmlib.VM = { 7 9 stack = {}, 10 + stackFrames = {}, 11 + functions = {}, 12 + types = {}, 8 13 } 9 14 15 + function wasmlib.VM:topFrame() 16 + return self.stackFrames[#self.stackFrames] 17 + end 18 + 10 19 function wasmlib.VM:new() 11 20 local vm = {} 12 21 setmetatable(vm, {__index = self}) 13 22 return vm 14 23 end 15 24 25 + function wasmlib.VM:triop(f) 26 + local c = table.remove(self.stack) 27 + local b = table.remove(self.stack) 28 + local a = table.remove(self.stack) 29 + table.insert(self.stack, f(a, b, c)) 30 + end 31 + 16 32 function wasmlib.VM:binop(f) 17 - local a = table.remove(self.stack) 18 33 local b = table.remove(self.stack) 34 + local a = table.remove(self.stack) 19 35 table.insert(self.stack, f(a, b)) 20 36 end 21 37 ··· 24 40 table.insert(self.stack, f(a)) 25 41 end 26 42 27 - function wasmlib.VM:doOperation(opcode) 43 + function wasmlib.VM:readarg8() 44 + local curFrame = self.topFrame() 45 + local body = self.functions[curFrame.funcIndex].body 46 + local result = body[curFrame.pc + 1] 47 + curFrame.pc = curFrame.pc + 1 48 + return result 49 + end 50 + 51 + function wasmlib.VM:readarg32() 52 + local curFrame = self:topFrame() 53 + local body = self.functions[curFrame.funcIndex].body 54 + local result = intutil.fromle32(body, curFrame.pc + 1) 55 + curFrame.pc = curFrame.pc + 4 56 + return result 57 + end 58 + 59 + function wasmlib.VM:local_get() 60 + local curFrame = self:topFrame() 61 + local localIdx = self:readarg32() 62 + local localVal = curFrame.locals[localIdx] 63 + if localVal == nil then 64 + error("read uninitialised or out of bounds local") 65 + end 66 + table.insert(self.stack, localVal) 67 + end 68 + 69 + function wasmlib.VM:local_set() 70 + local curFrame = self:topFrame() 71 + local localIdx = self:readarg32() 72 + local localVal = table.remove(self.stack) 73 + curFrame.locals[localIdx] = localVal 74 + end 75 + 76 + function wasmlib.VM:call() 77 + local funcIdx = self:readarg32() 78 + self:invoke(funcIdx) 79 + end 80 + 81 + function wasmlib.VM:step() 82 + local curFrame = self:topFrame() 83 + local body = self.functions[curFrame.funcIndex].body 84 + local opcode = body[curFrame.pc] 85 + 28 86 local c = constants.opcodes 29 87 local optable = { 30 - [c.OP_NOP] = function() end, 31 - [c.OP_I64_EQZ] = function() self:unop (ops.i64_eqz) end, 32 - [c.OP_I64_EQ] = function() self:binop(ops.i64_eq) end, 33 - [c.OP_I64_NE] = function() self:binop(ops.i64_ne) end, 34 - [c.OP_I64_LT_S] = function() self:binop(ops.i64_lt_s) end, 35 - [c.OP_I64_GT_S] = function() self:binop(ops.i64_gt_s) end, 36 - [c.OP_I64_LE_S] = function() self:binop(ops.i64_le_s) end, 37 - [c.OP_I64_GE_S] = function() self:binop(ops.i64_ge_s) end, 38 - [c.OP_I64_CLZ] = function() self:unop (ops.i64_clz) end, 39 - [c.OP_I64_CTZ] = function() self:unop (ops.i64_ctz) end, 88 + -- control 89 + [c.OP_UNREACHABLE] = function() error("unreachable") end, 90 + [c.OP_NOP] = function() end, 91 + -- BLOCK 92 + -- LOOP 93 + -- IF 94 + -- ELSE 95 + -- END 96 + -- BR 97 + -- BR_IF 98 + -- BR_TABLE 99 + [c.OP_RETURN] = function() self:ret() end, 100 + [c.OP_CALL] = function() self:call() end, 101 + -- CALL_INDIRECT 102 + -- parametric 103 + [c.OP_DROP] = function() table.remove(self.stack) end, 104 + [c.OP_SELECT] = function() self:triop(ops.select) end, 105 + -- variable 106 + [c.OP_LOCAL_GET] = function() self:local_get() end, 107 + [c.OP_LOCAL_SET] = function() self:local_set() end, 108 + -- LOCAL_TEE 109 + -- GLOBAL_GET 110 + -- GLOBAL_SET 111 + -- memory 112 + -- I32_LOAD 113 + -- I64_LOAD 114 + -- [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 127 + -- [floart instrs] 128 + -- I32_STORE8 129 + -- I32_STORE16 130 + -- I64_STORE8 131 + -- I64_STORE16 132 + -- I64_STORE32 133 + -- MEMORY_SIZE 134 + -- MEMORY_GROW 135 + -- i32 comparisons 136 + [c.OP_I32_EQZ] = function() self:unop (ops.i32_eqz) end, 137 + [c.OP_I32_EQ] = function() self:binop(ops.i32_eq) end, 138 + [c.OP_I32_NE] = function() self:binop(ops.i32_ne) end, 139 + [c.OP_I32_LT_S] = function() self:binop(ops.i32_lt_s) end, 140 + [c.OP_I32_LT_U] = function() self:binop(ops.i32_lt_u) end, 141 + [c.OP_I32_GT_S] = function() self:binop(ops.i32_gt_s) end, 142 + [c.OP_I32_GT_U] = function() self:binop(ops.i32_gt_u) end, 143 + [c.OP_I32_LE_S] = function() self:binop(ops.i32_le_s) end, 144 + [c.OP_I32_LE_U] = function() self:binop(ops.i32_le_u) end, 145 + -- i64 comparisons 146 + [c.OP_I64_EQZ] = function() self:unop (ops.i64_eqz) end, 147 + [c.OP_I64_EQ] = function() self:binop(ops.i64_eq) end, 148 + [c.OP_I64_NE] = function() self:binop(ops.i64_ne) end, 149 + [c.OP_I64_LT_S] = function() self:binop(ops.i64_lt_s) end, 150 + -- I64_LT_U 151 + [c.OP_I64_GT_S] = function() self:binop(ops.i64_gt_s) end, 152 + -- I64_GT_U 153 + [c.OP_I64_LE_S] = function() self:binop(ops.i64_le_s) end, 154 + -- I64_LE_U 155 + [c.OP_I64_GE_S] = function() self:binop(ops.i64_ge_s) end, 156 + -- I64_GE_U 157 + -- [float comparisons] 158 + -- i32 operations 159 + [c.OP_I32_CLZ] = function() self:unop (ops.i32_clz) end, 160 + [c.OP_I32_CTZ] = function() self:unop (ops.i32_ctz) end, 161 + [c.OP_I32_POPCNT] = function() self:unop (ops.i32_popcnt) end, 162 + [c.OP_I32_ADD] = function() self:binop(ops.i32_add) end, 163 + [c.OP_I32_SUB] = function() self:binop(ops.i32_sub) end, 164 + [c.OP_I32_MUL] = function() self:binop(ops.i32_mul) end, 165 + [c.OP_I32_DIV_S] = function() self:binop(ops.i32_div_s) end, 166 + [c.OP_I32_DIV_U] = function() self:binop(ops.i32_div_u) end, 167 + [c.OP_I32_REM_S] = function() self:binop(ops.i32_rem_s) end, 168 + [c.OP_I32_REM_U] = function() self:binop(ops.i32_rem_u) end, 169 + [c.OP_I32_AND] = function() self:binop(ops.i32_and) end, 170 + [c.OP_I32_OR] = function() self:binop(ops.i32_or) end, 171 + [c.OP_I32_XOR] = function() self:binop(ops.i32_xor) end, 172 + [c.OP_I32_SHL] = function() self:binop(ops.i32_shl) end, 173 + [c.OP_I32_SHR_S] = function() self:binop(ops.i32_shr_s) end, 174 + [c.OP_I32_SHR_U] = function() self:binop(ops.i32_shr_u) end, 175 + [c.OP_I32_ROTL] = function() self:binop(ops.i32_rotl) end, 176 + [c.OP_I32_ROTR] = function() self:binop(ops.i32_rotr) end, 177 + -- i64 operations 178 + [c.OP_I64_CLZ] = function() self:unop (ops.i64_clz) end, 179 + [c.OP_I64_CTZ] = function() self:unop (ops.i64_ctz) end, 40 180 [c.OP_I64_POPCNT] = function() self:unop (ops.i64_popcnt) end, 41 - [c.OP_I64_ADD] = function() self:binop(ops.i64_add) end, 42 - [c.OP_I64_SUB] = function() self:binop(ops.i64_sub) end, 43 - [c.OP_I64_MUL] = function() self:binop(ops.i64_mul) end, 44 - [c.OP_I64_DIV_S] = function() self:binop(ops.i64_div_s) end, 45 - [c.OP_I64_REM_S] = function() self:binop(ops.i64_rem_s) end, 46 - [c.OP_I64_AND] = function() self:binop(ops.i64_and) end, 47 - [c.OP_I64_OR] = function() self:binop(ops.i64_or) end, 48 - [c.OP_I64_XOR] = function() self:binop(ops.i64_xor) end, 49 - [c.OP_I64_SHL] = function() self:binop(ops.i64_shl) end, 50 - [c.OP_I64_SHR_S] = function() self:binop(ops.i64_shr_s) end, 51 - [c.OP_I64_ROTL] = function() self:binop(ops.i64_rotl) end, 52 - [c.OP_I64_ROTR] = function() self:binop(ops.i64_rotr) end, 181 + [c.OP_I64_ADD] = function() self:binop(ops.i64_add) end, 182 + [c.OP_I64_SUB] = function() self:binop(ops.i64_sub) end, 183 + [c.OP_I64_MUL] = function() self:binop(ops.i64_mul) end, 184 + [c.OP_I64_DIV_S] = function() self:binop(ops.i64_div_s) end, 185 + -- I64_DIV_U 186 + [c.OP_I64_REM_S] = function() self:binop(ops.i64_rem_s) end, 187 + -- I64_REM_U 188 + [c.OP_I64_AND] = function() self:binop(ops.i64_and) end, 189 + [c.OP_I64_OR] = function() self:binop(ops.i64_or) end, 190 + [c.OP_I64_XOR] = function() self:binop(ops.i64_xor) end, 191 + [c.OP_I64_SHL] = function() self:binop(ops.i64_shl) end, 192 + [c.OP_I64_SHR_S] = function() self:binop(ops.i64_shr_s) end, 193 + -- I64_SHR_U 194 + [c.OP_I64_ROTL] = function() self:binop(ops.i64_rotl) end, 195 + [c.OP_I64_ROTR] = function() self:binop(ops.i64_rotr) end, 196 + -- [float operations] 197 + -- conversions 198 + -- I32_WRAP_I64 199 + -- [float stuff] 200 + -- I64_EXTEND_I32_S 201 + -- I64_EXTEND_I32_U 202 + -- [float stuff] 53 203 } 54 204 55 205 local opfunc = optable[opcode] ··· 57 207 error("unimplemented") 58 208 end 59 209 opfunc() 210 + 211 + curFrame.pc = curFrame.pc + 1 212 + end 213 + 214 + function wasmlib.VM:invoke(funcIndex) 215 + local fr = frame.StackFrame:new(funcIndex) 216 + local f = self.functions[funcIndex] 217 + local sig = self.types[f.typeidx] 218 + for i = 1, #sig.arguments do 219 + fr.locals[#sig.arguments - i] = table.remove(self.stack) 220 + end 221 + table.insert(self.stackFrames, fr) 222 + end 223 + 224 + function wasmlib.VM:ret() 225 + table.remove(self.stackFrames) 60 226 end 61 227 62 228 return wasmlib