quick and dirty pure lua webassembly interpreter
1
fork

Configure Feed

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

implement imports, binary parsing fixes

+84 -28
+9 -7
constants.lua
··· 206 206 -- Types are represented as an array where each element represents an operand: 207 207 -- * "b": byte 208 208 -- * "u": u32 209 + -- * "d": u32 index (needs to be incremented by 1 to account for lua 1-indexed arrays) 210 + -- (used for all index types except label indices, and _not_ memory offsets) 209 211 -- * "U": u64 210 212 -- * "i": i32 211 213 -- * "I": i64 ··· 219 221 [c.OP_BR] = {"u"}, 220 222 [c.OP_BR_IF] = {"u"}, 221 223 [c.OP_BR_TABLE] = {"Vu", "u"}, 222 - [c.OP_CALL] = {"u"}, 223 - [c.OP_CALL_INDIRECT] = {"u", "b"}, 224 + [c.OP_CALL] = {"d"}, 225 + [c.OP_CALL_INDIRECT] = {"d", "b"}, 224 226 -- parametric 225 227 -- variable 226 - [c.OP_LOCAL_GET] = {"u"}, 227 - [c.OP_LOCAL_SET] = {"u"}, 228 - [c.OP_LOCAL_TEE] = {"u"}, 229 - [c.OP_GLOBAL_GET] = {"u"}, 230 - [c.OP_GLOBAL_SET] = {"u"}, 228 + [c.OP_LOCAL_GET] = {"d"}, 229 + [c.OP_LOCAL_SET] = {"d"}, 230 + [c.OP_LOCAL_TEE] = {"d"}, 231 + [c.OP_GLOBAL_GET] = {"d"}, 232 + [c.OP_GLOBAL_SET] = {"d"}, 231 233 -- memory 232 234 [c.OP_I32_LOAD] = {"u", "u"}, 233 235 [c.OP_I64_LOAD] = {"u", "u"},
+7
strutil.lua
··· 1 + local strutil = {} 2 + 3 + function strutil.bytestostr(bytes, idx, len) 4 + return string.char(table.unpack(bytes, idx, idx + len - 1)) 5 + end 6 + 7 + return strutil
+68 -21
wasmlib.lua
··· 6 6 local memory = require("memory") 7 7 local intutil = require("intutil") 8 8 local fileutil = require("fileutil") 9 + local strutil = require("strutil") 9 10 10 11 wasmlib.VM = { 12 + numImportedFuncs = 0, 11 13 stack = {}, 12 14 stackFrames = {}, 13 15 labelStack = {}, ··· 15 17 types = {}, 16 18 memory = {}, 17 19 globals = {}, 20 + imports = {}, 18 21 } 19 22 20 23 function wasmlib.VM:new() ··· 413 416 end 414 417 415 418 function wasmlib.VM:step() 419 + if self:curFrame().pc >= #self:curBody() then 420 + self:ret() 421 + return 422 + end 423 + 416 424 local opcode = self:nextArg() 417 425 418 426 local c = constants.opcodes ··· 569 577 return idx + 4 570 578 end 571 579 572 - function wasmlib.VM:parseCustom(bytes, idx) 580 + function wasmlib.VM:parseCustom(bytes, idx) -- luacheck: no unused args 573 581 -- ignore custom sections 574 582 local szlen, size = intutil.fromuleb128(bytes, idx) 575 583 return idx + szlen + size ··· 612 620 return idx 613 621 end 614 622 615 - function wasmlib.VM:parseImports(bytes, idx) -- TODO 616 - print("warning: skipping imports section") 617 - local szlen, size = intutil.fromuleb128(bytes, idx) 618 - return idx + szlen + size 623 + function wasmlib.VM:parseImports(bytes, idx, imports) 624 + local szlen, _ = intutil.fromuleb128(bytes, idx) 625 + idx = idx + szlen 626 + local nilen, numImports = intutil.fromuleb128(bytes, idx) 627 + idx = idx + nilen 628 + 629 + for _ = 1, numImports do 630 + local mnllen, mnameLen = intutil.fromuleb128(bytes, idx) 631 + idx = idx + mnllen 632 + local moduleName = strutil.bytestostr(bytes, idx, mnameLen) 633 + idx = idx + mnameLen 634 + local nllen, nameLen = intutil.fromuleb128(bytes, idx) 635 + idx = idx + nllen 636 + local importName = strutil.bytestostr(bytes, idx, nameLen) 637 + idx = idx + nameLen 638 + 639 + local importType = bytes[idx] 640 + idx = idx + 1 641 + 642 + if importType == 0x00 then 643 + local typeidx = bytes[idx] 644 + idx = idx + 1 645 + table.insert(self.functions, { 646 + typeidx = typeidx + 1, 647 + import = imports[moduleName][importName], 648 + }) 649 + elseif importType == 0x01 then 650 + error("table imports not supported") 651 + elseif importType == 0x02 then 652 + error("memory imports not supported") 653 + elseif importType == 0x03 then 654 + error("global imports not supported") 655 + else 656 + error("invalid import type "..importType) 657 + end 658 + end 659 + 660 + self.numImportedFuncs = #self.functions 661 + return idx 619 662 end 620 663 621 664 function wasmlib.VM:parseFunctions(bytes, idx) ··· 624 667 local nflen, numFuncs = intutil.fromuleb128(bytes, idx) 625 668 idx = idx + nflen 626 669 627 - for i = 1, numFuncs do -- TODO handle imported functions 670 + for i = self.numImportedFuncs + 1, self.numImportedFuncs + numFuncs do 628 671 local tilen, typeidx = intutil.fromuleb128(bytes, idx) 629 672 idx = idx + tilen 630 - self.functions[i] = { typeidx = typeidx } 673 + self.functions[i] = { typeidx = typeidx + 1 } 631 674 end 632 675 633 676 return idx 634 677 end 635 678 636 - function wasmlib.VM:parseTables(bytes, idx) -- TODO 679 + function wasmlib.VM:parseTables(bytes, idx, imports) -- luacheck: no unused args 637 680 print("warning: skipping tables section") 638 681 local szlen, size = intutil.fromuleb128(bytes, idx) 639 682 return idx + szlen + size ··· 708 751 return idx 709 752 end 710 753 711 - function wasmlib.VM:parseExports(bytes, idx) -- TODO 754 + function wasmlib.VM:parseExports(bytes, idx) -- luacheck: no unused args 712 755 print("warning: skipping exports section") 713 756 local szlen, size = intutil.fromuleb128(bytes, idx) 714 757 return idx + szlen + size 715 758 end 716 759 717 - function wasmlib.VM:parseStart(bytes, idx) -- TODO 760 + function wasmlib.VM:parseStart(bytes, idx) -- luacheck: no unused args 718 761 print("warning: skipping start section") 719 762 local szlen, size = intutil.fromuleb128(bytes, idx) 720 763 return idx + szlen + size 721 764 end 722 765 723 - function wasmlib.VM:parseElements(bytes, idx) -- TODO 766 + function wasmlib.VM:parseElements(bytes, idx) -- luacheck: no unused args 724 767 print("warning: skipping elements section") 725 768 local szlen, size = intutil.fromuleb128(bytes, idx) 726 769 return idx + szlen + size 727 770 end 728 771 729 - function wasmlib.VM:parseCode(bytes, idx) -- TODO 772 + function wasmlib.VM:parseCode(bytes, idx) 730 773 local szlen, _ = intutil.fromuleb128(bytes, idx) 731 774 idx = idx + szlen 732 775 local nclen, numCode = intutil.fromuleb128(bytes, idx) 733 776 idx = idx + nclen 734 777 735 - for i = 1, numCode do -- TODO handle imported functions 778 + for i = self.numImportedFuncs + 1, self.numImportedFuncs + numCode do 736 779 -- size (ignored, not needed for decoding) 737 780 local cszlen, _ = intutil.fromuleb128(bytes, idx) 738 781 idx = idx + cszlen ··· 776 819 end 777 820 778 821 local operands = constants.operandTypes[opcode] or {} 779 - for _ = 1, #operands do 780 - local operand = operands[i] 822 + for j = 1, #operands do 823 + local operand = operands[j] 781 824 if operand == "b" then 782 825 local a = bytes[idx] 783 826 idx = idx + 1 784 827 table.insert(body, a) 785 - elseif operand == "u" or operand == "U" then 828 + elseif operand == "u" or operand == "U" or operand == "d" then 786 829 local alen, a = intutil.fromuleb128(bytes, idx) 830 + if operand == "d" then a = a + 1 end 787 831 idx = idx + alen 788 832 table.insert(body, a) 789 833 elseif operand == "i" then ··· 812 856 end 813 857 until nestDepth == -1 -- expr is terminated with an END opcode which isn't part of any control flow structure, 814 858 -- therefore the nestDepth should end up at -1 859 + self.functions[i].body = body 815 860 end 816 861 817 862 return idx 818 863 end 819 864 820 - function wasmlib.VM:parseData(bytes, idx) -- TODO 865 + function wasmlib.VM:parseData(bytes, idx) 821 866 local szlen, _ = intutil.fromuleb128(bytes, idx) 822 867 idx = idx + szlen 823 868 local ndlen, numData = intutil.fromuleb128(bytes, idx) ··· 844 889 return idx 845 890 end 846 891 847 - function wasmlib.VM:instantiate(bytes) 892 + function wasmlib.VM:instantiate(bytes, imports) 893 + self.imports = imports or {} 894 + 848 895 local idx = 1 849 896 idx = checkMagic(bytes, idx) 850 897 idx = checkVersion(bytes, idx) ··· 872 919 if sectParser == nil then 873 920 error("unsupported section type " .. sectId) 874 921 end 875 - idx = sectParser(self, bytes, idx) 922 + idx = sectParser(self, bytes, idx, imports) 876 923 end 877 924 end 878 925 879 - function wasmlib.VM:instantiateFile(path) 880 - self:instantiate(fileutil.readBytes(path)) 926 + function wasmlib.VM:instantiateFile(path, imports) 927 + self:instantiate(fileutil.readBytes(path), imports) 881 928 end 882 929 883 930 return wasmlib