[PATCH 002/188] the initial commit

From bce2a7ed20747f29b4c9d00834e9f4b9e3cef5a0 Mon Sep 17 00:00:00 2001
From: Dmitry Boyarintsev <skalogryz.lists@gmail.com>
Date: Thu, 5 Sep 2019 17:03:31 -0400

git-svn-id: branches/wasm@45998 -
This commit is contained in:
nickysn 2020-08-03 12:58:42 +00:00
parent e173c688b0
commit 93d6993296
6 changed files with 410 additions and 0 deletions

5
.gitattributes vendored
View File

@ -18976,3 +18976,8 @@ utils/unicode/unihelper.lpr svneol=native#text/pascal
utils/unicode/weight_derivation.inc svneol=native#text/pascal
utils/usubst.pp svneol=native#text/plain
utils/wasmbin/README.md svneol=native#text/plain
utils/wasmbin/lebutils.pas svneol=native#text/plain
utils/wasmbin/wasmbin.pas svneol=native#text/plain
utils/wasmbin/wasmbindebug.pas svneol=native#text/plain
utils/wasmbin/wasmld.lpi svneol=native#text/plain
utils/wasmbin/wasmld.lpr svneol=native#text/plain

111
utils/wasmbin/lebutils.pas Normal file
View File

@ -0,0 +1,111 @@
unit lebutils;
interface
uses
SysUtils, Classes, wasmbin;
function ReadU(src: TStream): UInt64;
function ReadS(src: TStream; bits: Integer): Int64;
procedure ReadFuncTypesArray(src: TStream; var arr: TFuncTypeArray);
procedure ReadFuncType(src: TStream; var ft: TFuncType);
procedure ReadCodeEntry(src: TStream; var en: TCodeEntry);
procedure ReadCodeSection(src: TStream; var sc: TCodeSection);
implementation
procedure ReadFuncType(src: TStream; var ft: TFuncType);
var
c: integer;
begin
// vector of t1
c:=ReadU(src);
SetLength(ft.param, c);
src.Read(ft.param[0], c);
// vector of t2
c:=ReadU(src);
SetLength(ft.result, c);
src.Read(ft.result[0], c);
end;
procedure ReadFuncTypesArray(src: TStream; var arr: TFuncTypeArray);
var
cnt : integer;
i : Integer;
begin
cnt := ReadU(src);
SetLength(arr.funTypes, cnt);
for i:=0 to cnt-1 do begin
if src.ReadByte = func_type then
ReadFuncType(src, arr.funTypes[i]);
end;
end;
function ReadU(src: TStream): UInt64;
var
b : byte;
sh : integer;
begin
Result := 0;
sh := 0;
while true do begin
b := src.ReadByte;
Result := Result or ((b and $7f) shl sh);
if (b and $80)>0 then inc(sh, 7)
else break;
end;
end;
function ReadS(src: TStream; bits: Integer): Int64;
var
b : byte;
sh : Integer;
begin
result := 0;
sh := 0;
repeat
b := src.ReadByte;
result := Result or ((b and $77) shl sh);
inc(sh, 7);
until ((b and $80) = 0);
// sign bit of byte is second high order bit (0x40)
if (sh < bits) and ((b and $40) > 0) then
// sign extend
result := result or ( (not 0) shl sh);
end;
procedure ReadCodeEntry(src: TStream; var en: TCodeEntry);
var
sz : integer; // size in bytes
//pos : int64;
cnt : Integer;
i : integer;
begin
sz := ReadU(src);
cnt := ReadU(src);
SetLength(en.locals, cnt);
for i:=0 to cnt-1 do begin
en.locals[i].count := ReadU(src);
en.locals[i].valtyp := src.ReadByte;
end;
end;
procedure ReadCodeSection(src: TStream; var sc: TCodeSection);
var
cnt : integer;
i : integer;
begin
cnt := ReadU(src);
SetLength(sc.entries, cnt);
for i:= 0 to cnt-1 do
ReadCodeEntry(src, sc.entries[i]);
end;
end.

131
utils/wasmbin/wasmbin.pas Normal file
View File

