123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- unit wasmbinwriter;
- {$mode objfpc}{$H+}
- interface
- uses
- Classes, SysUtils, wasmmodule, wasmbin, lebutils, wasmbincode
- ,wasmlink;
- type
- TSectionRec = record
- secpos : int64;
- szpos : int64;
- datapos : int64;
- endofdata : int64;
- end;
- { TBinWriter }
- TBinWriter = class
- protected
- dst : TStream;
- org : TStream;
- strm : TList;
- // the list of relocations per module
- reloc : array of TRelocationEntry;
- relocCount : integer;
- recOfs : int64;
- procedure AddReloc(relocType: byte; ofs: int64; index: UInt32);
- procedure WriteRelocU32(u: longword);
- procedure SectionBegin(secId: byte; out secRec: TSectionRec; secsize: longWord=0);
- function SectionEnd(var secRec: TSectionRec): Boolean;
- procedure WriteInstList(list: TWasmInstrList);
- procedure WriteFuncTypeSect(m: TWasmModule);
- procedure WriteFuncSect(m: TWasmModule);
- procedure WriteExportSect(m: TWasmModule);
- procedure WriteCodeSect(m: TWasmModule);
- procedure pushStream(st: TStream);
- function popStream: TStream;
- public
- keepLeb128 : Boolean; // keep leb128 at 4 offset relocatable
- writeReloc : Boolean; // writting relocation (linking) information
- constructor Create;
- destructor Destroy; override;
- function Write(m: TWasmModule; adst: TStream): Boolean;
- end;
- function WriteModule(m: TWasmModule; dst: TStream): Boolean;
- type
- TLocalsInfo = record
- count : Integer;
- tp : byte;
- end;
- TLocalInfoArray = array of TLocalsInfo;
- // returns the list of local arrays
- procedure GetLocalInfo(func: TWasmFunc; out loc: TLocalInfoArray);
- implementation
- procedure GetLocalInfo(func: TWasmFunc; out loc: TLocalInfoArray);
- var
- i : integer;
- cnt : integer;
- tp : byte;
- nt : byte;
- j : integer;
- procedure Push;
- begin
- if j=length(loc) then begin
- if j=0 then SetLength(loc, 1)
- else SetLength(loc, j*2);
- end;
- loc[j].tp:=tp;
- loc[j].count:=cnt;
- inc(j);
- end;
- begin
- SetLength(Loc, 0);
- if func.LocalsCount = 0 then Exit;
- cnt:=1;
- tp:=func.GetLocal(0).tp;
- j:=0;
- for i:=1 to func.LocalsCount-1 do begin
- nt := func.GetLocal(i).tp;
- if nt<>tp then begin
- Push;
- tp:=nt;
- cnt:=1;
- end else
- inc(cnt);
- end;
- Push;
- SetLength(loc, j);
- end;
- function WriteModule(m: TWasmModule; dst: TStream): Boolean;
- var
- bw : TBinWriter;
- begin
- bw := TBinWriter.Create;
- try
- bw.keepLeb128:=true;
- Normalize(m);
- Result := bw.Write(m, dst);
- finally
- bw.Free;
- end;
- end;
- { TBinWriter }
- procedure TBinWriter.AddReloc(relocType: byte; ofs: int64; index: UInt32);
- begin
- if relocCount=length(reloc) then begin
- if relocCount=0 then SetLength(reloc, 16)
- else SetLength(reloc, relocCount*2);
- end;
- reloc[relocCount].reltype:=relocType;
- reloc[relocCount].offset:=ofs+recOfs;
- reloc[relocCount].index:=index;
- inc(relocType);
- end;
- procedure TBinWriter.WriteRelocU32(u: longword);
- begin
- WriteU(dst, u, sizeof(u)*8, keepLeb128);
- end;
- function TBinWriter.Write(m: TWasmModule; adst: TStream): Boolean;
- var
- l : Longword;
- begin
- if not Assigned(m) or not Assigned(adst) then begin
- Result:=false;
- Exit;
- end;
- dst:=adst;
- org:=adst;
- dst.Write(WasmId_Buf, length(WasmId_Buf));
- l:=NtoLE(Wasm_Version1);
- dst.Write(l, sizeof(l));
- // 01 function type section
- WriteFuncTypeSect(m);
- // 03 function section
- WriteFuncSect(m);
- // 07 export section
- WriteExportSect(m);
- // 10 code section
- WriteCodeSect(m);
- Result:=true;
- end;
- procedure TBinWriter.SectionBegin(secId: byte; out secRec: TSectionRec; secsize: longWord=0);
- begin
- secRec.secpos:=dst.Position;
- dst.WriteByte(secId);
- secRec.szpos:=dst.Position;
- WriteRelocU32(secsize);
- secRec.datapos:=dst.Position;
- secRec.endofdata:=dst.Position+secsize;
- end;
- function TBinWriter.SectionEnd(var secRec: TSectionRec): Boolean;
- var
- sz: LongWord;
- begin
- secRec.endofdata:=dst.Position;
- dst.Position:=secRec.szpos;
- sz := secRec.endofdata - secRec.datapos;
- WriteRelocU32(sz);
- dst.Position:=secRec.endofdata;
- Result := true;
- end;
- procedure TBinWriter.WriteFuncTypeSect(m: TWasmModule);
- var
- sc : TSectionRec;
- i : integer;
- j : integer;
- tp : TWasmFuncType;
- begin
- SectionBegin(SECT_TYPE, sc);
- WriteU32(dst, m.TypesCount);
- for i:=0 to m.TypesCount-1 do begin
- tp:=m.GetType(i);
- dst.WriteByte(func_type);
- WriteU32(dst, tp.ParamCount);
- for j:=0 to tp.ParamCount-1 do
- dst.WriteByte(tp.GetParam(i).tp);
- WriteU32(dst, tp.ResultCount);
- for j:=0 to tp.ResultCount-1 do
- dst.WriteByte(tp.GetResult(i).tp);
- end;
- SectionEnd(sc);
- end;
- procedure TBinWriter.WriteFuncSect(m: TWasmModule);
- var
- sc : TSectionRec;
- i : integer;
- begin
- SectionBegin(SECT_FUNCTION, sc);
- WriteU32(dst, m.FuncCount);
- for i:=0 to m.FuncCount-1 do
- WriteRelocU32(m.GetFunc(i).functype.typeNum);
- SectionEnd(sc);
- end;
- procedure TBinWriter.WriteExportSect(m: TWasmModule);
- var
- sc : TSectionRec;
- i : integer;
- x : TWasmExport;
- begin
- SectionBegin(SECT_EXPORT, sc);
- WriteU32(dst, m.ExportCount);
- for i:=0 to m.ExportCount-1 do begin
- x:=m.GetExport(i);
- WriteU32(dst, length(x.name));
- if length(x.name)>0 then
- dst.Write(x.name[1], length(x.name));
- dst.WriteByte(x.exportType);
- WriteRelocU32(x.exportNum);
- end;
- SectionEnd(sc);
- end;
- procedure TBinWriter.WriteCodeSect(m: TWasmModule);
- var
- sc : TSectionRec;
- i, j : integer;
- sz : int64;
- mem : TMemoryStream;
- la : TLocalInfoArray;
- f : TWasmFunc;
- begin
- SectionBegin(SECT_CODE, sc);
- mem:=TMemoryStream.Create;
- try
- WriteU32(dst, m.FuncCount);
- for i :=0 to m.FuncCount-1 do begin
- f:=m.GetFunc(i);
- GetLocalInfo(f, la);
- mem.Position:=0;
- pushStream(mem);
- WriteU32(dst, length(la));
- for j:=0 to length(la)-1 do begin
- WriteU32(dst, la[i].count);
- dst.WriteByte(la[i].tp);
- end;
- WriteInstList(f.instr);
- popStream;
- sz:=mem.Position;
- mem.Position:=0;
- WriteRelocU32(sz);
- dst.CopyFrom(mem, sz);
- end;
- finally
- mem.Free;
- end;
- SectionEnd(sc);
- end;
- procedure TBinWriter.WriteInstList(list: TWasmInstrList);
- var
- i : integer;
- ci : TWasmInstr;
- begin
- for i:=0 to list.Count-1 do begin
- ci :=list[i];
- dst.WriteByte(ci.code);
- case INST_FLAGS[ci.code].Param of
- ipLeb:
- if INST_RELOC_FLAGS[ci.code].doReloc then
- WriteRelocU32(ci.operandNum)
- else
- WriteU32(dst, ci.operandNum);
- end;
- end;
- end;
- procedure TBinWriter.pushStream(st: TStream);
- begin
- if st=nil then Exit;
- strm.Add(st);
- dst:=st;
- end;
- function TBinWriter.popStream: TStream;
- begin
- if strm.Count=0 then
- Result:=nil
- else begin
- Result:=TStream(strm[strm.Count-1]);
- strm.Delete(strm.Count-1);
- end;
- if strm.Count=0 then dst:=org
- else dst:=TStream(strm[strm.Count-1]);
- end;
- constructor TBinWriter.Create;
- begin
- inherited Create;
- strm:=TList.Create;
- end;
- destructor TBinWriter.Destroy;
- begin
- strm.Free;
- inherited Destroy;
- end;
- end.
|