Browse Source

+ generate the global section in the wasm internal linker exe writer

Nikolay Nikolov 1 year ago
parent
commit
d03963afe9
1 changed files with 161 additions and 18 deletions
  1. 161 18
      compiler/ogwasm.pas

+ 161 - 18
compiler/ogwasm.pas

@@ -41,17 +41,30 @@ interface
     type
       TWasmObjSymbolExtraData = class;
 
+      TGlobalInitializer = record
+        case typ:TWasmBasicType of
+          wbt_i32: (init_i32: Int32);
+          wbt_i64: (init_i64: Int64);
+          wbt_f32: (init_f32: Single);
+          wbt_f64: (init_f64: Double);
+      end;
+
       { TWasmObjSymbolLinkingData }
 
       TWasmObjSymbolLinkingData = class
       public
         ImportModule: string;
         ImportName: string;
+
         FuncType: TWasmFuncType;
         ExeFunctionIndex: Integer;
         ExeIndirectFunctionTableIndex: Integer;
         ExeTypeIndex: Integer;
 
+        GlobalType: TWasmBasicType;
+        GlobalIsMutable: Boolean;
+        GlobalInitializer: TGlobalInitializer;
+
         constructor Create;
         destructor Destroy;override;
       end;
@@ -369,6 +382,36 @@ implementation
         until Done;
       end;
 
+{$ifdef FPC_LITTLE_ENDIAN}
+    procedure WriteF32LE(d: tdynamicarray; v: Single);
+      begin
+        d.write(v,4);
+      end;
+
+    procedure WriteF64LE(d: tdynamicarray; v: Double);
+      begin
+        d.write(v,8);
+      end;
+{$else FPC_LITTLE_ENDIAN}
+    procedure WriteF32LE(d: tdynamicarray; v: Single);
+      var
+        tmpI: UInt32;
+      begin
+        Move(v,tmpI,4);
+        tmpI:=SwapEndian(tmpI);
+        d.write(tmpI,4);
+      end;
+
+    procedure WriteF64LE(d: tdynamicarray; v: Double);
+      var
+        tmpI: UInt64;
+      begin
+        Move(v,tmpI,8);
+        tmpI:=SwapEndian(tmpI);
+        d.write(tmpI,8);
+      end;
+{$endif FPC_LITTLE_ENDIAN}
+
     procedure WriteByte(d: tdynamicarray; b: byte);
       begin
         d.write(b,1);
@@ -2345,6 +2388,7 @@ implementation
           IsMutable: Boolean;
           IsExported: Boolean;
           ExportName: ansistring;
+          GlobalInit: TGlobalInitializer;
         end;
         GlobalTypeImportsCount: uint32;
 
@@ -3205,12 +3249,11 @@ implementation
 
         function ReadGlobalSection: Boolean;
 
-          function ParseExpr: Boolean;
+          function ParseExpr(out Init: TGlobalInitializer): Boolean;
             var
-              B: Byte;
-              tmpbuf: array [1..8] of Byte;
-              tmpInt32: int32;
-              tmpInt64: int64;
+              B, B2: Byte;
+              tmpU32: UInt32;
+              tmpU64: UInt64;
             begin
               Result:=False;
               repeat
@@ -3220,20 +3263,46 @@ implementation
                   $0B:  { end }
                     ;
                   $41:  { i32.const }
-                    if not ReadSleb32(tmpInt32) then
-                      exit;
+                    begin
+                      Init.typ:=wbt_i32;
+                      if not ReadSleb32(Init.init_i32) then
+                        exit;
+                    end;
                   $42:  { i64.const }
-                    if not ReadSleb(tmpInt64) then
-                      exit;
+                    begin
+                      Init.typ:=wbt_i64;
+                      if not ReadSleb(Init.init_i64) then
+                        exit;
+                    end;
                   $43:  { f32.const }
-                    if not Read(tmpbuf, 4) then
-                      exit;
+                    begin
+                      Init.typ:=wbt_f32;
+                      if not Read(tmpU32, 4) then
+                        exit;
+{$ifdef FPC_BIG_ENDIAN}
+                      tmpU32:=SwapEndian(tmpU32);
+{$endif FPC_BIG_ENDIAN}
+                      Move(tmpU32,Init.init_f32,4);
+                    end;
                   $44:  { f64.const }
-                    if not Read(tmpbuf, 8) then
-                      exit;
+                    begin
+                      Init.typ:=wbt_f64;
+                      if not Read(tmpU64, 8) then
+                        exit;
+{$ifdef FPC_BIG_ENDIAN}
+                      tmpU64:=SwapEndian(tmpU64);
+{$endif FPC_BIG_ENDIAN}
+                      Move(tmpU64,Init.init_f64,8);
+                    end;
                   $D0:  { ref.null }
-                    if not Read(tmpbuf, 1) then
-                      exit;
+                    begin
+                      if not Read(B2, 1) then
+                        exit;
+                      if not decode_wasm_basic_type(B2, Init.typ) then
+                        exit;
+                      if not (Init.typ in WasmReferenceTypes) then
+                        exit;
+                    end;
                   else
                     begin
                       InputError('Unsupported opcode in global initializer');
@@ -3292,11 +3361,16 @@ implementation
                         exit;
                       end;
                   end;
-                  if not ParseExpr then
+                  if not ParseExpr(GlobalInit) then
                     begin
                       InputError('Error parsing the global initializer expression in the global section');
                       exit;
                     end;
+                  if GlobalInit.typ<>valtype then
+                    begin
+                      InputError('Initializer expression for global produces a type, which does not match the type of the global');
+                      exit;
+                    end;
                 end;
             if AReader.Pos<>(SectionStart+SectionSize) then
               begin