@ -0,0 +1,131 @@
unit wasmbin;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
const
valtype_i32 = $7f;
valtype_i64 = $7e;
valtype_f32 = $7d;
valtype_f64 = $7C;
block_type = $40;
func_type = $60;
elem_type = $70;
global_const = $00;
global_mut = $01;
limit_min_inf = $00; // minimum - to infinity
limit_min_max = $01; // minimum - maximum
const
WasmId = #0'asm';
WasmId_Int = $6D736100;
const
sect_custom = 0; // custom section
sect_type = 1; // type section
sect_import = 2; // import section
sect_function = 3; // function section
sect_table = 4; // table section
sect_memory = 5; // memory section
sect_global = 6; // global section
sect_export = 7; // export section
sect_start = 8; // start section
sect_element = 9; // element section
sect_code = 10; // code section
sect_data = 11; // data section
type
TSection = packed record
id : byte;
size : LongWord; // it is Leb128 encoded in the file, thus cannot be read directly
end;
TFuncType = record
param : array of byte;
result : array of byte;
end;
TFuncTypeArray = record
funTypes : array of TFuncType;
end;
TCodeLocalEntry = record
count : LongWord;
valtyp : Byte;
end;
TCodeInstr = record
inst : byte;
idxArr: array of LongWord;
case byte of
0: (align, offset : LongWord);
1: (index: LongWord);
2: (i32: LongWord);
3: (i64: UInt64);
4: (f32: single);
5: (f64: double);
// for labels
6: (idxCount: integer;
idxDef :LongWord);
7: (returnType: byte);
end;
TCodeEntry = record
locals : array of TCodeLocalEntry;
instCount : integer;
instr : array of TCodeInstr;
end;
TCodeSection = record
entries : array of TCodeEntry;
end;
function SectionIdToStr(id: integer): string;
function ValTypeToStr(id: integer): string;
implementation
function ValTypeToStr(id: integer): string;
begin
case id of
valtype_i32 : Result := 'i32';
valtype_i64 : Result := 'i64';
valtype_f32 : Result := 'f32';
valtype_f64 : Result := 'f64';
else
Str(id, Result);
Result := 'iUnk'+Result;
end
end;
function SectionIdToStr(id: integer): string;
begin
case id of
sect_custom : Result := 'custom'; // custom section
sect_type : Result := 'type'; // type section
sect_import : Result := 'import'; // import section
sect_function : Result := 'function'; // function section
sect_table : Result := 'table'; // table section
sect_memory : Result := 'memory'; // memory section
sect_global : Result := 'global'; // global section
sect_export : Result := 'export'; // export section
sect_start : Result := 'start'; // start section
sect_element : Result := 'element'; // element section
sect_code : Result := 'code'; // code section
sect_data : Result := 'data'; // data section
else
Str(id, Result);
Result := 'sect_unknown'+Result;
end;
end;
end.

View File

@ -0,0 +1,36 @@
unit wasmbindebug;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, wasmbin, lebutils;
procedure DumpTypes(sr: TStream);
implementation
procedure DumpTypes(sr: TStream);
var
ar : TFuncTypeArray;
i : integer;
j : integer;
begin
ReadFuncTypesArray(sr, ar);
for i:=0 to length(ar.funTypes)-1 do begin
write('#',i);
writeln;
write(' params:');
for j:=0 to length(ar.funTypes[i].param)-1 do
write(' ', ValTypeToStr(ar.funTypes[i].param[j]));
writeln;
write(' result:');
for j:=0 to length(ar.funTypes[i].result)-1 do
write(' ', ValTypeToStr(ar.funTypes[i].result[j]));
writeln;
end;
end;
end.

68
utils/wasmbin/wasmld.lpi Normal file
View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<General>
<Flags>
<MainUnitHasCreateFormStatements Value="False"/>
<MainUnitHasTitleStatement Value="False"/>
<MainUnitHasScaledStatement Value="False"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<Title Value="wasmld"/>
<UseAppBundle Value="False"/>
<ResourceType Value="res"/>
</General>
<BuildModes Count="1">
<Item1 Name="Default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
<UseFileFilters Value="True"/>
</PublishOptions>
<RunParams>
<FormatVersion Value="2"/>
<Modes Count="0"/>
</RunParams>
<Units Count="3">
<Unit0>
<Filename Value="wasmld.lpr"/>
<IsPartOfProject Value="True"/>
</Unit0>
<Unit1>
<Filename Value="wasmbin.pas"/>
<IsPartOfProject Value="True"/>
</Unit1>
<Unit2>
<Filename Value="wasmbindebug.pas"/>
<IsPartOfProject Value="True"/>
</Unit2>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="wasmld"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
</CompilerOptions>
<Debugging>
<Exceptions Count="3">
<Item1>
<Name Value="EAbort"/>
</Item1>
<Item2>
<Name Value="ECodetoolError"/>
</Item2>
<Item3>
<Name Value="EFOpenError"/>
</Item3>
</Exceptions>
</Debugging>
</CONFIG>

59
utils/wasmbin/wasmld.lpr Normal file
View File

@ -0,0 +1,59 @@
program wasmld;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
{ you can add units after this }
Classes, SysUtils, wasmbin, lebutils, wasmbindebug;
function ReadStream(st: TStream): Boolean;
var
dw : LongWord;
ofs : int64;
sc : TSection;
ps : int64;
begin
dw := st.ReadDWord;
Result := dw = WasmId_Int;
if not Result then begin
writeln('not a wasm file');
Exit;
end;
dw := st.ReadDWord;
writeln('version: ', dw);
while st.Position<st.Size do begin
ofs := st.Position;
sc.id := st.ReadByte;
sc.Size := ReadU(st);
writeln(ofs,': id=', sc.id,'(', SectionIdToStr(sc.id),') sz=', sc.size);
ps := st.Position+sc.size;
if sc.id= 1 then DumpTypes(st);
if st.Position <> ps then
begin
writeln('adjust stream targ=',ps,' actual: ', st.position);
st.Position := ps;
end;
end;
end;
var
fs :TFileStream;
begin
if ParamCount=0 then begin
writeln('please sepcify .wasm file');
exit;
end;
fs := TFileStream.Create(ParamStr(1), fmOpenRead or fmShareDenyNone);
try
ReadStream(fs);
finally
fs.Free;
end;
end.