public Global(Bin.TypeID type, bool mutable) { this.mutable = (mutable == true) ? Mutability.Variable : Mutability.Const; this.type = type; uint size = DataStore.GetTypeIDSize(type); this.store = new DataStore(size); }
private DefGlobal(int index, Bin.TypeID type, int elements, bool mutable, byte [] defaultValue) { this.index = index; this.defaultValue = defaultValue; this.type = type; this.elements = elements; this.mut = mutable ? Global.Mutability.Variable : Global.Mutability.Const; }
public void AddGlobalImp(string module, string fieldname, Bin.TypeID type, bool mutable) { this.indexingGlobal.Add(IndexEntry.CreateImport(this.importGlobalsCt, module, fieldname)); DefGlobal global = new DefGlobal(this.globals.Count, type, mutable); this.globals.Add(global); this.GetOrCreateRecord(module).globals.Add(fieldname, global); ++this.importGlobalsCt; }
//////////////////////////////////////////////////////////////////////////////// // // Add Table Declarations // //////////////////////////////////////////////////////////////////////////////// public void AddTableLoc(Bin.TypeID type, uint initialElements, uint?maxElements) { this._CheckTablesEmptyBeforeAdding(); uint maxele = maxElements ?? uint.MaxValue; this.indexingTable.Add(IndexEntry.CreateLocal(this.localTablesCt)); DefTable table = new DefTable(this.tables.Count, type, initialElements, initialElements, maxele); this.tables.Add(table); ++this.localTablesCt; }
public DefTable(int index, Bin.TypeID type, uint initialElements, uint minEntries, uint maxEntries) { this.index = index; this.defSegments = new List <DefSegment>(); uint typeSize = DataStore.GetTypeIDSize(type); this.type = type; this.elements = initialElements; this.limits = new LimitEntries( typeSize, minEntries, maxEntries); }
public void AddTableImp(string module, string fieldname, Bin.TypeID type, uint initialElements, uint?maxElements) { this._CheckTablesEmptyBeforeAdding(); uint maxele = maxElements ?? uint.MaxValue; this.indexingTable.Add(IndexEntry.CreateImport(this.importTablesCt, module, fieldname)); DefTable table = new DefTable(this.tables.Count, type, initialElements, initialElements, maxele); this.tables.Add(table); this.GetOrCreateRecord(module).tables.Add(fieldname, table); ++this.importTablesCt; }
public static uint GetTypeIDSize(Bin.TypeID type) { switch (type) { case Bin.TypeID.Int32: case Bin.TypeID.Float32: case Bin.TypeID.FuncRef: case Bin.TypeID.Function: return(4); case Bin.TypeID.Float64: case Bin.TypeID.Int64: return(8); } throw new System.Exception($"Attempting to query size of type of unknown size {type}"); }
public static StackOpd ConvertToStackType(Bin.TypeID tyid) { switch (tyid) { case Bin.TypeID.Float32: return(StackOpd.f32); case Bin.TypeID.Float64: return(StackOpd.f64); case Bin.TypeID.Int32: return(StackOpd.i32); case Bin.TypeID.Int64: return(StackOpd.i64); } return(StackOpd.Unknown); }
public DefGlobal(int index, Bin.TypeID type, bool mutable) : this(index, type, 1, mutable, null) { }
unsafe public static Module LoadBinary(byte *pb, ref uint idx, int endIdx) { // https://www.reddit.com/r/WebAssembly/comments/9vq019/is_anyone_learning_webassembly_in_binary_im_stuck/ // https://webassembly.github.io/wabt/demo/wat2wasm/ if (*((int *)(&pb[idx])) != BinParse.WASM_BINARY_MAGIC) { return(null); } idx += 4; if (*(int *)&pb[idx] != BinParse.WASM_BINARY_VERSION) { return(null); } idx += 4; Module ret = new Module(); while (idx < endIdx) { Bin.Section sectionCode = (Bin.Section)pb[idx]; ++idx; uint sectionSize = BinParse.LoadUnsignedLEB32(pb, ref idx); if (sectionCode == Bin.Section.CustomSec) { uint end = idx + sectionSize; while (true) { return(ret); // TODO: Considered end and unprocessed for now. // // uint nameLen = LoadUnsignedLEB32(pb, ref idx); // string customSecName = LoadString(pb, nameLen, ref idx); // // uint subType = LoadUnsignedLEB32(pb, ref idx); // uint subSize = LoadUnsignedLEB32(pb, ref idx); } } else if (sectionCode == Bin.Section.TypeSec) { uint numTypes = BinParse.LoadUnsignedLEB32(pb, ref idx); for (uint i = 0; i < numTypes; ++i) { Bin.TypeID type = (Bin.TypeID)BinParse.LoadUnsignedLEB32(pb, ref idx); if (type == Bin.TypeID.Function) { FunctionType fty = new FunctionType(); fty.typeid = (uint)type; ret.types.Add(fty); uint numParams = BinParse.LoadUnsignedLEB32(pb, ref idx); for (uint j = 0; j < numParams; ++j) { FunctionType.DataOrgInfo paramInfo = new FunctionType.DataOrgInfo(); paramInfo.type = (Bin.TypeID)BinParse.LoadUnsignedLEB32(pb, ref idx); fty.paramTypes.Add(paramInfo); } uint numResults = BinParse.LoadUnsignedLEB32(pb, ref idx); for (uint j = 0; j < numResults; ++j) { FunctionType.DataOrgInfo resultInfo = new FunctionType.DataOrgInfo(); resultInfo.type = (Bin.TypeID)BinParse.LoadUnsignedLEB32(pb, ref idx); fty.resultTypes.Add(resultInfo); } fty.InitializeOrganization(); } else { } } } else if (sectionCode == Bin.Section.ImportSec) { uint numImports = BinParse.LoadUnsignedLEB32(pb, ref idx); for (uint i = 0; i < numImports; ++i) { uint modnameLen = BinParse.LoadUnsignedLEB32(pb, ref idx); string modName = LoadString(pb, modnameLen, ref idx); uint fieldnameLen = BinParse.LoadUnsignedLEB32(pb, ref idx); string fieldName = LoadString(pb, fieldnameLen, ref idx); ImportType importTy = (ImportType)BinParse.LoadUnsignedLEB32(pb, ref idx); switch (importTy) { case ImportType.TypeIndex: { uint fnTyIdx = BinParse.LoadUnsignedLEB32(pb, ref idx); FunctionType fnTy = ret.types[(int)fnTyIdx]; ret.storeDecl.AddFunctionImp(modName, fieldName, fnTy); } break; case ImportType.TableType: { const int FLAG_HASMAX = 0x01; const int FLAG_OTHERS = ~(FLAG_HASMAX); // We may be able top unify parts of this code with non-imported tables uint type = BinParse.LoadUnsignedLEB32(pb, ref idx); uint flags = BinParse.LoadUnsignedLEB32(pb, ref idx); uint initial = BinParse.LoadUnsignedLEB32(pb, ref idx); uint?max = null; if ((flags & FLAG_HASMAX) != 0) { max = BinParse.LoadUnsignedLEB32(pb, ref idx); } if ((flags & FLAG_OTHERS) != 0) { throw new System.Exception("Encountered unknown flags for imported table."); } ret.storeDecl.AddTableImp(modName, fieldName, (Bin.TypeID)type, initial, max); } break; case ImportType.MemType: { const int FLAG_HASMAX = 0x01; const int FLAG_OTHERS = ~(FLAG_HASMAX); // We may be able to unify parts of this code with non-imported memory uint flags = BinParse.LoadUnsignedLEB32(pb, ref idx); uint initial = BinParse.LoadUnsignedLEB32(pb, ref idx); uint?max = null; if ((flags & FLAG_HASMAX) != 0) { max = BinParse.LoadUnsignedLEB32(pb, ref idx); } if ((flags & FLAG_OTHERS) != 0) { throw new System.Exception("Encountered unknown flags for imported memory."); } ret.storeDecl.AddMemoryImp(modName, fieldName, initial, initial, max); } break; case ImportType.GlobalType: { uint type = BinParse.LoadUnsignedLEB32(pb, ref idx); uint mutability = BinParse.LoadUnsignedLEB32(pb, ref idx); ret.storeDecl.AddGlobalImp(modName, fieldName, (Bin.TypeID)type, mutability != 0); } break; } } } else if (sectionCode == Bin.Section.FunctionSec) { uint numFunctions = BinParse.LoadUnsignedLEB32(pb, ref idx); for (uint i = 0; i < numFunctions; ++i) { Function function = new Function(ret); uint fnType = BinParse.LoadUnsignedLEB32(pb, ref idx); function.typeidx = fnType; function.fnType = ret.types[(int)fnType]; ret.storeDecl.AddFunctionLoc(function.fnType); ret.functions.Add(function); } } else if (sectionCode == Bin.Section.TableSec) { uint numTables = BinParse.LoadUnsignedLEB32(pb, ref idx); for (uint i = 0; i < numTables; ++i) { const int FLAG_HASMAX = 0x01; const int FLAG_OTHERS = ~(FLAG_HASMAX); Bin.TypeID ty = (Bin.TypeID)BinParse.LoadUnsignedLEB32(pb, ref idx); uint flags = BinParse.LoadUnsignedLEB32(pb, ref idx); uint initial = BinParse.LoadUnsignedLEB32(pb, ref idx); uint?max = null; if ((flags & FLAG_HASMAX) != 0) { max = BinParse.LoadUnsignedLEB32(pb, ref idx); } if ((flags & FLAG_OTHERS) != 0) { throw new System.Exception("Table section contains unsupported flags."); } ret.storeDecl.AddTableLoc(ty, initial, max); } } else if (sectionCode == Bin.Section.MemorySec) { // Prepare the declaration of memory regions. // // Note that this is only prepping for the data payloads, actual // parsing of that data happens in the Data section. uint numMems = BinParse.LoadUnsignedLEB32(pb, ref idx); // Right now this is assumed to be 1 for (uint i = 0; i < numMems; ++i) { const int FLAG_HASMAX = 0x01; const int FLAG_OTHERS = ~(FLAG_HASMAX); uint memFlags = BinParse.LoadUnsignedLEB32(pb, ref idx); uint memInitialPageCt = BinParse.LoadUnsignedLEB32(pb, ref idx); uint?memMaxPageCt = null; if ((memFlags & FLAG_HASMAX) != 0) { memMaxPageCt = BinParse.LoadUnsignedLEB32(pb, ref idx); } if ((memFlags & FLAG_OTHERS) != 0) { throw new System.Exception("Memory section contains unsupported flags."); } ret.storeDecl.AddMemoryLoc(memInitialPageCt, memInitialPageCt, memMaxPageCt); } } else if (sectionCode == Bin.Section.GlobalSec) { uint numGlobals = BinParse.LoadUnsignedLEB32(pb, ref idx); for (uint i = 0; i < numGlobals; ++i) { const int FLAG_MUTABLE = 0x01; const int FLAG_OTHERS = ~(FLAG_MUTABLE); uint globType = BinParse.LoadUnsignedLEB32(pb, ref idx); uint globFlags = BinParse.LoadUnsignedLEB32(pb, ref idx); bool mutable = (globFlags & FLAG_MUTABLE) != 0; if ((globFlags & FLAG_OTHERS) != 0) { throw new System.Exception("Global section contains unsupported flags."); } // For now we're just going to assume they do a type.const, then the value, // and then an end. // // I actually haven't read the specs to see what's allowed here. if (globType == (int)Bin.TypeID.Int32) { AssertConsumeByte(pb, ref idx, (byte)Instruction.i32_const); int idef = BinParse.LoadSignedLEB32(pb, ref idx); AssertConsumeByte(pb, ref idx, (byte)Instruction.end); ret.storeDecl.AddGlobalLoc(idef, mutable); } else if (globType == (int)Bin.TypeID.Float32) { AssertConsumeByte(pb, ref idx, (byte)Instruction.f32_const); float fdef = *(float *)&pb[idx]; idx += 4; AssertConsumeByte(pb, ref idx, (byte)Instruction.end); ret.storeDecl.AddGlobalLoc(fdef, mutable); } else if (globType == (int)Bin.TypeID.Int64) { AssertConsumeByte(pb, ref idx, (byte)Instruction.i64_const); long ldef = BinParse.LoadSignedLEB64(pb, ref idx); AssertConsumeByte(pb, ref idx, (byte)Instruction.end); ret.storeDecl.AddGlobalLoc(ldef, mutable); } else if (globType == (int)Bin.TypeID.Float64) { AssertConsumeByte(pb, ref idx, (byte)Instruction.f64_const); double ddef = *(float *)&pb[idx]; idx += 8; AssertConsumeByte(pb, ref idx, (byte)Instruction.end); ret.storeDecl.AddGlobalLoc(ddef, mutable); } else { throw new System.Exception("Unexpected global type."); } } } else if (sectionCode == Bin.Section.ExportSec) { uint numExports = BinParse.LoadUnsignedLEB32(pb, ref idx); for (uint i = 0; i < numExports; ++i) { uint strLen = BinParse.LoadUnsignedLEB32(pb, ref idx); string name = LoadString(pb, strLen, ref idx); uint kind = BinParse.LoadUnsignedLEB32(pb, ref idx); uint index = BinParse.LoadUnsignedLEB32(pb, ref idx); Export export = new Export(); export.name = name; export.kind = (ImportType)kind; export.index = index; ret.exports.Add(export); } } else if (sectionCode == Bin.Section.StartSec) { ret.startFnIndex = BinParse.LoadUnsignedLEB32(pb, ref idx); ret.ValidateStartFunction(true); } else if (sectionCode == Bin.Section.ElementSec) { uint numSegments = BinParse.LoadUnsignedLEB32(pb, ref idx); if (numSegments == 0) { continue; } if (ret.storeDecl.tables.Count < 1) { throw new System.Exception("Element(s) specified when no tables are defined."); } DefTable defTable = ret.storeDecl.tables[0]; for (uint i = 0; i < numSegments; ++i) { // Table index uint flags = BinParse.LoadUnsignedLEB32(pb, ref idx); DefSegment ds = new DefSegment(pb, ref idx, false); Bin.TypeID tabTy = ret.storeDecl.tables[0].type; uint tySize = DataStore.GetTypeIDSize(tabTy); uint elemCt = BinParse.LoadUnsignedLEB32(pb, ref idx); ds.data = new byte[elemCt * tySize]; fixed(byte *ptabdefs = ds.data) { switch (tabTy) { case Bin.TypeID.FuncRef: case Bin.TypeID.Int32: for (int j = 0; j < elemCt; ++j) { ((int *)ptabdefs)[j] = BinParse.LoadSignedLEB32(pb, ref idx); } break; case Bin.TypeID.Float32: for (int j = 0; j < elemCt; ++j) { ((float *)ptabdefs)[j] = *(float *)pb; idx += 4; } break; case Bin.TypeID.Int64: for (int j = 0; j < elemCt; ++j) { ((long *)ptabdefs)[j] = BinParse.LoadSignedLEB64(pb, ref idx); } break; case Bin.TypeID.Float64: for (int j = 0; j < elemCt; ++j) { ((double *)ptabdefs)[j] = *(double *)pb; idx += 8; } break; } } } } else if (sectionCode == Bin.Section.CodeSec) { uint numFunctions = BinParse.LoadUnsignedLEB32(pb, ref idx); for (uint i = 0; i < numFunctions; ++i) { Function function = ret.functions[(int)i]; uint bodySize = BinParse.LoadUnsignedLEB32(pb, ref idx); uint end = idx + bodySize; uint localsCount = BinParse.LoadUnsignedLEB32(pb, ref idx); for (int j = 0; j < localsCount; ++j) { // The number of consecutive occurences of this type uint localTyCt = BinParse.LoadUnsignedLEB32(pb, ref idx); // The type to place on the stack. The quantity of how many // is specified in localTyCt. uint type = BinParse.LoadUnsignedLEB32(pb, ref idx); for (int k = 0; k < localTyCt; ++k) { FunctionType.DataOrgInfo doi = new FunctionType.DataOrgInfo(); doi.type = (Bin.TypeID)type; function.localTypes.Add(doi); } } function.InitializeOrganization(); uint size = end - idx; function.expression = new byte[size]; System.Runtime.InteropServices.Marshal.Copy( (System.IntPtr)(int *)(&pb[idx]), function.expression, (int)0, (int)size); idx = end; } for (uint i = 0; i < numFunctions; ++i) { ret.functions[(int)i].ExpandExpressionToBeUsable(ret); } } else if (sectionCode == Bin.Section.DataSec) { uint numData = BinParse.LoadUnsignedLEB32(pb, ref idx); if (numData == 0) { continue; } if (ret.storeDecl.memories.Count < 1) { throw new System.Exception("Data(s) specified when no mems are defined."); } for (uint i = 0; i < numData; ++i) { uint segHeaderFlags = BinParse.LoadUnsignedLEB32(pb, ref idx); DefMem dmem = ret.storeDecl.memories[0]; DefSegment ds = new DefSegment(pb, ref idx, false); uint dataSz = BinParse.LoadUnsignedLEB32(pb, ref idx); ds.data = new byte[dataSz]; // We're going to do the copy manually, but if there's a C# // low-level copy function that also does this, that would be // prefered. for (uint j = 0; j < dataSz; ++j) { ds.data[j] = pb[idx + j]; } dmem.AddDefault(ds); //ret.storeDecl.memories[(int)i] = dmem; ret.storeDecl.memories[0] = dmem; idx += dataSz; } } else { throw new System.Exception("Encountered unknown Module section."); } } ++idx; return(ret); }
public StackOpd PopOpd(Bin.TypeID expect) { StackOpd soexp = ConvertToStackType(expect); return(this.PopOpd(soexp)); }
public void PushOpd(Bin.TypeID ty) { StackOpd so = ConvertToStackType(ty); this.PushOpd(so); }