@@ -3969,9 +4043,14 @@ implementation
                       objsym.objsection:=ObjData.createsection('.wasm_globals.n_'+SymName,1,[oso_Data,oso_load],true);
                       if objsym.objsection.Size=0 then
                         objsym.objsection.WriteZeros(1);
+                      if (SymFlags and WASM_SYM_EXPLICIT_NAME)=0 then
+                        TWasmObjSection(objsym.objsection).MainFuncSymbol:=objsym;
                       objsym.offset:=0;
                       objsym.size:=1;
+                      objsym.LinkingData.GlobalInitializer:=GlobalTypes[SymIndex].GlobalInit;
                     end;
+                  objsym.LinkingData.GlobalType:=GlobalTypes[SymIndex].valtype;
+                  objsym.LinkingData.GlobalIsMutable:=GlobalTypes[SymIndex].IsMutable;
                 end;
               byte(SYMTAB_SECTION),
               byte(SYMTAB_EVENT),
@@ -4295,6 +4374,63 @@ implementation
             WriteUleb(FWasmSections[wsiElement],FIndirectFunctionTable[i].FuncIdx);
         end;
 
+      procedure WriteGlobalSection;
+        var
+          exesec: TExeSection;
+          globals_count, i: Integer;
+          objsec: TWasmObjSection;
+        begin
+          exesec:=FindExeSection('.wasm_globals');
+          if not assigned(exesec) then
+            internalerror(2024010112);
+          globals_count:=exesec.ObjSectionList.Count;
+          if globals_count<>exesec.Size then
+            internalerror(2024010113);
+          WriteUleb(FWasmSections[wsiGlobal],globals_count);
+          for i:=0 to exesec.ObjSectionList.Count-1 do
+            begin
+              objsec:=TWasmObjSection(exesec.ObjSectionList[i]);
+              WriteByte(FWasmSections[wsiGlobal],encode_wasm_basic_type(objsec.MainFuncSymbol.LinkingData.GlobalType));
+              if objsec.MainFuncSymbol.LinkingData.GlobalIsMutable then
+                WriteByte(FWasmSections[wsiGlobal],1)
+              else
+                WriteByte(FWasmSections[wsiGlobal],0);
+              { initializer expr }
+              with objsec.MainFuncSymbol.LinkingData.GlobalInitializer do
+                case typ of
+                  wbt_i32:
+                    begin
+                      WriteByte(FWasmSections[wsiGlobal],$41);  { i32.const }
+                      WriteSleb(FWasmSections[wsiGlobal],init_i32);
+                    end;
+                  wbt_i64:
+                    begin
+                      WriteByte(FWasmSections[wsiGlobal],$42);  { i64.const }
+                      WriteSleb(FWasmSections[wsiGlobal],init_i64);
+                    end;
+                  wbt_f32:
+                    begin
+                      WriteByte(FWasmSections[wsiGlobal],$43);  { f32.const }
+                      WriteF32LE(FWasmSections[wsiGlobal],init_f32);
+                    end;
+                  wbt_f64:
+                    begin
+                      WriteByte(FWasmSections[wsiGlobal],$44);  { f64.const }
+                      WriteF64LE(FWasmSections[wsiGlobal],init_f64);
+                    end;
+                  wbt_funcref,
+                  wbt_externref:
+                    begin
+                      WriteByte(FWasmSections[wsiGlobal],$D0);  { ref.null }
+                      WriteByte(FWasmSections[wsiGlobal],encode_wasm_basic_type(typ));
+                    end;
+                  else
+                    internalerror(2024010114);
+                end;
+              WriteByte(FWasmSections[wsiGlobal],$0B);  { end }
+            end;
+        end;
+
       begin
         result:=false;
 
@@ -4303,6 +4439,7 @@ implementation
         WriteCodeSegments;
         WriteDataSegments;
         WriteTableAndElemSections;
+        WriteGlobalSection;
 
         WriteUleb(FWasmSections[wsiMemory],1);
         WriteByte(FWasmSections[wsiMemory],0);
@@ -4317,6 +4454,7 @@ implementation
         WriteWasmSection(wsiFunction);
         WriteWasmSection(wsiTable);
         WriteWasmSection(wsiMemory);
+        WriteWasmSection(wsiGlobal);
         WriteWasmSection(wsiElement);
         WriteWasmSection(wsiDataCount);
         WriteWasmSection(wsiCode);
@@ -4496,14 +4634,19 @@ implementation
       const
         StackPointerSymStr='__stack_pointer';
       var
-        objsym: TObjSymbol;
+        objsym: TWasmObjSymbol;
       begin
         if aname=StackPointerSymStr then
           begin
             internalObjData.createsection('*'+aname,1,[oso_Data,oso_load]);
-            objsym:=internalObjData.SymbolDefine(aname,AB_GLOBAL,AT_WASM_GLOBAL);
+            objsym:=TWasmObjSymbol(internalObjData.SymbolDefine(aname,AB_GLOBAL,AT_WASM_GLOBAL));
             objsym.size:=1;
             objsym.ObjSection.WriteZeros(1);
+            TWasmObjSection(objsym.ObjSection).MainFuncSymbol:=objsym;
+            objsym.LinkingData.GlobalType:=wbt_i32;
+            objsym.LinkingData.GlobalIsMutable:=True;
+            objsym.LinkingData.GlobalInitializer.typ:=wbt_i32;
+            objsym.LinkingData.GlobalInitializer.init_i32:=0;
           end
         else
           inherited;