Browse Source

[PATCH 002/188] the initial commit

From bce2a7ed20747f29b4c9d00834e9f4b9e3cef5a0 Mon Sep 17 00:00:00 2001
From: Dmitry Boyarintsev <[email protected]>
Date: Thu, 5 Sep 2019 17:03:31 -0400

git-svn-id: branches/wasm@45998 -
nickysn 5 years ago
parent
commit
93d6993296

+ 5 - 0
.gitattributes

@@ -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 - 0
utils/wasmbin/lebutils.pas

@@ -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 - 0
utils/wasmbin/wasmbin.pas

@@ -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.
+

+ 36 - 0
utils/wasmbin/wasmbindebug.pas

@@ -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 - 0
utils/wasmbin/wasmld.lpi

@@ -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 - 0
utils/wasmbin/wasmld.lpr

@@ -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.
+