Bläddra i källkod

[PATCH 04/83] update for Wasm target. adapting Karoly's changes from webassembly branch

From 8acd7baf8d14236dc12781dd15bac188581ccecf Mon Sep 17 00:00:00 2001
From: Dmitry Boyarintsev <[email protected]>
Date: Thu, 29 Aug 2019 15:09:58 -0400

git-svn-id: branches/wasm@45881 -
nickysn 5 år sedan
förälder
incheckning
6e7bb5927e

+ 4 - 0
.gitattributes

@@ -840,6 +840,7 @@ compiler/systems/i_os2.pas svneol=native#text/plain
 compiler/systems/i_palmos.pas svneol=native#text/plain
 compiler/systems/i_sunos.pas svneol=native#text/plain
 compiler/systems/i_symbian.pas svneol=native#text/plain
+compiler/systems/i_wasm.pas svneol=native#text/plain
 compiler/systems/i_watcom.pas svneol=native#text/plain
 compiler/systems/i_wdosx.pas svneol=native#text/plain
 compiler/systems/i_wii.pas svneol=native#text/plain
@@ -919,6 +920,7 @@ compiler/utils/samplecfg svneol=native#text/plain
 compiler/verbose.pas svneol=native#text/plain
 compiler/version.pas svneol=native#text/plain
 compiler/wasm/aasmcpu.pas svneol=native#text/plain
+compiler/wasm/agbinaryen.pas svneol=native#text/plain
 compiler/wasm/agwat.pas svneol=native#text/plain
 compiler/wasm/cgcpu.pas svneol=native#text/plain
 compiler/wasm/cpubase.pas svneol=native#text/plain
@@ -928,6 +930,7 @@ compiler/wasm/cpupara.pas svneol=native#text/plain
 compiler/wasm/cpupi.pas svneol=native#text/plain
 compiler/wasm/cputarg.pas svneol=native#text/plain
 compiler/wasm/hlcgcpu.pas svneol=native#text/plain
+compiler/wasm/itcpuwasm.pas svneol=native#text/plain
 compiler/wasm/rgcpu.pas svneol=native#text/plain
 compiler/wasm/rwasmcon.inc svneol=native#text/plain
 compiler/wasm/rwasmnor.inc svneol=native#text/plain
@@ -937,6 +940,7 @@ compiler/wasm/rwasmsri.inc svneol=native#text/plain
 compiler/wasm/rwasmstd.inc svneol=native#text/plain
 compiler/wasm/rwasmsup.inc svneol=native#text/plain
 compiler/wasm/symcpu.pas svneol=native#text/plain
+compiler/wasm/tgcpu.pas svneol=native#text/plain
 compiler/wasm/wasmdef.pas svneol=native#text/plain
 compiler/wasm/wasmreg.dat svneol=native#text/plain
 compiler/widestr.pas svneol=native#text/plain

+ 1 - 1
compiler/psub.pas

@@ -2095,7 +2095,7 @@ implementation
 
         { check if the definitions of certain types are available which might not be available in older rtls and
           which are assigned "on the fly" in types_dec }
-{$ifndef jvm}
+{$if not defined(jvm) and not defined(wasm)}
         if not assigned(rec_exceptaddr) then
           Message1(cg_f_internal_type_not_found,'TEXCEPTADDR');
         if not assigned(rec_tguid) then

+ 4 - 0
compiler/psystem.pas

@@ -369,6 +369,10 @@ implementation
         create_fpu_types;
         s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);
 {$endif jvm}
+{$ifdef wasm}
+        create_fpu_types;
+        s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);
+{$endif wasm}
         set_default_int_types;
         { some other definitions }
         charpointertype:=cpointerdef.create(cansichartype);

+ 1 - 0
compiler/systems.inc

@@ -244,6 +244,7 @@
              ,as_wasm_binaryen
              ,as_powerpc_gas_legacy    { for systems with very old GAS versions only, which don't support eg. named sections }
              ,as_llvm_clang
+             ,as_wasm_wabt
        );
 
        tlink = (ld_none,

+ 114 - 0
compiler/systems/i_wasm.pas

@@ -0,0 +1,114 @@
+{
+    Copyright (c) 2019 by Dmitry Boyarintsev
+
+    This unit implements support information structures for WebAssembly
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ ****************************************************************************
+}
+
+unit i_wasm;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       systems,rescmn;
+
+    const
+       res_wasmraw_info : tresinfo =
+           (
+             id     : res_none; // todo: not implemented. but could be as memory
+             resbin : 'fpcwasmres';
+             rescmd : '-o $OBJ $DBG';
+             rcbin  : '';
+             rccmd  : '';
+             resourcefileclass : nil;
+             resflags : [res_no_compile];
+           );
+
+        system_wasm_info : tsysteminfo =
+          (
+            system       : system_wasm_wasm32;
+            name         : 'WebAssembly';
+            shortname    : 'Wasm';
+            flags        : [tf_files_case_sensitive,tf_no_generic_stackcheck,
+                            { avoid the creation of threadvar tables }
+                            tf_section_threadvars];
+            cpu          : cpu_wasm;
+            unit_env     : '';
+            extradefines : '';
+            exeext       : '';
+            defext       : '.def';
+            scriptext    : '.sh';
+            smartext     : '.sl';
+            unitext      : '.ppu';
+            unitlibext   : '.ppl';
+            asmext       : '.wat';
+            objext       : '.wasm';
+            resext       : '';
+            resobjext    : '.wasm';
+            sharedlibext : '.wasm';
+            staticlibext : '.wasm';
+            staticlibprefix : '';
+            sharedlibprefix : '';
+            sharedClibext : '.wasm';
+            staticClibext : '.wasm';
+            staticClibprefix : '';
+            sharedClibprefix : '';
+            importlibprefix : '';
+            importlibext : '.wasm';
+            Cprefix      : '';
+            newline      : #10;
+            dirsep       : '/';
+            assem        : as_wasm_wabt;
+            assemextern  : as_wasm_binaryen;
+            link         : ld_none;
+            linkextern   : ld_none; // there's no linker, only object files for WASM
+            ar           : ar_none;
+            res          : res_none;
+            dbg          : dbg_none;
+            script       : script_unix;
+            endian       : endian_little;
+            alignment    :
+              (
+                procalign       : 4;
+                loopalign       : 4;
+                jumpalign       : 0;
+                jumpalignskipmax    : 0;
+                coalescealign   : 0;
+                coalescealignskipmax: 0;
+                constalignmin   : 0;
+                constalignmax   : 4;
+                varalignmin     : 4;
+                varalignmax     : 4;
+                localalignmin   : 4;
+                localalignmax   : 4;
+                recordalignmin  : 0;
+                recordalignmax  : 2;
+                maxCrecordalign : 4
+              );
+            first_parm_offset : 0;
+            stacksize   : 262144;
+            stackalign   : 4;
+            abi          : abi_default;
+            llvmdatalayout : 'todo';
+          );
+
+
+  implementation
+
+end.

+ 6 - 0
compiler/systems/t_wasm.pas

@@ -2,6 +2,12 @@ unit t_wasm;
 
 interface
 
+uses
+  systems, i_wasm, tgcpu;
+
 implementation
 
+initialization
+  RegisterTarget(system_wasm_info);
+
 end.

+ 6 - 5
compiler/wasm/aasmcpu.pas

@@ -121,9 +121,9 @@ implementation
       begin
         inherited create(op);
         ops:=1;
-        is_jmp:=op in [a_if_acmpeq, a_if_acmpne, a_if_icmpeq, a_if_icmpge, a_if_icmpgt,
-          a_if_icmple, a_if_icmplt, a_if_icmpne,
-          a_ifeq, a_ifge, a_ifgt, a_ifle, a_iflt, a_ifne, a_ifnonnull, a_ifnull, a_goto];
+        //is_jmp:=op in [a_if_acmpeq, a_if_acmpne, a_if_icmpeq, a_if_icmpge, a_if_icmpgt,
+        //  a_if_icmple, a_if_icmplt, a_if_icmpne,
+        //  a_ifeq, a_ifge, a_ifgt, a_ifle, a_iflt, a_ifne, a_ifnonnull, a_ifnull, a_goto];
         loadsymbol(0,_op1,0);
       end;
 
@@ -228,7 +228,7 @@ implementation
 
     function taicpu.spilling_get_operation_type(opnr: longint): topertype;
       begin
-        case opcode of
+        {case opcode of
           a_iinc:
             result:=operand_readwrite;
           a_aastore,
@@ -267,7 +267,8 @@ implementation
             result:=operand_write;
           else
             result:=operand_read;
-        end;
+        end;}
+        result:=operand_read;
       end;
 
 

+ 612 - 0
compiler/wasm/agbinaryen.pas

@@ -0,0 +1,612 @@
+{
+    Copyright (c) 2017 by Karoly Balogh
+
+    This unit implements the Binaryen assembler writer
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit agbinaryen;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      cclasses,systems,
+      globtype,globals,
+      symconst,symbase,symdef,symsym,
+      aasmbase,aasmtai,aasmdata,aasmcpu,
+      assemble;
+
+    type
+      TBinaryenAssemblerOutputFile=class(TExternalAssemblerOutputFile)
+        procedure RemoveAsm; override;
+      end;
+
+      TBinaryenInstrWriter = class;
+      {# This is a derived class which is used to write
+         Binaryen-styled assembler.
+      }
+
+      { TBinaryenAssembler }
+
+      TBinaryenAssembler=class(texternalassembler)
+       protected
+        jasminjar: tcmdstr;
+        asmfiles: TCmdStrList;
+
+        procedure WriteExtraHeader(obj: tabstractrecorddef);
+        procedure WriteInstruction(hp: tai);
+
+        function CreateNewAsmWriter: TExternalAssemblerOutputFile; override;
+       public
+        constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override;
+        function MakeCmdLine: TCmdStr;override;
+        procedure WriteTree(p:TAsmList);override;
+        procedure WriteAsmList;override;
+        destructor destroy; override;
+       protected
+        InstrWriter: TBinaryenInstrWriter;
+      end;
+
+
+      {# This is the base class for writing instructions.
+
+         The WriteInstruction() method must be overridden
+         to write a single instruction to the assembler
+         file.
+      }
+
+      { TBinaryenInstrWriter }
+
+      TBinaryenInstrWriter = class
+        constructor create(_owner: TBinaryenAssembler);
+        procedure WriteInstruction(hp : tai); virtual;
+       protected
+        owner: TBinaryenAssembler;
+      end;
+
+
+implementation
+
+    uses
+      SysUtils,
+      cutils,cfileutl,cscript,
+      fmodule,finput,verbose,
+      symtype,symcpu,symtable,
+      itcpuwasm,cpubase,cpuinfo,cgutils,
+      widestr
+      ;
+
+    const
+      line_length = 70;
+
+    type
+      t64bitarray = array[0..7] of byte;
+      t32bitarray = array[0..3] of byte;
+
+{****************************************************************************}
+{                          Support routines                                  }
+{****************************************************************************}
+
+   function fixline(s:string):string;
+   {
+     return s with all leading and ending spaces and tabs removed
+   }
+     var
+       i,j,k : integer;
+     begin
+       i:=length(s);
+       while (i>0) and (s[i] in [#9,' ']) do
+        dec(i);
+       j:=1;
+       while (j<i) and (s[j] in [#9,' ']) do
+        inc(j);
+       for k:=j to i do
+        if s[k] in [#0..#31,#127..#255] then
+         s[k]:='.';
+       fixline:=Copy(s,j,i-j+1);
+     end;
+
+
+   function constastr(p: pchar; len: longint): ansistring;
+     var
+       i,runstart,runlen: longint;
+
+       procedure flush;
+         begin
+           if runlen>0 then
+             begin
+               setlength(result,length(result)+runlen);
+               move(p[runstart],result[length(result)-runlen+1],runlen);
+               runlen:=0;
+             end;
+         end;
+
+     begin
+       result:='"';
+       runlen:=0;
+       runstart:=0;
+       for i:=0 to len-1 do
+         begin
+           { escape control codes }
+           case p[i] of
+             { LF and CR must be escaped specially, because \uXXXX parsing
+               happens in the pre-processor, so it's the same as actually
+               inserting a newline in the middle of a string constant }
+             #10:
+               begin
+                 flush;
+                 result:=result+'\n';
+               end;
+             #13:
+               begin
+                 flush;
+                 result:=result+'\r';
+               end;
+             '"','\':
+               begin
+                 flush;
+                 result:=result+'\'+p[i];
+               end
+             else if p[i]<#32 then
+               begin
+                 flush;
+                 result:=result+'\u'+hexstr(ord(p[i]),4);
+               end
+             else if p[i]<#127 then
+               begin
+                 if runlen=0 then
+                   runstart:=i;
+                 inc(runlen);
+               end
+             else
+               begin
+                 { see comments in njvmcon }
+                 flush;
+                 result:=result+'\u'+hexstr(ord(p[i]),4)
+               end;
+           end;
+         end;
+       flush;
+       result:=result+'"';
+     end;
+
+
+
+{****************************************************************************}
+{                       Binaryen Output File                                   }
+{****************************************************************************}
+
+    procedure TBinaryenAssemblerOutputFile.RemoveAsm;
+      var
+        g : file;
+      begin
+        inherited;
+        if cs_asm_leave in current_settings.globalswitches then
+         exit;
+        while not TBinaryenAssembler(owner).asmfiles.empty do
+          begin
+            if cs_asm_extern in current_settings.globalswitches then
+             AsmRes.AddDeleteCommand(TBinaryenAssembler(owner).asmfiles.GetFirst)
+            else
+             begin
+               assign(g,TBinaryenAssembler(owner).asmfiles.GetFirst);
+               {$I-}
+                erase(g);
+               {$I+}
+               if ioresult<>0 then;
+             end;
+          end;
+      end;
+
+
+{****************************************************************************}
+{                       Binaryen Assembler writer                              }
+{****************************************************************************}
+
+    destructor TBinaryenAssembler.Destroy;
+      begin
+        InstrWriter.free;
+        asmfiles.free;
+        inherited destroy;
+      end;
+
+
+    procedure TBinaryenAssembler.WriteTree(p:TAsmList);
+      var
+        ch       : char;
+        hp       : tai;
+        hp1      : tailineinfo;
+        s        : ansistring;
+        i,pos    : longint;
+        InlineLevel : longint;
+        do_line  : boolean;
+      begin
+        if not assigned(p) then
+         exit;
+
+        InlineLevel:=0;
+        { lineinfo is only needed for al_procedures (PFV) }
+        do_line:=(cs_asm_source in current_settings.globalswitches);
+        hp:=tai(p.first);
+        while assigned(hp) do
+         begin
+           prefetch(pointer(hp.next)^);
+           if not(hp.typ in SkipLineInfo) then
+            begin
+              hp1 := hp as tailineinfo;
+              current_filepos:=hp1.fileinfo;
+               { no line info for inlined code }
+               if do_line and (inlinelevel=0) then
+                begin
+                  { load infile }
+                  if lastfileinfo.fileindex<>hp1.fileinfo.fileindex then
+                   begin
+                     infile:=current_module.sourcefiles.get_file(hp1.fileinfo.fileindex);
+                     if assigned(infile) then
+                      begin
+                        { open only if needed !! }
+                        if (cs_asm_source in current_settings.globalswitches) then
+                         infile.open;
+                      end;
+                     { avoid unnecessary reopens of the same file !! }
+                     lastfileinfo.fileindex:=hp1.fileinfo.fileindex;
+                     { be sure to change line !! }
+                     lastfileinfo.line:=-1;
+                   end;
+
+                { write source }
+                  if (cs_asm_source in current_settings.globalswitches) and
+                     assigned(infile) then
+                   begin
+                     if (infile<>lastinfile) then
+                       begin
+                         writer.AsmWriteLn(asminfo^.comment+'['+infile.name+']');
+                         if assigned(lastinfile) then
+                           lastinfile.close;
+                       end;
+                     if (hp1.fileinfo.line<>lastfileinfo.line) and
+                        ((hp1.fileinfo.line<infile.maxlinebuf) or (InlineLevel>0)) then
+                       begin
+                         if (hp1.fileinfo.line<>0) and
+                            ((infile.linebuf^[hp1.fileinfo.line]>=0) or (InlineLevel>0)) then
+                           writer.AsmWriteLn(asminfo^.comment+'['+tostr(hp1.fileinfo.line)+'] '+
+                             fixline(infile.GetLineStr(hp1.fileinfo.line)));
+                         { set it to a negative value !
+                         to make that is has been read already !! PM }
+                         if (infile.linebuf^[hp1.fileinfo.line]>=0) then
+                           infile.linebuf^[hp1.fileinfo.line]:=-infile.linebuf^[hp1.fileinfo.line]-1;
+                       end;
+                   end;
+                  lastfileinfo:=hp1.fileinfo;
+                  lastinfile:=infile;
+                end;
+            end;
+
+           case hp.typ of
+
+             ait_comment :
+               Begin
+                 writer.AsmWrite(asminfo^.comment);
+                 writer.AsmWritePChar(tai_comment(hp).str);
+                 writer.AsmLn;
+               End;
+
+             ait_regalloc :
+               begin
+                 if (cs_asm_regalloc in current_settings.globalswitches) then
+                   begin
+                     writer.AsmWrite(#9+asminfo^.comment+'Register ');
+                     repeat
+                       writer.AsmWrite(std_regname(Tai_regalloc(hp).reg));
+                       if (hp.next=nil) or
+                          (tai(hp.next).typ<>ait_regalloc) or
+                          (tai_regalloc(hp.next).ratype<>tai_regalloc(hp).ratype) then
+                         break;
+                       hp:=tai(hp.next);
+                       writer.AsmWrite(',');
+                     until false;
+                     writer.AsmWrite(' ');
+                     writer.AsmWriteLn(regallocstr[tai_regalloc(hp).ratype]);
+                   end;
+               end;
+
+             ait_tempalloc :
+               begin
+                 if (cs_asm_tempalloc in current_settings.globalswitches) then
+                   begin
+  {$ifdef EXTDEBUG}
+                     if assigned(tai_tempalloc(hp).problem) then
+                       writer.AsmWriteLn(asminfo^.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
+                         tostr(tai_tempalloc(hp).tempsize)+' '+tai_tempalloc(hp).problem^)
+                     else
+  {$endif EXTDEBUG}
+                       writer.AsmWriteLn(asminfo^.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
+                         tostr(tai_tempalloc(hp).tempsize)+' '+tempallocstr[tai_tempalloc(hp).allocation]);
+                   end;
+               end;
+
+             ait_align :
+               begin
+
+               end;
+
+             ait_section :
+               begin
+
+               end;
+
+             ait_datablock :
+               begin
+//                 internalerror(2010122701);
+               end;
+
+             ait_const:
+               begin
+                 writer.AsmWriteln('constant');
+//                 internalerror(2010122702);
+               end;
+
+             ait_realconst :
+               begin
+                 internalerror(2010122703);
+               end;
+
+             ait_string :
+               begin
+                 pos:=0;
+                  for i:=1 to tai_string(hp).len do
+                   begin
+                     if pos=0 then
+                      begin
+                        writer.AsmWrite(#9'strconst: '#9'"');
+                        pos:=20;
+                      end;
+                     ch:=tai_string(hp).str[i-1];
+                     case ch of
+                        #0, {This can't be done by range, because a bug in FPC}
+                   #1..#31,
+                #128..#255 : s:='\'+tostr(ord(ch) shr 6)+tostr((ord(ch) and 63) shr 3)+tostr(ord(ch) and 7);
+                       '"' : s:='\"';
+                       '\' : s:='\\';
+                     else
+                      s:=ch;
+                     end;
+                     writer.AsmWrite(s);
+                     inc(pos,length(s));
+                     if (pos>line_length) or (i=tai_string(hp).len) then
+                      begin
+                        writer.AsmWriteLn('"');
+                        pos:=0;
+                      end;
+                   end;
+               end;
+
+             ait_label :
+               begin
+                 if (tai_label(hp).labsym.is_used) then
+                  begin
+                    writer.AsmWrite(tai_label(hp).labsym.name);
+                    writer.AsmWriteLn(':');
+                  end;
+               end;
+
+             ait_symbol :
+               begin
+                  if (tai_symbol(hp).sym.typ = AT_FUNCTION) then
+                    begin
+                    end
+                  else
+                   begin
+                     writer.AsmWrite('data symbol: ');
+                     writer.AsmWriteln(tai_symbol(hp).sym.name);
+//                     internalerror(2010122706);
+                   end;
+               end;
+             ait_symbol_end :
+               begin
+               end;
+
+             ait_instruction :
+               begin
+                 WriteInstruction(hp);
+               end;
+
+             ait_force_line,
+             ait_function_name : ;
+
+             ait_cutobject :
+               begin
+               end;
+
+             ait_marker :
+               if tai_marker(hp).kind=mark_NoLineInfoStart then
+                 inc(InlineLevel)
+               else if tai_marker(hp).kind=mark_NoLineInfoEnd then
+                 dec(InlineLevel);
+
+             ait_directive :
+               begin
+                 { the CPU directive is probably not supported by the JVM assembler,
+                   so it's commented out }
+                 if tai_directive(hp).directive=asd_cpu then
+                   writer.AsmWrite(asminfo^.comment);
+                 writer.AsmWrite('.'+directivestr[tai_directive(hp).directive]+' ');
+                 if tai_directive(hp).name<>'' then
+                   writer.AsmWrite(tai_directive(hp).name);
+                 writer.AsmLn;
+               end;
+
+             else
+               internalerror(2010122707);
+           end;
+           hp:=tai(hp.next);
+         end;
+      end;
+
+
+    procedure TBinaryenAssembler.WriteExtraHeader(obj: tabstractrecorddef);
+      begin
+      end;
+
+
+    procedure TBinaryenAssembler.WriteInstruction(hp: tai);
+      begin
+        InstrWriter.WriteInstruction(hp);
+      end;
+
+
+   function TBinaryenAssembler.MakeCmdLine: TCmdStr;
+     begin
+       Replace(result,'$EXTRAOPT',asmextraopt);
+     end;
+
+
+
+
+    function TBinaryenAssembler.CreateNewAsmWriter: TExternalAssemblerOutputFile;
+      begin
+        Result:=TBinaryenAssemblerOutputFile.Create(self);
+      end;
+
+
+    constructor TBinaryenAssembler.CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean);
+      begin
+        inherited;
+        InstrWriter:=TBinaryenInstrWriter.Create(self);
+        asmfiles:=TCmdStrList.Create;
+      end;
+
+
+    procedure TBinaryenAssembler.WriteAsmList;
+      var
+        hal : tasmlisttype;
+      begin
+        writer.MarkEmpty;
+        WriteExtraHeader(nil);
+
+      for hal:=low(TasmlistType) to high(TasmlistType) do
+        begin
+          if not (current_asmdata.asmlists[hal].empty) then
+            begin
+              writer.AsmWriteLn(asminfo^.comment+'Begin asmlist '+AsmlistTypeStr[hal]);
+              writetree(current_asmdata.asmlists[hal]);
+              writer.AsmWriteLn(asminfo^.comment+'End asmlist '+AsmlistTypeStr[hal]);
+            end;
+        end;
+
+        writer.AsmLn;
+      end;
+
+
+{****************************************************************************}
+{                         Binaryen Instruction Writer                          }
+{****************************************************************************}
+
+     constructor TBinaryenInstrWriter.create(_owner: TBinaryenAssembler);
+       begin
+         inherited create;
+         owner := _owner;
+       end;
+
+    function getreferencestring(var ref : treference) : ansistring;
+      begin
+{        if (ref.arrayreftype<>art_none) or
+           (ref.index<>NR_NO) then
+          internalerror(2010122809);}
+        if assigned(ref.symbol) then
+          begin
+            // global symbol or field -> full type and name
+            // ref.base can be <> NR_NO in case an instance field is loaded.
+            // This register is not part of this instruction, it will have
+            // been placed on the stack by the previous one.
+            if (ref.offset<>0) then
+              internalerror(2010122811);
+            result:=ref.symbol.name;
+          end
+        else
+          begin
+            // local symbol -> stack slot, stored in offset
+            if ref.base<>NR_STACK_POINTER_REG then
+              internalerror(2010122810);
+            result:=tostr(ref.offset);
+          end;
+      end;
+
+
+    function getopstr(const o:toper) : ansistring;
+      begin
+        case o.typ of
+          top_reg:
+            // should have been translated into a memory location by the
+            // register allocator)
+            if (cs_no_regalloc in current_settings.globalswitches) then
+              getopstr:=std_regname(o.reg)
+            else
+              internalerror(2010122803);
+          top_const:
+            str(o.val,result);
+          top_ref:
+            getopstr:=getreferencestring(o.ref^);
+          else
+            internalerror(2010122802);
+        end;
+      end;
+
+
+    procedure TBinaryenInstrWriter.WriteInstruction(hp: tai);
+      var
+        s: ansistring;
+        i: byte;
+        sep: ansistring;
+      begin
+        s:=#9+wasm_op2str[taicpu(hp).opcode];
+        if taicpu(hp).ops<>0 then
+          begin
+            sep:=#9;
+            for i:=0 to taicpu(hp).ops-1 do
+              begin
+                 s:=s+sep+getopstr(taicpu(hp).oper[i]^);
+                 sep:=' ';
+              end;
+          end;
+        owner.writer.AsmWriteLn(s);
+      end;
+
+{****************************************************************************}
+{                         Binaryen Instruction Writer                        }
+{****************************************************************************}
+
+  const
+    as_wasm_binaryen_info : tasminfo =
+       (
+         id     : as_wasm_binaryen;
+         idtxt  : 'Binaryen';
+         asmbin : 'wasm-as';
+         asmcmd : '$ASM $EXTRAOPT';
+         supported_targets : [system_wasm_wasm32];
+         flags : [];
+         labelprefix : 'L';
+         comment : ';; ';
+         dollarsign : '$';
+       );
+
+
+begin
+  RegisterAssembler(as_wasm_binaryen_info,TBinaryenAssembler);
+end.

+ 543 - 3
compiler/wasm/agwat.pas

@@ -1,7 +1,9 @@
 {
     Copyright (c) 1998-2010 by the Free Pascal team
 
-    This unit implements the WebAssembly text writer
+    This unit implements the WebAssembly text assembler
+    The text is in S-expression format and should be consumable
+    By either Binaryen or Wabt
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -19,12 +21,550 @@
 
  ****************************************************************************
 }
-{ Unit for writing WebAssembly text (S-Expression) output.
-}
 unit agwat;
 
 interface
 
+  uses
+    cclasses,systems, cgutils,
+    globtype,globals,
+    symconst,symbase,symdef,symsym, symtype,symcpu,
+    aasmbase,aasmtai,aasmdata,aasmcpu,
+    assemble
+    ,cutils
+    ,cpubase
+    ,fmodule
+    ,verbose, itcpuwasm;
+
+  type
+     TWatInstrWriter = class;
+
+     {# This is a derived class which is used to write
+        Binaryen-styled assembler.
+     }
+
+     { TWatAssembler }
+
+     { TWabtTextAssembler }
+
+     TWabtTextAssembler=class(texternalassembler)
+     protected
+       procedure WriteInstruction(hp: tai);
+       procedure WriteProcDef(pd: tprocdef);
+       procedure WriteSymtableProcdefs(st: TSymtable);
+     public
+       constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override;
+       procedure WriteTree(p:TAsmList);override;
+       procedure WriteAsmList;override;
+     end;
+
+
+     {# This is the base class for writing instructions.
+
+        The WriteInstruction() method must be overridden
+        to write a single instruction to the assembler
+        file.
+     }
+
+     { TBinaryenInstrWriter }
+
+     { TWatInstrWriter }
+
+     TWatInstrWriter = class
+       constructor create(_owner: TWabtTextAssembler);
+       procedure WriteInstruction(hp : tai); virtual;
+      protected
+       owner: TWabtTextAssembler;
+     end;
+
 implementation
 
+    type
+      t64bitarray = array[0..7] of byte;
+      t32bitarray = array[0..3] of byte;
+
+
+    const
+      line_length = 70;
+
+  {****************************************************************************}
+  {                          Support routines                                  }
+  {****************************************************************************}
+
+     function fixline(s:string):string;
+     {
+       return s with all leading and ending spaces and tabs removed
+     }
+       var
+         i,j,k : integer;
+       begin
+         i:=length(s);
+         while (i>0) and (s[i] in [#9,' ']) do
+          dec(i);
+         j:=1;
+         while (j<i) and (s[j] in [#9,' ']) do
+          inc(j);
+         for k:=j to i do
+          if s[k] in [#0..#31,#127..#255] then
+           s[k]:='.';
+         fixline:=Copy(s,j,i-j+1);
+       end;
+
+     function getreferencestring(var ref : treference) : ansistring;
+       begin
+         if (ref.arrayreftype<>art_none) or
+            (ref.index<>NR_NO) then
+           internalerror(2010122809);
+         if assigned(ref.symbol) then
+           begin
+             // global symbol or field -> full type and name
+             // ref.base can be <> NR_NO in case an instance field is loaded.
+             // This register is not part of this instruction, it will have
+             // been placed on the stack by the previous one.
+             if (ref.offset<>0) then
+               internalerror(2010122811);
+             result:=ref.symbol.name;
+           end
+         else
+           begin
+             // local symbol -> stack slot, stored in offset
+             if ref.base<>NR_STACK_POINTER_REG then
+               internalerror(2010122810);
+             result:=tostr(ref.offset);
+           end;
+       end;
+
+     function constsingle(s: single): ansistring;
+       begin
+         result:='0fx'+hexstr(longint(t32bitarray(s)),8);
+       end;
+
+     function constdouble(d: double): ansistring;
+        begin
+          // force interpretation as double (since we write it out as an
+          // integer, we never have to swap the endianess). We have to
+          // include the sign separately because of the way Java parses
+          // hex numbers (0x8000000000000000 is not a valid long)
+         result:=hexstr(abs(int64(t64bitarray(d))),16);
+         if int64(t64bitarray(d))<0 then
+           result:='-'+result;
+         result:='0dx'+result;
+        end;
+
+    function getopstr(const o:toper) : ansistring;
+      var
+        d: double;
+        s: single;
+      begin
+        case o.typ of
+          top_reg:
+            // should have been translated into a memory location by the
+            // register allocator)
+            if (cs_no_regalloc in current_settings.globalswitches) then
+              getopstr:=std_regname(o.reg)
+            else
+              internalerror(2010122803);
+          top_const:
+            str(o.val,result);
+          top_ref:
+            getopstr:=getreferencestring(o.ref^);
+          top_single:
+            begin
+              result:=constsingle(o.sval);
+            end;
+          top_double:
+            begin
+              result:=constdouble(o.dval);
+            end;
+          {top_string:
+            begin
+              result:=constastr(o.pcval,o.pcvallen);
+            end;
+          top_wstring:
+            begin
+              result:=constwstr(o.pwstrval^.data,getlengthwidestring(o.pwstrval));
+            end}
+          else
+            internalerror(2010122802);
+        end;
+      end;
+
+  { TWabtTextAssembler }
+
+    procedure TWabtTextAssembler.WriteInstruction(hp: tai);
+    var
+      cpu : taicpu;
+      i   : integer;
+    begin
+      //writer.AsmWriteLn('instr');
+      //writeln('>',taicpu(hp).opcode);
+      writer.AsmWrite(#9);
+      writer.AsmWrite(wasm_op2str[taicpu(hp).opcode] );
+      cpu := taicpu(hp);
+      if cpu.ops<>0 then
+        begin
+          for i:=0 to taicpu(hp).ops-1 do
+            begin
+              writer.AsmWrite(#9);
+              writer.AsmWrite(getopstr(taicpu(hp).oper[i]^));
+            end;
+        end;
+
+      writer.AsmLn;
+    end;
+
+    procedure TWabtTextAssembler.WriteProcDef(pd: tprocdef);
+    begin
+      if not assigned(tcpuprocdef(pd).exprasmlist) and
+         not(po_abstractmethod in pd.procoptions) and
+         (not is_javainterface(pd.struct) or
+          (pd.proctypeoption in [potype_unitinit,potype_unitfinalize])) then
+      begin
+        //writeln('mordoy ne vyshel! ',pd.procsym.RealName );
+        exit;
+      end;
+      writer.AsmWrite('(func ');
+
+      writer.AsmWrite('$');
+      writer.AsmWrite(pd.procsym.RealName);
+      //writer.AsmWriteln(MethodDefinition(pd));
+      {if jvmtypeneedssignature(pd) then
+        begin
+          writer.AsmWrite('.signature "');
+          writer.AsmWrite(tcpuprocdef(pd).jvmmangledbasename(true));
+          writer.AsmWriteln('"');
+        end;}
+      WriteTree(tcpuprocdef(pd).exprasmlist);
+      writer.AsmWriteln(')');
+      writer.AsmLn;
+    end;
+
+    procedure TWabtTextAssembler.WriteTree(p: TAsmList);
+      var
+        ch       : char;
+        hp       : tai;
+        hp1      : tailineinfo;
+        s        : ansistring;
+        i,pos    : longint;
+        InlineLevel : longint;
+        do_line  : boolean;
+      begin
+        if not assigned(p) then
+         exit;
+
+        InlineLevel:=0;
+        { lineinfo is only needed for al_procedures (PFV) }
+        do_line:=(cs_asm_source in current_settings.globalswitches);
+        hp:=tai(p.first);
+        while assigned(hp) do
+         begin
+           prefetch(pointer(hp.next)^);
+           if not(hp.typ in SkipLineInfo) then
+            begin
+              hp1 := hp as tailineinfo;
+              current_filepos:=hp1.fileinfo;
+               { no line info for inlined code }
+               if do_line and (inlinelevel=0) then
+                begin
+                  { load infile }
+                  if lastfileinfo.fileindex<>hp1.fileinfo.fileindex then
+                   begin
+                     infile:=current_module.sourcefiles.get_file(hp1.fileinfo.fileindex);
+                     if assigned(infile) then
+                      begin
+                        { open only if needed !! }
+                        if (cs_asm_source in current_settings.globalswitches) then
+                         infile.open;
+                      end;
+                     { avoid unnecessary reopens of the same file !! }
+                     lastfileinfo.fileindex:=hp1.fileinfo.fileindex;
+                     { be sure to change line !! }
+                     lastfileinfo.line:=-1;
+                   end;
+
+                { write source }
+                  if (cs_asm_source in current_settings.globalswitches) and
+                     assigned(infile) then
+                   begin
+                     if (infile<>lastinfile) then
+                       begin
+                         writer.AsmWriteLn(asminfo^.comment+'['+infile.name+']');
+                         if assigned(lastinfile) then
+                           lastinfile.close;
+                       end;
+                     if (hp1.fileinfo.line<>lastfileinfo.line) and
+                        ((hp1.fileinfo.line<infile.maxlinebuf) or (InlineLevel>0)) then
+                       begin
+                         if (hp1.fileinfo.line<>0) and
+                            ((infile.linebuf^[hp1.fileinfo.line]>=0) or (InlineLevel>0)) then
+                           writer.AsmWriteLn(asminfo^.comment+'['+tostr(hp1.fileinfo.line)+'] '+
+                             fixline(infile.GetLineStr(hp1.fileinfo.line)));
+                         { set it to a negative value !
+                         to make that is has been read already !! PM }
+                         if (infile.linebuf^[hp1.fileinfo.line]>=0) then
+                           infile.linebuf^[hp1.fileinfo.line]:=-infile.linebuf^[hp1.fileinfo.line]-1;
+                       end;
+                   end;
+                  lastfileinfo:=hp1.fileinfo;
+                  lastinfile:=infile;
+                end;
+            end;
+
+           case hp.typ of
+
+             ait_comment :
+               Begin
+                 writer.AsmWrite(asminfo^.comment);
+                 writer.AsmWritePChar(tai_comment(hp).str);
+                 writer.AsmLn;
+               End;
+
+             ait_regalloc :
+               begin
+                 if (cs_asm_regalloc in current_settings.globalswitches) then
+                   begin
+                     writer.AsmWrite(#9+asminfo^.comment+'Register ');
+                     repeat
+                       writer.AsmWrite(std_regname(Tai_regalloc(hp).reg));
+                       if (hp.next=nil) or
+                          (tai(hp.next).typ<>ait_regalloc) or
+                          (tai_regalloc(hp.next).ratype<>tai_regalloc(hp).ratype) then
+                         break;
+                       hp:=tai(hp.next);
+                       writer.AsmWrite(',');
+                     until false;
+                     writer.AsmWrite(' ');
+                     writer.AsmWriteLn(regallocstr[tai_regalloc(hp).ratype]);
+                   end;
+               end;
+
+             ait_tempalloc :
+               begin
+                 if (cs_asm_tempalloc in current_settings.globalswitches) then
+                   begin
+  {$ifdef EXTDEBUG}
+                     if assigned(tai_tempalloc(hp).problem) then
+                       writer.AsmWriteLn(asminfo^.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
+                         tostr(tai_tempalloc(hp).tempsize)+' '+tai_tempalloc(hp).problem^)
+                     else
+  {$endif EXTDEBUG}
+                       writer.AsmWriteLn(asminfo^.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
+                         tostr(tai_tempalloc(hp).tempsize)+' '+tempallocstr[tai_tempalloc(hp).allocation]);
+                   end;
+               end;
+
+             ait_align :
+               begin
+
+               end;
+
+             ait_section :
+               begin
+
+               end;
+
+             ait_datablock :
+               begin
+//                 internalerror(2010122701);
+               end;
+
+             ait_const:
+               begin
+                 writer.AsmWriteln('constant');
+//                 internalerror(2010122702);
+               end;
+
+             ait_realconst :
+               begin
+                 internalerror(2010122703);
+               end;
+
+             ait_string :
+               begin
+                 pos:=0;
+                  for i:=1 to tai_string(hp).len do
+                   begin
+                     if pos=0 then
+                      begin
+                        writer.AsmWrite(#9'strconst: '#9'"');
+                        pos:=20;
+                      end;
+                     ch:=tai_string(hp).str[i-1];
+                     case ch of
+                        #0, {This can't be done by range, because a bug in FPC}
+                   #1..#31,
+                #128..#255 : s:='\'+tostr(ord(ch) shr 6)+tostr((ord(ch) and 63) shr 3)+tostr(ord(ch) and 7);
+                       '"' : s:='\"';
+                       '\' : s:='\\';
+                     else
+                      s:=ch;
+                     end;
+                     writer.AsmWrite(s);
+                     inc(pos,length(s));
+                     if (pos>line_length) or (i=tai_string(hp).len) then
+                      begin
+                        writer.AsmWriteLn('"');
+                        pos:=0;
+                      end;
+                   end;
+               end;
+
+             ait_label :
+               begin
+                 if (tai_label(hp).labsym.is_used) then
+                  begin
+                    writer.AsmWrite(tai_label(hp).labsym.name);
+                    writer.AsmWriteLn(':');
+                  end;
+               end;
+
+             ait_symbol :
+               begin
+                  if (tai_symbol(hp).sym.typ = AT_FUNCTION) then
+                    begin
+                    end
+                  else
+                   begin
+                     writer.AsmWrite('data symbol: ');
+                     writer.AsmWriteln(tai_symbol(hp).sym.name);
+//                     internalerror(2010122706);
+                   end;
+               end;
+             ait_symbol_end :
+               begin
+               end;
+
+             ait_instruction :
+               begin
+                 WriteInstruction(hp);
+               end;
+
+             ait_force_line,
+             ait_function_name : ;
+
+             ait_cutobject :
+               begin
+               end;
+
+             ait_marker :
+               if tai_marker(hp).kind=mark_NoLineInfoStart then
+                 inc(InlineLevel)
+               else if tai_marker(hp).kind=mark_NoLineInfoEnd then
+                 dec(InlineLevel);
+
+             ait_directive :
+               begin
+                 { the CPU directive is probably not supported by the JVM assembler,
+                   so it's commented out }
+                 //if tai_directive(hp).directive=asd_cpu then
+                 //  writer.AsmWrite(asminfo^.comment);
+                 //writer.AsmWrite('.'+directivestr[tai_directive(hp).directive]+' ');
+                 //if tai_directive(hp).name<>'' then
+                 //  writer.AsmWrite(tai_directive(hp).name);
+                 //writer.AsmLn;
+               end;
+
+             else
+               internalerror(2010122707);
+           end;
+           hp:=tai(hp.next);
+         end;
+    end;
+
+    procedure TWabtTextAssembler.WriteAsmList;
+      var
+        hal : tasmlisttype;
+      begin
+        if current_module.is_unit then begin
+          writer.AsmWriteLn('(module)');
+          exit;
+        end;
+        writer.MarkEmpty;
+        writer.AsmWriteLn('(module ');
+
+        { print all global variables }
+        //WriteSymtableVarSyms(current_module.globalsymtable);
+        //WriteSymtableVarSyms(current_module.localsymtable);
+        //writer.AsmLn;
+        { print all global procedures/functions }
+        WriteSymtableProcdefs(current_module.globalsymtable);
+        WriteSymtableProcdefs(current_module.localsymtable);
+
+        //WriteSymtableStructDefs(current_module.globalsymtable);
+        //WriteSymtableStructDefs(current_module.localsymtable);
+        //writer.decorator.LinePrefix := '';
+        writer.AsmWriteLn(')');
+
+        writer.AsmLn;
+      end;
+
+    constructor TWabtTextAssembler.CreateWithWriter(info: pasminfo;
+      wr: TExternalAssemblerOutputFile; freewriter, smart: boolean);
+      begin
+        inherited CreateWithWriter(info, wr, freewriter, smart);
+      end;
+
+    procedure TWabtTextAssembler.WriteSymtableProcdefs(st: TSymtable);
+      var
+        i   : longint;
+        def : tdef;
+      begin
+        if not assigned(st) then
+          exit;
+        for i:=0 to st.DefList.Count-1 do
+          begin
+            def:=tdef(st.DefList[i]);
+            case def.typ of
+              procdef :
+                begin
+                  { methods are also in the static/globalsymtable of the unit
+                    -> make sure they are only written for the objectdefs that
+                    own them }
+                  if (not(st.symtabletype in [staticsymtable,globalsymtable]) or
+                      (def.owner=st)) and
+                     not(df_generic in def.defoptions) then
+                    begin
+                      WriteProcDef(tprocdef(def));
+                      if assigned(tprocdef(def).localst) then
+                        WriteSymtableProcdefs(tprocdef(def).localst);
+                    end;
+                end;
+              else
+                ;
+            end;
+          end;
+      end;
+
+
+{ TWatInstrWriter }
+
+  constructor TWatInstrWriter.create(_owner: TWabtTextAssembler);
+    begin
+      inherited create;
+      owner := _owner;
+    end;
+
+  procedure TWatInstrWriter.WriteInstruction(hp: tai);
+    begin
+
+    end;
+
+
+  const
+    as_wasm_wabt_info : tasminfo =
+       (
+         id     : as_wasm_wabt;
+         idtxt  : 'Wabt';
+         asmbin : 'wat2wasm';
+         asmcmd : '$ASM $EXTRAOPT';
+         supported_targets : [system_wasm_wasm32];
+         flags : [];
+         labelprefix : 'L';
+         comment : ';; ';
+         dollarsign : '$';
+       );
+
+initialization
+  RegisterAssembler(as_wasm_wabt_info, TWabtTextAssembler);
+
 end.

+ 46 - 63
compiler/wasm/cpubase.pas

@@ -1,5 +1,5 @@
 {
-    Copyright (c) 2019 by Free Pascal and Lazarus foundation
+    Copyright (c) 2016-2017 by Karoly Balogh
 
     Contains the base types for the WebAssembly
 
@@ -38,68 +38,51 @@ uses
 
     type
       TAsmOp=(A_None,
-        a_aaload, a_aastore, a_aconst_null,
-        a_aload, a_aload_0, a_aload_1, a_aload_2, a_aload_3,
-        a_anewarray, a_areturn, a_arraylength,
-        a_astore, a_astore_0, a_astore_1, a_astore_2, a_astore_3,
-        a_athrow, a_baload, a_bastore, a_bipush, a_breakpoint,
-        a_caload, a_castore, a_checkcast,
-        a_d2f, a_d2i, a_d2l, a_dadd, a_daload, a_dastore, a_dcmpg, a_dcmpl,
-        a_dconst_0, a_dconst_1, a_ddiv,
-        a_dload, a_dload_0, a_dload_1, a_dload_2, a_dload_3,
-        a_dmul, a_dneg, a_drem, a_dreturn,
-        a_dstore, a_dstore_0, a_dstore_1, a_dstore_2, a_dstore_3,
-        a_dsub,
-        a_dup, a_dup2, a_dup2_x1, a_dup2_x2, a_dup_x1, a_dup_x2,
-        a_f2d, a_f2i, a_f2l, a_fadd, a_faload, a_fastore, a_fcmpg, a_fcmpl,
-        a_fconst_0, a_fconst_1, a_fconst_2, a_fdiv,
-        a_fload, a_fload_0, a_fload_1, a_fload_2, a_fload_3,
-        a_fmul, a_fneg, a_frem, a_freturn,
-        a_fstore, a_fstore_0, a_fstore_1, a_fstore_2, a_fstore_3,
-        a_fsub,
-        a_getfield, a_getstatic,
-        a_goto, a_goto_w,
-        a_i2b, a_i2c, a_i2d, a_i2f, a_i2l, a_i2s,
-        a_iadd, a_iaload, a_iand, a_iastore,
-        a_iconst_m1, a_iconst_0, a_iconst_1, a_iconst_2, a_iconst_3,
-        a_iconst_4, a_iconst_5,
-        a_idiv,
-        a_if_acmpeq, a_if_acmpne, a_if_icmpeq, a_if_icmpge, a_if_icmpgt,
-        a_if_icmple, a_if_icmplt, a_if_icmpne,
-        a_ifeq, a_ifge, a_ifgt, a_ifle, a_iflt, a_ifne, a_ifnonnull, a_ifnull,
-        a_iinc,
-        a_iload, a_iload_0, a_iload_1, a_iload_2, a_iload_3,
-        a_imul, a_ineg,
-        a_instanceof,
-        a_invokeinterface, a_invokespecial, a_invokestatic, a_invokevirtual,
-        a_ior, a_irem, a_ireturn, a_ishl, a_ishr,
-        a_istore, a_istore_0, a_istore_1, a_istore_2, a_istore_3,
-        a_isub, a_iushr, a_ixor,
-        a_jsr, a_jsr_w,
-        a_l2d, a_l2f, a_l2i, a_ladd, a_laload, a_land, a_lastore, a_lcmp,
-        a_lconst_0, a_lconst_1,
-        a_ldc, a_ldc2_w, a_ldc_w, a_ldiv,
-        a_lload, a_lload_0, a_lload_1, a_lload_2, a_lload_3,
-        a_lmul, a_lneg,
-        a_lookupswitch,
-        a_lor, a_lrem,
-        a_lreturn,
-        a_lshl, a_lshr,
-        a_lstore, a_lstore_0, a_lstore_1, a_lstore_2, a_lstore_3,
-        a_lsub, a_lushr, a_lxor,
-        a_monitorenter,
-        a_monitorexit,
-        a_multianewarray,
-        a_new,
-        a_newarray,
-        a_nop,
-        a_pop, a_pop2,
-        a_putfield, a_putstatic,
-        a_ret, a_return,
-        a_saload, a_sastore, a_sipush,
-        a_swap,
-        a_tableswitch,
-        a_wide
+      // control flow
+      a_block, a_loop, a_br, a_br_if, a_br_table, a_if, a_else, a_end,
+      a_return, a_unreachable,
+      // basic
+      a_nop, a_drop, a_i32_const, a_i64_const, a_f32_const, a_f64_const,
+      a_get_local, a_set_local, a_tee_local, a_get_global, a_set_global,
+      a_select, a_call, a_call_indirect,
+      // integer
+      a_i32_add, a_i64_add, a_i32_sub, a_i64_sub, a_i32_mul, a_i64_mul,
+      a_i32_div_s, a_i64_div_s, a_i32_div_u, a_i64_div_u, a_i32_rem_s, a_i64_rem_s,
+      a_i32_rem_u, a_i64_rem_u, a_i32_and, a_i64_and, a_i32_or, a_i64_or,
+      a_i32_xor, a_i64_xor, a_i32_shl, a_i64_shl, a_i32_shr_s, a_i64_shr_s,
+      a_i32_shr_u, a_i64_shr_u, a_i32_rotl, a_i64_rotl, a_i32_rotr, a_i64_rotr,
+      a_i32_clz, a_i64_clz, a_i32_ctz, a_i64_ctz, a_i32_popcnt, a_i64_popcnt,
+      a_i32_eqz, a_i64_eqz,
+      // floating point
+      a_f32_add, a_f64_add, a_f32_sub, a_f64_sub, a_f32_mul, a_f64_mul,
+      a_f32_div, a_f64_div, a_f32_sqrt, a_f64_sqrt, a_f32_min, a_f64_min,
+      a_f32_max, a_f64_max, a_f32_ceil, a_f64_ceil, a_f32_floor, a_f64_floor,
+      a_f32_trunc, a_f64_trunc, a_f32_nearest, a_f64_nearest, a_f32_abs, a_f64_abs,
+      a_f32_neg, a_f64_neg, a_f32_copysign, a_f64_copysign,
+      // integer compare
+      a_i32_eq, a_i64_eq, a_i32_ne, a_i64_ne, a_i32_lt_s, a_i64_lt_s,
+      a_i32_lt_u, a_i64_lt_u, a_i32_le_s, a_i64_le_s, a_i32_le_u, a_i64_le_u,
+      a_i32_gt_s, a_i64_gt_s, a_i32_gt_u, a_i64_gt_u, a_i32_ge_s, a_i64_ge_s,
+      a_i32_ge_u, a_i64_ge_u,
+      // floating point compare
+      a_f32_eq, a_f64_eq, a_f32_ne, a_f64_ne, a_f32_lt, a_f64_lt,
+      a_f32_le, a_f64_le, a_f32_gt, a_f64_gt, a_f32_ge, a_f64_ge,
+      // conversion
+      a_i32_wrap_i64, a_i64_extend_s_i32, a_i64_extend_u_i32,
+      a_i32_trunc_s_f32, a_i32_trunc_s_f64, a_i64_trunc_s_f32, a_i64_trunc_s_f64,
+      a_i32_trunc_u_f32, a_i32_trunc_u_f64, a_i64_trunc_u_f32, a_i64_trunc_u_f64,
+      a_f32_demote_f64, a_f64_promote_f32,
+      a_f32_convert_s_i32, a_f32_convert_s_i64,a_f64_convert_s_i32,a_f64_convert_s_i64,
+      a_f32_convert_u_i32, a_f32_convert_u_i64,a_f64_convert_u_i32,a_f64_convert_u_i64,
+      a_i32_reinterpret_f32, a_i64_reinterpret_f64, a_f32_reinterpret_i32, a_f64_reinterpret_f64,
+      // load/store
+      a_i32_load, a_i64_load, a_f32_load, a_f64_load,
+      a_i32_store, a_i64_store, a_f32_store, a_f64_store,
+      a_i32_load8_s, a_i32_load16_s, a_i64_load8_s, a_i64_load16_s, a_i64_load32_s,
+      a_i32_load8_u, a_i32_load16_u, a_i64_load8_u, a_i64_load16_u, a_i64_load32_u,
+      a_i32_store8, a_i32_store16, a_i64_store8, a_i64_store16, a_i64_store32,
+      // additional memory
+      a_grow_memory, a_current_memory
       );
 
       {# This should define the array of instructions as string }

+ 1 - 3
compiler/wasm/cputarg.pas

@@ -38,16 +38,14 @@ implementation
 {**************************************
              Targets
 **************************************}
-
-    {$ifndef NOTARGETSUNOS}
       ,t_wasm
-    {$endif}
 
 {**************************************
              Assemblers
 **************************************}
 
       ,agwat
+      ,agbinaryen
 
 {**************************************
         Assembler Readers

+ 120 - 115
compiler/wasm/hlcgcpu.pas

@@ -35,9 +35,9 @@ uses
 
   type
 
-    { thlcgjvm }
+    { thlcgwasm }
 
-    thlcgjvm = class(thlcgobj)
+    thlcgwasm = class(thlcgobj)
      private
       fevalstackheight,
       fmaxevalstackheight: longint;
@@ -236,9 +236,14 @@ uses
 
 
   const
-    opcmp2if: array[topcmp] of tasmop = (A_None,
-      a_ifeq,a_ifgt,a_iflt,a_ifge,a_ifle,
-      a_ifne,a_ifle,a_iflt,a_ifge,a_ifgt);
+    opcmp2if: array[TOpCmp] of TAsmOp = (A_None,
+       a_i64_eq,               // OC_EQ
+       a_i64_gt_s, a_i64_lt_s, // OC_GT, OC_LT
+       a_i64_ge_s, a_i64_le_s, // OC_GTE, OC_LTE
+       a_i64_ne,               // OC_NE
+       a_i64_le_u, a_i64_lt_u, // OC_BE, OC_B
+       a_i64_ge_u, a_i64_gt_u  // OC_AE, OC_A
+    );
 
 implementation
 
@@ -257,13 +262,13 @@ implementation
       A_None,A_None,a_ladd,a_land,A_none,a_ldiv,a_lmul,a_lmul,a_lneg,A_None,a_lor,a_lshr,a_lshl,a_lushr,a_lsub,a_lxor,A_None,A_None
     );
 
-  constructor thlcgjvm.create;
+  constructor thlcgwasm.create;
     begin
       fevalstackheight:=0;
       fmaxevalstackheight:=0;
     end;
 
-  procedure thlcgjvm.incstack(list: TasmList;slots: longint);
+  procedure thlcgwasm.incstack(list: TasmList;slots: longint);
     begin
       if slots=0 then
         exit;
@@ -274,7 +279,7 @@ implementation
         list.concat(tai_comment.Create(strpnew('    allocated '+tostr(slots)+', stack height = '+tostr(fevalstackheight))));
     end;
 
-  procedure thlcgjvm.decstack(list: TAsmList;slots: longint);
+  procedure thlcgwasm.decstack(list: TAsmList;slots: longint);
     begin
       if slots=0 then
         exit;
@@ -286,7 +291,7 @@ implementation
         list.concat(tai_comment.Create(strpnew('    freed '+tostr(slots)+', stack height = '+tostr(fevalstackheight))));
     end;
 
-  class function thlcgjvm.def2regtyp(def: tdef): tregistertype;
+  class function thlcgwasm.def2regtyp(def: tdef): tregistertype;
     begin
       case def.typ of
         { records (including files) and enums are implemented via classes }
@@ -305,7 +310,7 @@ implementation
       end;
     end;
 
-  procedure thlcgjvm.a_load_const_cgpara(list: TAsmList; tosize: tdef; a: tcgint; const cgpara: TCGPara);
+  procedure thlcgwasm.a_load_const_cgpara(list: TAsmList; tosize: tdef; a: tcgint; const cgpara: TCGPara);
     begin
       tosize:=get_para_push_size(tosize);
       if tosize=s8inttype then
@@ -315,25 +320,25 @@ implementation
       inherited a_load_const_cgpara(list, tosize, a, cgpara);
     end;
 
-  function thlcgjvm.a_call_name(list: TAsmList; pd: tprocdef; const s: TSymStr; const paras: array of pcgpara; forceresdef: tdef; weak: boolean): tcgpara;
+  function thlcgwasm.a_call_name(list: TAsmList; pd: tprocdef; const s: TSymStr; const paras: array of pcgpara; forceresdef: tdef; weak: boolean): tcgpara;
     begin
       result:=a_call_name_intern(list,pd,s,forceresdef,false);
     end;
 
-  function thlcgjvm.a_call_name_inherited(list: TAsmList; pd: tprocdef; const s: TSymStr; const paras: array of pcgpara): tcgpara;
+  function thlcgwasm.a_call_name_inherited(list: TAsmList; pd: tprocdef; const s: TSymStr; const paras: array of pcgpara): tcgpara;
     begin
       result:=a_call_name_intern(list,pd,s,nil,true);
     end;
 
 
-  function thlcgjvm.a_call_reg(list: TAsmList; pd: tabstractprocdef; reg: tregister; const paras: array of pcgpara): tcgpara;
+  function thlcgwasm.a_call_reg(list: TAsmList; pd: tabstractprocdef; reg: tregister; const paras: array of pcgpara): tcgpara;
     begin
       internalerror(2012042824);
       result.init;
     end;
 
 
-  procedure thlcgjvm.a_load_const_stack_intern(list : TAsmList;size : tdef;a : tcgint; typ: TRegisterType; legalize_const: boolean);
+  procedure thlcgwasm.a_load_const_stack_intern(list : TAsmList;size : tdef;a : tcgint; typ: TRegisterType; legalize_const: boolean);
     begin
       if legalize_const and
          (typ=R_INTREGISTER) and
@@ -354,7 +359,7 @@ implementation
     end;
 
 
-  procedure thlcgjvm.a_load_const_stack(list : TAsmList;size : tdef;a : tcgint; typ: TRegisterType);
+  procedure thlcgwasm.a_load_const_stack(list : TAsmList;size : tdef;a : tcgint; typ: TRegisterType);
     const
       int2opc: array[-1..5] of tasmop = (a_iconst_m1,a_iconst_0,a_iconst_1,
         a_iconst_2,a_iconst_3,a_iconst_4,a_iconst_5);
@@ -412,7 +417,7 @@ implementation
       incstack(list,1);
     end;
 
-  procedure thlcgjvm.a_load_stack_loc(list: TAsmList; size: tdef; const loc: tlocation);
+  procedure thlcgwasm.a_load_stack_loc(list: TAsmList; size: tdef; const loc: tlocation);
     begin
       case loc.loc of
         LOC_REGISTER,LOC_CREGISTER,
@@ -425,7 +430,7 @@ implementation
       end;
     end;
 
-  procedure thlcgjvm.a_load_loc_stack(list: TAsmList;size: tdef;const loc: tlocation);
+  procedure thlcgwasm.a_load_loc_stack(list: TAsmList;size: tdef;const loc: tlocation);
     begin
       case loc.loc of
         LOC_REGISTER,LOC_CREGISTER,
@@ -440,7 +445,7 @@ implementation
       end;
     end;
 
-  procedure thlcgjvm.a_loadfpu_const_stack(list: TAsmList; size: tdef; a: double);
+  procedure thlcgwasm.a_loadfpu_const_stack(list: TAsmList; size: tdef; a: double);
     begin
       case tfloatdef(size).floattype of
         s32real:
@@ -470,7 +475,7 @@ implementation
       end;
     end;
 
-  procedure thlcgjvm.a_op_stack(list: TAsmList; op: topcg; size: tdef; trunc32: boolean);
+  procedure thlcgwasm.a_op_stack(list: TAsmList; op: topcg; size: tdef; trunc32: boolean);
     var
       cgsize: tcgsize;
     begin
@@ -540,7 +545,7 @@ implementation
         end;
     end;
 
-  procedure thlcgjvm.a_op_const_stack(list: TAsmList;op: topcg;size: tdef;a: tcgint);
+  procedure thlcgwasm.a_op_const_stack(list: TAsmList;op: topcg;size: tdef;a: tcgint);
     var
       trunc32: boolean;
     begin
@@ -557,7 +562,7 @@ implementation
       a_op_stack(list,op,size,trunc32);
     end;
 
-  procedure thlcgjvm.a_op_reg_stack(list: TAsmList; op: topcg; size: tdef; reg: tregister);
+  procedure thlcgwasm.a_op_reg_stack(list: TAsmList; op: topcg; size: tdef; reg: tregister);
     var
       trunc32: boolean;
     begin
@@ -579,7 +584,7 @@ implementation
       a_op_stack(list,op,size,trunc32);
     end;
 
-  procedure thlcgjvm.a_op_ref_stack(list: TAsmList; op: topcg; size: tdef; const ref: treference);
+  procedure thlcgwasm.a_op_ref_stack(list: TAsmList; op: topcg; size: tdef; const ref: treference);
     var
       trunc32: boolean;
     begin
@@ -605,7 +610,7 @@ implementation
       a_op_stack(list,op,size,trunc32);
     end;
 
-  procedure thlcgjvm.a_op_loc_stack(list: TAsmList; op: topcg; size: tdef; const loc: tlocation);
+  procedure thlcgwasm.a_op_loc_stack(list: TAsmList; op: topcg; size: tdef; const loc: tlocation);
     begin
       case loc.loc of
         LOC_REGISTER,LOC_CREGISTER:
@@ -619,7 +624,7 @@ implementation
       end;
     end;
 
-  procedure thlcgjvm.g_reference_loc(list: TAsmList; def: tdef; const fromloc: tlocation; out toloc: tlocation);
+  procedure thlcgwasm.g_reference_loc(list: TAsmList; def: tdef; const fromloc: tlocation; out toloc: tlocation);
     begin
       case fromloc.loc of
         LOC_CREFERENCE,
@@ -652,7 +657,7 @@ implementation
       end;
     end;
 
-  procedure thlcgjvm.g_newarray(list: TAsmList; arrdef: tdef; initdim: longint);
+  procedure thlcgwasm.g_newarray(list: TAsmList; arrdef: tdef; initdim: longint);
     var
       recref,
       enuminitref: treference;
@@ -765,7 +770,7 @@ implementation
         end;
     end;
 
-  procedure thlcgjvm.g_getarraylen(list: TAsmList; const arrloc: tlocation);
+  procedure thlcgwasm.g_getarraylen(list: TAsmList; const arrloc: tlocation);
     var
       nillab,endlab: tasmlabel;
     begin
@@ -803,7 +808,7 @@ implementation
       a_label(list,endlab);
     end;
 
-    procedure thlcgjvm.a_cmp_stack_label(list: TAsmlist; size: tdef; cmp_op: topcmp; lab: tasmlabel);
+    procedure thlcgwasm.a_cmp_stack_label(list: TAsmlist; size: tdef; cmp_op: topcmp; lab: tasmlabel);
       const
         opcmp2icmp: array[topcmp] of tasmop = (A_None,
           a_if_icmpeq,a_if_icmpgt,a_if_icmplt,a_if_icmpge,a_if_icmple,
@@ -851,7 +856,7 @@ implementation
         end;
       end;
 
-    procedure thlcgjvm.maybe_adjust_cmp_stackval(list: TAsmlist; size: tdef; cmp_op: topcmp);
+    procedure thlcgwasm.maybe_adjust_cmp_stackval(list: TAsmlist; size: tdef; cmp_op: topcmp);
       begin
         { use cmp_op because eventually that's what indicates the
           signed/unsigned character of the operation, not the size... }
@@ -869,7 +874,7 @@ implementation
         end;
       end;
 
-    function thlcgjvm.maybe_adjust_cmp_constval(size: tdef; cmp_op: topcmp; a: tcgint): tcgint;
+    function thlcgwasm.maybe_adjust_cmp_constval(size: tdef; cmp_op: topcmp; a: tcgint): tcgint;
       begin
         result:=a;
         { use cmp_op because eventually that's what indicates the
@@ -889,7 +894,7 @@ implementation
         end;
       end;
 
-    procedure thlcgjvm.maybe_adjust_op_result(list: TAsmList; op: TOpCg; size: tdef);
+    procedure thlcgwasm.maybe_adjust_op_result(list: TAsmList; op: TOpCg; size: tdef);
       const
         overflowops = [OP_MUL,OP_SHL,OP_ADD,OP_SUB,OP_NOT,OP_NEG];
       begin
@@ -899,7 +904,7 @@ implementation
           resize_stack_int_val(list,s32inttype,size,false);
       end;
 
-  procedure thlcgjvm.gen_load_uninitialized_function_result(list: TAsmList; pd: tprocdef; resdef: tdef; const resloc: tcgpara);
+  procedure thlcgwasm.gen_load_uninitialized_function_result(list: TAsmList; pd: tprocdef; resdef: tdef; const resloc: tcgpara);
     begin
       { constructors don't return anything in Java }
       if pd.proctypeoption=potype_constructor then
@@ -930,7 +935,7 @@ implementation
     end;
 
 
-  procedure thlcgjvm.g_copyvalueparas(p: TObject; arg: pointer);
+  procedure thlcgwasm.g_copyvalueparas(p: TObject; arg: pointer);
     var
       list: tasmlist;
       tmpref: treference;
@@ -962,13 +967,13 @@ implementation
     end;
 
 
-  procedure thlcgjvm.inittempvariables(list: TAsmList);
+  procedure thlcgwasm.inittempvariables(list: TAsmList);
     begin
       { these are automatically initialised when allocated if necessary }
     end;
 
 
-  function thlcgjvm.g_call_system_proc_intern(list: TAsmList; pd: tprocdef; const paras: array of pcgpara; forceresdef: tdef): tcgpara;
+  function thlcgwasm.g_call_system_proc_intern(list: TAsmList; pd: tprocdef; const paras: array of pcgpara; forceresdef: tdef): tcgpara;
     begin
       result:=inherited;
       pd.init_paraloc_info(callerside);
@@ -976,7 +981,7 @@ implementation
     end;
 
 
-  function thlcgjvm.prepare_stack_for_ref(list: TAsmList; const ref: treference; dup: boolean): longint;
+  function thlcgwasm.prepare_stack_for_ref(list: TAsmList; const ref: treference; dup: boolean): longint;
     var
       href: treference;
     begin
@@ -1070,13 +1075,13 @@ implementation
         end;
     end;
 
-  procedure thlcgjvm.a_load_const_reg(list: TAsmList; tosize: tdef; a: tcgint; register: tregister);
+  procedure thlcgwasm.a_load_const_reg(list: TAsmList; tosize: tdef; a: tcgint; register: tregister);
     begin
       a_load_const_stack(list,tosize,a,def2regtyp(tosize));
       a_load_stack_reg(list,tosize,register);
     end;
 
-  procedure thlcgjvm.a_load_const_ref(list: TAsmList; tosize: tdef; a: tcgint; const ref: treference);
+  procedure thlcgwasm.a_load_const_ref(list: TAsmList; tosize: tdef; a: tcgint; const ref: treference);
     var
       extra_slots: longint;
     begin
@@ -1085,7 +1090,7 @@ implementation
       a_load_stack_ref(list,tosize,ref,extra_slots);
     end;
 
-  procedure thlcgjvm.a_load_reg_ref(list: TAsmList; fromsize, tosize: tdef; register: tregister; const ref: treference);
+  procedure thlcgwasm.a_load_reg_ref(list: TAsmList; fromsize, tosize: tdef; register: tregister; const ref: treference);
     var
       extra_slots: longint;
     begin
@@ -1096,7 +1101,7 @@ implementation
       a_load_stack_ref(list,tosize,ref,extra_slots);
     end;
 
-  procedure thlcgjvm.a_load_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister);
+  procedure thlcgwasm.a_load_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister);
     begin
       a_load_reg_stack(list,fromsize,reg1);
       if def2regtyp(fromsize)=R_INTREGISTER then
@@ -1104,7 +1109,7 @@ implementation
       a_load_stack_reg(list,tosize,reg2);
     end;
 
-  procedure thlcgjvm.a_load_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; register: tregister);
+  procedure thlcgwasm.a_load_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; register: tregister);
     var
       extra_slots: longint;
     begin
@@ -1116,7 +1121,7 @@ implementation
       a_load_stack_reg(list,tosize,register);
     end;
 
-  procedure thlcgjvm.a_load_ref_ref(list: TAsmList; fromsize, tosize: tdef; const sref: treference; const dref: treference);
+  procedure thlcgwasm.a_load_ref_ref(list: TAsmList; fromsize, tosize: tdef; const sref: treference; const dref: treference);
     var
       extra_sslots,
       extra_dslots: longint;
@@ -1131,7 +1136,7 @@ implementation
       a_load_stack_ref(list,tosize,dref,extra_dslots);
     end;
 
-  procedure thlcgjvm.a_loadaddr_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; r: tregister);
+  procedure thlcgwasm.a_loadaddr_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; r: tregister);
     begin
       { only allowed for types that are not implicit pointers in Pascal (in
         that case, ref contains a pointer to the actual data and we simply
@@ -1141,19 +1146,19 @@ implementation
       a_load_ref_reg(list,java_jlobject,java_jlobject,ref,r);
     end;
 
-  procedure thlcgjvm.a_op_const_reg(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; reg: TRegister);
+  procedure thlcgwasm.a_op_const_reg(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; reg: TRegister);
     begin
       a_op_const_reg_reg(list,op,size,a,reg,reg);
     end;
 
-  procedure thlcgjvm.a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tdef; a: tcgint; src, dst: tregister);
+  procedure thlcgwasm.a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tdef; a: tcgint; src, dst: tregister);
     begin
       a_load_reg_stack(list,size,src);
       a_op_const_stack(list,op,size,a);
       a_load_stack_reg(list,size,dst);
     end;
 
-  procedure thlcgjvm.a_op_const_ref(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; const ref: TReference);
+  procedure thlcgwasm.a_op_const_ref(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; const ref: TReference);
     var
       extra_slots: longint;
     begin
@@ -1169,7 +1174,7 @@ implementation
       a_load_stack_ref(list,size,ref,extra_slots);
     end;
 
-  procedure thlcgjvm.a_op_ref_reg(list: TAsmList; Op: TOpCG; size: tdef; const ref: TReference; reg: TRegister);
+  procedure thlcgwasm.a_op_ref_reg(list: TAsmList; Op: TOpCG; size: tdef; const ref: TReference; reg: TRegister);
     begin
       if not(op in [OP_NOT,OP_NEG]) then
         a_load_reg_stack(list,size,reg);
@@ -1177,7 +1182,7 @@ implementation
       a_load_stack_reg(list,size,reg);
     end;
 
-  procedure thlcgjvm.a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tdef; src1, src2, dst: tregister);
+  procedure thlcgwasm.a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tdef; src1, src2, dst: tregister);
     begin
       if not(op in [OP_NOT,OP_NEG]) then
         a_load_reg_stack(list,size,src2);
@@ -1185,12 +1190,12 @@ implementation
       a_load_stack_reg(list,size,dst);
     end;
 
-  procedure thlcgjvm.a_op_reg_reg(list: TAsmList; Op: TOpCG; size: tdef; reg1, reg2: TRegister);
+  procedure thlcgwasm.a_op_reg_reg(list: TAsmList; Op: TOpCG; size: tdef; reg1, reg2: TRegister);
     begin
       a_op_reg_reg_reg(list,op,size,reg1,reg2,reg2);
     end;
 
-  procedure thlcgjvm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tdef; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation);
+  procedure thlcgwasm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tdef; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation);
     var
       tmpreg: tregister;
     begin
@@ -1204,7 +1209,7 @@ implementation
       a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,true,ovloc);
     end;
 
-  procedure thlcgjvm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tdef; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation);
+  procedure thlcgwasm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tdef; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation);
     var
       orgsrc1, orgsrc2: tregister;
       docheck: boolean;
@@ -1289,7 +1294,7 @@ implementation
         ovloc.loc:=LOC_VOID;
     end;
 
-  procedure thlcgjvm.a_cmp_const_ref_label(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; const ref: treference; l: tasmlabel);
+  procedure thlcgwasm.a_cmp_const_ref_label(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; const ref: treference; l: tasmlabel);
     begin
       if ref.base<>NR_EVAL_STACK_BASE then
         a_load_ref_stack(list,size,ref,prepare_stack_for_ref(list,ref,false));
@@ -1298,7 +1303,7 @@ implementation
       a_cmp_stack_label(list,size,cmp_op,l);
     end;
 
-  procedure thlcgjvm.a_cmp_const_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
+  procedure thlcgwasm.a_cmp_const_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
     begin
       a_load_reg_stack(list,size,reg);
       maybe_adjust_cmp_stackval(list,size,cmp_op);
@@ -1306,7 +1311,7 @@ implementation
       a_cmp_stack_label(list,size,cmp_op,l);
     end;
 
-  procedure thlcgjvm.a_cmp_ref_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; const ref: treference; reg: tregister; l: tasmlabel);
+  procedure thlcgwasm.a_cmp_ref_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; const ref: treference; reg: tregister; l: tasmlabel);
     begin
       a_load_reg_stack(list,size,reg);
       maybe_adjust_cmp_stackval(list,size,cmp_op);
@@ -1318,7 +1323,7 @@ implementation
       a_cmp_stack_label(list,size,cmp_op,l);
     end;
 
-  procedure thlcgjvm.a_cmp_reg_ref_label(list: TAsmList; size: tdef; cmp_op: topcmp; reg: tregister; const ref: treference; l: tasmlabel);
+  procedure thlcgwasm.a_cmp_reg_ref_label(list: TAsmList; size: tdef; cmp_op: topcmp; reg: tregister; const ref: treference; l: tasmlabel);
     begin
       if ref.base<>NR_EVAL_STACK_BASE then
         a_load_ref_stack(list,size,ref,prepare_stack_for_ref(list,ref,false));
@@ -1328,7 +1333,7 @@ implementation
       a_cmp_stack_label(list,size,cmp_op,l);
     end;
 
-  procedure thlcgjvm.a_cmp_reg_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel);
+  procedure thlcgwasm.a_cmp_reg_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel);
     begin
       a_load_reg_stack(list,size,reg2);
       maybe_adjust_cmp_stackval(list,size,cmp_op);
@@ -1337,12 +1342,12 @@ implementation
       a_cmp_stack_label(list,size,cmp_op,l);
     end;
 
-  procedure thlcgjvm.a_jmp_always(list: TAsmList; l: tasmlabel);
+  procedure thlcgwasm.a_jmp_always(list: TAsmList; l: tasmlabel);
     begin
       list.concat(taicpu.op_sym(a_goto,current_asmdata.RefAsmSymbol(l.name,AT_METADATA)));
     end;
 
-  procedure thlcgjvm.concatcopy_normal_array(list: TAsmList; size: tdef; const source, dest: treference);
+  procedure thlcgwasm.concatcopy_normal_array(list: TAsmList; size: tdef; const source, dest: treference);
     var
       procname: string;
       eledef: tdef;
@@ -1442,7 +1447,7 @@ implementation
        end;
     end;
 
-    procedure thlcgjvm.concatcopy_record(list: TAsmList; size: tdef; const source, dest: treference);
+    procedure thlcgwasm.concatcopy_record(list: TAsmList; size: tdef; const source, dest: treference);
       var
         srsym: tsym;
         pd: tprocdef;
@@ -1463,7 +1468,7 @@ implementation
       end;
 
 
-    procedure thlcgjvm.concatcopy_set(list: TAsmList; size: tdef; const source, dest: treference);
+    procedure thlcgwasm.concatcopy_set(list: TAsmList; size: tdef; const source, dest: treference);
       begin
         a_load_ref_stack(list,size,source,prepare_stack_for_ref(list,source,false));
         a_load_ref_stack(list,size,dest,prepare_stack_for_ref(list,dest,false));
@@ -1475,7 +1480,7 @@ implementation
       end;
 
 
-    procedure thlcgjvm.concatcopy_shortstring(list: TAsmList; size: tdef; const source, dest: treference);
+    procedure thlcgwasm.concatcopy_shortstring(list: TAsmList; size: tdef; const source, dest: treference);
       var
         srsym: tsym;
         pd: tprocdef;
@@ -1496,7 +1501,7 @@ implementation
       end;
 
 
-  procedure thlcgjvm.g_concatcopy(list: TAsmList; size: tdef; const source, dest: treference);
+  procedure thlcgwasm.g_concatcopy(list: TAsmList; size: tdef; const source, dest: treference);
     var
       handled: boolean;
     begin
@@ -1543,12 +1548,12 @@ implementation
         inherited;
     end;
 
-  procedure thlcgjvm.g_copyshortstring(list: TAsmList; const source, dest: treference; strdef: tstringdef);
+  procedure thlcgwasm.g_copyshortstring(list: TAsmList; const source, dest: treference; strdef: tstringdef);
     begin
       concatcopy_shortstring(list,strdef,source,dest);
     end;
 
-  procedure thlcgjvm.a_loadfpu_ref_ref(list: TAsmList; fromsize, tosize: tdef; const ref1, ref2: treference);
+  procedure thlcgwasm.a_loadfpu_ref_ref(list: TAsmList; fromsize, tosize: tdef; const ref1, ref2: treference);
     var
       dstack_slots: longint;
     begin
@@ -1558,14 +1563,14 @@ implementation
       a_load_stack_ref(list,tosize,ref2,dstack_slots);
     end;
 
-  procedure thlcgjvm.a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister);
+  procedure thlcgwasm.a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister);
     begin
       a_load_ref_stack(list,fromsize,ref,prepare_stack_for_ref(list,ref,false));
       resizestackfpuval(list,def_cgsize(fromsize),def_cgsize(tosize));
       a_load_stack_reg(list,tosize,reg);
     end;
 
-  procedure thlcgjvm.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tdef; reg: tregister; const ref: treference);
+  procedure thlcgwasm.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tdef; reg: tregister; const ref: treference);
     var
       dstack_slots: longint;
     begin
@@ -1575,14 +1580,14 @@ implementation
       a_load_stack_ref(list,tosize,ref,dstack_slots);
     end;
 
-  procedure thlcgjvm.a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister);
+  procedure thlcgwasm.a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister);
     begin
       a_load_reg_stack(list,fromsize,reg1);
       resizestackfpuval(list,def_cgsize(fromsize),def_cgsize(tosize));
       a_load_stack_reg(list,tosize,reg2);
     end;
 
-  procedure thlcgjvm.g_proc_entry(list: TAsmList; localsize: longint; nostackframe: boolean);
+  procedure thlcgwasm.g_proc_entry(list: TAsmList; localsize: longint; nostackframe: boolean);
     begin
       { the localsize is based on tg.lasttemp -> already in terms of stack
         slots rather than bytes }
@@ -1594,7 +1599,7 @@ implementation
       list.concat(tai_directive.Create(asd_jlimit,'stack '+tostr(fmaxevalstackheight)));
     end;
 
-  procedure thlcgjvm.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
+  procedure thlcgwasm.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
     var
       retdef: tdef;
       opc: tasmop;
@@ -1632,7 +1637,7 @@ implementation
       list.concat(taicpu.op_none(opc));
     end;
 
-  procedure thlcgjvm.gen_load_return_value(list: TAsmList);
+  procedure thlcgwasm.gen_load_return_value(list: TAsmList);
     begin
       { constructors don't return anything in the jvm }
       if current_procinfo.procdef.proctypeoption in [potype_constructor,potype_class_constructor] then
@@ -1640,7 +1645,7 @@ implementation
       inherited gen_load_return_value(list);
     end;
 
-  procedure thlcgjvm.record_generated_code_for_procdef(pd: tprocdef; code, data: TAsmList);
+  procedure thlcgwasm.record_generated_code_for_procdef(pd: tprocdef; code, data: TAsmList);
     begin
       { add something to the al_procedures list as well, because if all al_*
         lists are empty, the assembler writer isn't called }
@@ -1654,12 +1659,12 @@ implementation
         internalerror(2010122801);
     end;
 
-  procedure thlcgjvm.g_incrrefcount(list: TAsmList; t: tdef; const ref: treference);
+  procedure thlcgwasm.g_incrrefcount(list: TAsmList; t: tdef; const ref: treference);
     begin
       // do nothing
     end;
 
-  procedure thlcgjvm.g_array_rtti_helper(list: TAsmList; t: tdef; const ref: treference; const highloc: tlocation; const name: string);
+  procedure thlcgwasm.g_array_rtti_helper(list: TAsmList; t: tdef; const ref: treference; const highloc: tlocation; const name: string);
     var
       normaldim: longint;
       eleref: treference;
@@ -1711,7 +1716,7 @@ implementation
         internalerror(2011031901);
     end;
 
-  procedure thlcgjvm.g_initialize(list: TAsmList; t: tdef; const ref: treference);
+  procedure thlcgwasm.g_initialize(list: TAsmList; t: tdef; const ref: treference);
     var
       dummyloc: tlocation;
       sym: tsym;
@@ -1745,18 +1750,18 @@ implementation
         a_load_const_ref(list,t,0,ref);
     end;
 
-  procedure thlcgjvm.g_finalize(list: TAsmList; t: tdef; const ref: treference);
+  procedure thlcgwasm.g_finalize(list: TAsmList; t: tdef; const ref: treference);
     begin
       // do nothing
     end;
 
-  procedure thlcgjvm.g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef);
+  procedure thlcgwasm.g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef);
     begin
       { not possible, need the original operands }
       internalerror(2012102101);
     end;
 
-  procedure thlcgjvm.g_overflowCheck_loc(List: TAsmList; const Loc: TLocation; def: TDef; var ovloc: tlocation);
+  procedure thlcgwasm.g_overflowCheck_loc(List: TAsmList; const Loc: TLocation; def: TDef; var ovloc: tlocation);
     var
       hl : tasmlabel;
     begin
@@ -1768,7 +1773,7 @@ implementation
       a_label(list,hl);
     end;
 
-  procedure thlcgjvm.location_get_data_ref(list: TAsmList; def: tdef; const l: tlocation; var ref: treference; loadref: boolean; alignment: longint);
+  procedure thlcgwasm.location_get_data_ref(list: TAsmList; def: tdef; const l: tlocation; var ref: treference; loadref: boolean; alignment: longint);
     var
       tmploc: tlocation;
     begin
@@ -1836,12 +1841,12 @@ implementation
       end;
     end;
 
-  procedure thlcgjvm.maybe_change_load_node_reg(list: TAsmList; var n: tnode; reload: boolean);
+  procedure thlcgwasm.maybe_change_load_node_reg(list: TAsmList; var n: tnode; reload: boolean);
     begin
       { don't do anything, all registers become stack locations anyway }
     end;
 
-  procedure thlcgjvm.g_copyvaluepara_openarray(list: TAsmList; const ref: treference; const lenloc: tlocation; arrdef: tarraydef; destreg: tregister);
+  procedure thlcgwasm.g_copyvaluepara_openarray(list: TAsmList; const ref: treference; const lenloc: tlocation; arrdef: tarraydef; destreg: tregister);
     var
       localref: treference;
       arrloc: tlocation;
@@ -1863,12 +1868,12 @@ implementation
       a_load_ref_reg(list,java_jlobject,java_jlobject,localref,destreg);
     end;
 
-  procedure thlcgjvm.g_releasevaluepara_openarray(list: TAsmList; arrdef: tarraydef; const l: tlocation);
+  procedure thlcgwasm.g_releasevaluepara_openarray(list: TAsmList; arrdef: tarraydef; const l: tlocation);
     begin
       // do nothing, long live garbage collection!
     end;
 
-  procedure thlcgjvm.gen_initialize_code(list: TAsmList);
+  procedure thlcgwasm.gen_initialize_code(list: TAsmList);
     var
       ref: treference;
     begin
@@ -1894,77 +1899,77 @@ implementation
       end;
     end;
 
-  procedure thlcgjvm.gen_entry_code(list: TAsmList);
+  procedure thlcgwasm.gen_entry_code(list: TAsmList);
     begin
       list.concat(Tai_force_line.Create);
     end;
 
-  procedure thlcgjvm.gen_exit_code(list: TAsmList);
+  procedure thlcgwasm.gen_exit_code(list: TAsmList);
     begin
       { nothing }
     end;
 
-  procedure thlcgjvm.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tdef; src, dst: tregister);
+  procedure thlcgwasm.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tdef; src, dst: tregister);
     begin
       internalerror(2012090201);
     end;
 
-  procedure thlcgjvm.a_loadmm_loc_reg(list: TAsmList; fromsize, tosize: tdef; const loc: tlocation; const reg: tregister; shuffle: pmmshuffle);
+  procedure thlcgwasm.a_loadmm_loc_reg(list: TAsmList; fromsize, tosize: tdef; const loc: tlocation; const reg: tregister; shuffle: pmmshuffle);
     begin
       internalerror(2012090202);
     end;
 
-  procedure thlcgjvm.a_loadmm_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister; shuffle: pmmshuffle);
+  procedure thlcgwasm.a_loadmm_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister; shuffle: pmmshuffle);
     begin
       internalerror(2012060130);
     end;
 
-  procedure thlcgjvm.a_loadmm_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister; shuffle: pmmshuffle);
+  procedure thlcgwasm.a_loadmm_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister; shuffle: pmmshuffle);
     begin
       internalerror(2012060131);
     end;
 
-  procedure thlcgjvm.a_loadmm_reg_ref(list: TAsmList; fromsize, tosize: tdef; reg: tregister; const ref: treference; shuffle: pmmshuffle);
+  procedure thlcgwasm.a_loadmm_reg_ref(list: TAsmList; fromsize, tosize: tdef; reg: tregister; const ref: treference; shuffle: pmmshuffle);
     begin
       internalerror(2012060132);
     end;
 
-  procedure thlcgjvm.a_opmm_reg_reg(list: TAsmList; Op: TOpCG; size: tdef; src, dst: tregister; shuffle: pmmshuffle);
+  procedure thlcgwasm.a_opmm_reg_reg(list: TAsmList; Op: TOpCG; size: tdef; src, dst: tregister; shuffle: pmmshuffle);
     begin
       internalerror(2012060133);
     end;
 
-  procedure thlcgjvm.a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize: tdef; intreg, mmreg: tregister; shuffle: pmmshuffle);
+  procedure thlcgwasm.a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize: tdef; intreg, mmreg: tregister; shuffle: pmmshuffle);
     begin
       internalerror(2012060134);
     end;
 
-  procedure thlcgjvm.a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize: tdef; mmreg, intreg: tregister; shuffle: pmmshuffle);
+  procedure thlcgwasm.a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize: tdef; mmreg, intreg: tregister; shuffle: pmmshuffle);
     begin
       internalerror(2012060135);
     end;
 
-  procedure thlcgjvm.g_stackpointer_alloc(list: TAsmList; size: longint);
+  procedure thlcgwasm.g_stackpointer_alloc(list: TAsmList; size: longint);
     begin
       internalerror(2012090203);
     end;
 
-  procedure thlcgjvm.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
+  procedure thlcgwasm.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
     begin
       internalerror(2012090204);
     end;
 
-  procedure thlcgjvm.g_adjust_self_value(list: TAsmList; procdef: tprocdef; ioffset: aint);
+  procedure thlcgwasm.g_adjust_self_value(list: TAsmList; procdef: tprocdef; ioffset: aint);
     begin
       internalerror(2012090205);
     end;
 
-  procedure thlcgjvm.g_local_unwind(list: TAsmList; l: TAsmLabel);
+  procedure thlcgwasm.g_local_unwind(list: TAsmList; l: TAsmLabel);
     begin
       internalerror(2012090206);
     end;
 
-  procedure thlcgjvm.a_load_stack_reg(list: TAsmList; size: tdef; reg: tregister);
+  procedure thlcgwasm.a_load_stack_reg(list: TAsmList; size: tdef; reg: tregister);
     var
       opc: tasmop;
       finishandval: tcgint;
@@ -1977,7 +1982,7 @@ implementation
       decstack(list,1+ord(size.size>4));
     end;
 
-  procedure thlcgjvm.a_load_stack_ref(list: TAsmList; size: tdef; const ref: treference; extra_slots: longint);
+  procedure thlcgwasm.a_load_stack_ref(list: TAsmList; size: tdef; const ref: treference; extra_slots: longint);
     var
       opc: tasmop;
       finishandval: tcgint;
@@ -1996,7 +2001,7 @@ implementation
       decstack(list,1+ord(size.size>4)+extra_slots);
     end;
 
-  procedure thlcgjvm.a_load_reg_stack(list: TAsmList; size: tdef; reg: tregister);
+  procedure thlcgwasm.a_load_reg_stack(list: TAsmList; size: tdef; reg: tregister);
     var
       opc: tasmop;
       finishandval: tcgint;
@@ -2011,7 +2016,7 @@ implementation
         a_op_const_stack(list,OP_AND,size,finishandval);
     end;
 
-  procedure thlcgjvm.a_load_ref_stack(list: TAsmList; size: tdef; const ref: treference; extra_slots: longint);
+  procedure thlcgwasm.a_load_ref_stack(list: TAsmList; size: tdef; const ref: treference; extra_slots: longint);
     var
       opc: tasmop;
       finishandval: tcgint;
@@ -2034,7 +2039,7 @@ implementation
         gen_typecheck(list,a_checkcast,size);
     end;
 
-  function thlcgjvm.loadstoreopcref(def: tdef; isload: boolean; const ref: treference; out finishandval: tcgint): tasmop;
+  function thlcgwasm.loadstoreopcref(def: tdef; isload: boolean; const ref: treference; out finishandval: tcgint): tasmop;
     const
                      { isload  static }
       getputopc: array[boolean,boolean] of tasmop =
@@ -2065,7 +2070,7 @@ implementation
         result:=loadstoreopc(def,isload,ref.arrayreftype<>art_none,finishandval);
     end;
 
-  function thlcgjvm.loadstoreopc(def: tdef; isload, isarray: boolean; out finishandval: tcgint): tasmop;
+  function thlcgwasm.loadstoreopc(def: tdef; isload, isarray: boolean; out finishandval: tcgint): tasmop;
     var
       size: longint;
     begin
@@ -2182,7 +2187,7 @@ implementation
       end;
     end;
 
-  procedure thlcgjvm.resize_stack_int_val(list: TAsmList; fromsize, tosize: tdef; formemstore: boolean);
+  procedure thlcgwasm.resize_stack_int_val(list: TAsmList; fromsize, tosize: tdef; formemstore: boolean);
     var
       fromcgsize, tocgsize: tcgsize;
     begin
@@ -2260,7 +2265,7 @@ implementation
         end;
     end;
 
-    procedure thlcgjvm.maybe_resize_stack_para_val(list: TAsmList; retdef: tdef; callside: boolean);
+    procedure thlcgwasm.maybe_resize_stack_para_val(list: TAsmList; retdef: tdef; callside: boolean);
       var
         convsize: tdef;
       begin
@@ -2286,7 +2291,7 @@ implementation
       end;
 
 
-  procedure thlcgjvm.g_adjust_stack_after_call(list: TAsmList; pd: tabstractprocdef; paraheight: longint; forceresdef: tdef);
+  procedure thlcgwasm.g_adjust_stack_after_call(list: TAsmList; pd: tabstractprocdef; paraheight: longint; forceresdef: tdef);
     var
       totalremovesize: longint;
       realresdef: tdef;
@@ -2310,7 +2315,7 @@ implementation
     end;
 
 
-  procedure thlcgjvm.allocate_implicit_struct_with_base_ref(list: TAsmList; vs: tabstractvarsym; ref: treference);
+  procedure thlcgwasm.allocate_implicit_struct_with_base_ref(list: TAsmList; vs: tabstractvarsym; ref: treference);
     var
       tmpref: treference;
     begin
@@ -2324,7 +2329,7 @@ implementation
     end;
 
 
-  procedure thlcgjvm.allocate_enum_with_base_ref(list: TAsmList; vs: tabstractvarsym; const initref: treference; destbaseref: treference);
+  procedure thlcgwasm.allocate_enum_with_base_ref(list: TAsmList; vs: tabstractvarsym; const initref: treference; destbaseref: treference);
     begin
       destbaseref.symbol:=current_asmdata.RefAsmSymbol(vs.mangledname,AT_DATA);
       { only copy the reference, not the actual data }
@@ -2332,7 +2337,7 @@ implementation
     end;
 
 
-  function thlcgjvm.get_enum_init_val_ref(def: tdef; out ref: treference): boolean;
+  function thlcgwasm.get_enum_init_val_ref(def: tdef; out ref: treference): boolean;
     var
       sym: tstaticvarsym;
     begin
@@ -2346,7 +2351,7 @@ implementation
     end;
 
 
-  procedure thlcgjvm.allocate_implicit_structs_for_st_with_base_ref(list: TAsmList; st: tsymtable; const ref: treference; allocvartyp: tsymtyp);
+  procedure thlcgwasm.allocate_implicit_structs_for_st_with_base_ref(list: TAsmList; st: tsymtable; const ref: treference; allocvartyp: tsymtyp);
     var
       vs: tabstractvarsym;
       def: tdef;
@@ -2405,7 +2410,7 @@ implementation
         end;
     end;
 
-  procedure thlcgjvm.gen_initialize_fields_code(list: TAsmList);
+  procedure thlcgwasm.gen_initialize_fields_code(list: TAsmList);
     var
       sym: tsym;
       selfpara: tparavarsym;
@@ -2442,7 +2447,7 @@ implementation
       allocate_implicit_structs_for_st_with_base_ref(list,obj.symtable,ref,fieldvarsym);
     end;
 
-  procedure thlcgjvm.gen_typecheck(list: TAsmList; checkop: tasmop; checkdef: tdef);
+  procedure thlcgwasm.gen_typecheck(list: TAsmList; checkop: tasmop; checkdef: tdef);
     begin
       { replace special types with their equivalent class type }
       if (checkdef.typ=pointerdef) and
@@ -2478,7 +2483,7 @@ implementation
         }
     end;
 
-  procedure thlcgjvm.resizestackfpuval(list: TAsmList; fromsize, tosize: tcgsize);
+  procedure thlcgwasm.resizestackfpuval(list: TAsmList; fromsize, tosize: tcgsize);
     begin
       if (fromsize=OS_F32) and
          (tosize=OS_F64) then
@@ -2494,7 +2499,7 @@ implementation
         end;
     end;
 
-  procedure thlcgjvm.maybepreparedivu32(list: TAsmList; var op: topcg; size: tdef; out isdivu32: boolean);
+  procedure thlcgwasm.maybepreparedivu32(list: TAsmList; var op: topcg; size: tdef; out isdivu32: boolean);
     begin
       if (op=OP_DIV) and
          (def_cgsize(size)=OS_32) then
@@ -2509,7 +2514,7 @@ implementation
         isdivu32:=false;
     end;
 
-  function thlcgjvm.a_call_name_intern(list: TAsmList; pd: tprocdef; const s: TSymStr; forceresdef: tdef; inheritedcall: boolean): tcgpara;
+  function thlcgwasm.a_call_name_intern(list: TAsmList; pd: tprocdef; const s: TSymStr; forceresdef: tdef; inheritedcall: boolean): tcgpara;
     var
       opc: tasmop;
     begin
@@ -2577,11 +2582,11 @@ implementation
 
   procedure create_hlcodegen_cpu;
     begin
-      hlcg:=thlcgjvm.create;
+      hlcg:=thlcgwasm.create;
       create_codegen;
     end;
 
 begin
-  chlcgobj:=thlcgjvm;
+  chlcgobj:=thlcgwasm;
   create_hlcodegen:=@create_hlcodegen_cpu;
 end.

+ 85 - 0
compiler/wasm/itcpuwasm.pas

@@ -0,0 +1,85 @@
+{
+    Copyright (c) 2016 by Karoly Balogh
+
+    This unit contains the WebAssembly instruction tables
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit itcpuwasm;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      cpubase,cgbase;
+
+    const
+      wasm_op2str : array[tasmop] of string[31] = ( '<none>',
+        // control flow
+        'block', 'loop', 'br', 'br_if', 'br_table', 'if', 'else', 'end',
+        'return', 'unreachable',
+        // basic
+        'nop', 'drop', 'i32.const', 'i64.const', 'f32.const', 'f64.const',
+        'get_local', 'set_local', 'tee_local', 'get_global', 'set_global',
+        'select', 'call', 'call_indirect',
+        // integer
+        'i32.add', 'i64.add', 'i32.sub', 'i64.sub', 'i32.mul', 'i64.mul',
+        'i32.div_s', 'i64.div_s', 'i32.div_u', 'i64.div_u', 'i32.rem_s', 'i64.rem_s',
+        'i32.rem_u', 'i64.rem_u', 'i32.and', 'i64.and', 'i32.or', 'i64.or',
+        'i32.xor', 'i64.xor', 'i32.shl', 'i64.shl', 'i32.shr_s', 'i64.shr_s',
+        'i32.shr_u', 'i64.shr_u', 'i32.rotl', 'i64.rotl', 'i32.rotr', 'i64.rotr',
+        'i32.clz', 'i64.clz', 'i32.ctz', 'i64.ctz', 'i32.popcnt', 'i64.popcnt',
+        'i32.eqz', 'i64.eqz',
+        // floating point
+        'f32.add', 'f64.add', 'f32.sub', 'f64.sub', 'f32.mul', 'f64.mul',
+        'f32.div', 'f64.div', 'f32.sqrt', 'f64.sqrt', 'f32.min', 'f64.min',
+        'f32.max', 'f64.max', 'f32.ceil', 'f64.ceil', 'f32.floor', 'f64.floor',
+        'f32.trunc', 'f64.trunc', 'f32.nearest', 'f64.nearest', 'f32.abs', 'f64.abs',
+        'f32.neg', 'f64.neg', 'f32.copysign', 'f64.copysign',
+        // integer compare
+        'i32.eq', 'i64.eq', 'i32.ne', 'i64.ne', 'i32.lt_s', 'i64.lt_s',
+        'i32.lt_u', 'i64.lt_u', 'i32.le_s', 'i64.le_s', 'i32.le_u', 'i64.le_u',
+        'i32.gt_s', 'i64.gt_s', 'i32.gt_u', 'i64.gt_u', 'i32.ge_s', 'i64.ge_s',
+        'i32.ge_u', 'i64.ge_u',
+        // floating point compare
+        'f32.eq', 'f64.eq', 'f32.ne', 'f64.ne', 'f32.lt', 'f64.lt',
+        'f32.le', 'f64.le', 'f32.gt', 'f64.gt', 'f32.ge', 'f64.gt',
+        // conversion
+        'i32.wrap/i64', 'i64.extend_s/i32', 'i64.extend_u/i32',
+        'i32.trunc_s/f32', 'i32.trunc_s/f64', 'i64.trunc_s/f32', 'i64.trunc_s/f64',
+        'i32.trunc_u/f32', 'i32.trunc_u/f64', 'i64.trunc_u/f32', 'i64.trunc_u/f64',
+        'f32.demote/f64', 'f64.promote/f32',
+        'f32.convert_s/i32', 'f32.convert_s/i64', 'f64.convert_s/i32', 'f64.convert_s/i64',
+        'f32.convert_u/i32', 'f32.convert_u/i64', 'f64.convert_u/i32', 'f64.convert_u/i64',
+        'i32.reinterpret/f32', 'i64.reinterpret/f64', 'f32.reinterpret/i32', 'f64.reinterpret/i64',
+        // load/store
+        'i32.load', 'i64.load', 'f32.load', 'f64.load',
+        'i32.store', 'i64.store', 'f32.store', 'f64.store',
+        'i32.load8_s', 'i32.load16_s', 'i64.load8_s', 'i64.load16_s', 'i64.load32_s',
+        'i32.load8_u', 'i32.load16_u', 'i64.load8_u', 'i64.load16_u', 'i64.load32_u',
+        'i32.store8', 'i32.store16', 'i64.store8', 'i64.store16', 'i64.store32',
+        // additional memory
+        'grow_memory', 'current_memory'
+        ,'<none>','<none>','<none>','<none>','<none>','<none>','<none>','<none>','<none>','<none>'
+        ,'<none>','<none>','<none>','<none>','<none>','<none>','<none>','<none>','<none>','<none>'
+        ,'<none>','<none>','<none>','<none>','<none>','<none>','<none>','<none>','<none>','<none>'
+      );
+
+implementation
+
+end.

+ 46 - 46
compiler/wasm/rgcpu.pas

@@ -1,5 +1,5 @@
 {
-    Copyright (c) 2010 by Jonas Maebe
+    Copyright (c) 2019 by Dmitry Boyarintsev
 
     This unit implements the WebAssembly specific class for the register
     allocator
@@ -61,7 +61,7 @@ implementation
         l: longint;
         reg: tregister;
       begin
-        { jvm instructions never have more than one memory (virtual register)
+        { WebAssebly instructions never have more than one memory (virtual register)
           operand, so there is no danger of superregister conflicts }
         for l:=0 to instr.ops-1 do
           if instr.oper[l]^.typ=top_reg then
@@ -89,16 +89,16 @@ implementation
         end;
 
       function issimpleregstore(p: tai; var reg: tregister; doubleprecisionok: boolean): boolean;
-        const
-          simplestoressp = [a_astore,a_fstore,a_istore];
-          simplestoresdp = [a_dstore,a_lstore];
+        //const
+        //  simplestoressp = [a_astore,a_fstore,a_istore];
+        //  simplestoresdp = [a_dstore,a_lstore];
         begin
           result:=
             assigned(p) and
             (p.typ=ait_instruction) and
-            ((taicpu(p).opcode in simplestoressp) or
-             (doubleprecisionok and
-              (taicpu(p).opcode in simplestoresdp))) and
+            //((taicpu(p).opcode in simplestoressp) or
+            // (doubleprecisionok and
+            //  (taicpu(p).opcode in simplestoresdp))) and
             ((reg=NR_NO) or
              (taicpu(p).oper[0]^.typ=top_reg) and
              (taicpu(p).oper[0]^.reg=reg));
@@ -108,16 +108,16 @@ implementation
         end;
 
       function issimpleregload(p: tai; var reg: tregister; doubleprecisionok: boolean): boolean;
-        const
-          simpleloadssp = [a_aload,a_fload,a_iload];
-          simpleloadsdp = [a_dload,a_lload];
+        //const
+        //  simpleloadssp = [a_aload,a_fload,a_iload];
+        //  simpleloadsdp = [a_dload,a_lload];
         begin
           result:=
             assigned(p) and
             (p.typ=ait_instruction) and
-            ((taicpu(p).opcode in simpleloadssp) or
-             (doubleprecisionok and
-              (taicpu(p).opcode in simpleloadsdp))) and
+            //((taicpu(p).opcode in simpleloadssp) or
+            // (doubleprecisionok and
+            //  (taicpu(p).opcode in simpleloadsdp))) and
             ((reg=NR_NO) or
              (taicpu(p).oper[0]^.typ=top_reg) and
              (taicpu(p).oper[0]^.reg=reg));
@@ -182,7 +182,7 @@ implementation
               load regx
             and remove. We don't have to check that the load/store
             types match, because they have to for this to be
-            valid JVM code }
+            valid WebAssembly code }
           dealloc:=nextskipping(p,[ait_comment,ait_tempalloc]);
           load:=nextskipping(dealloc,[ait_comment,ait_tempalloc]);
           reg:=NR_NO;
@@ -234,37 +234,37 @@ implementation
            This will create opportunities to remove the store/load regx
            (and possibly also for regy)
          }
-         regx:=NR_NO;
-         regy:=NR_NO;
-         if not issimpleregstore(p,regx,false) then
-           exit;
-         storex:=p;
-         deallocy:=nextskipping(storex,[ait_comment,ait_tempalloc]);
-         loady:=nextskipping(deallocy,[ait_comment,ait_tempalloc]);
-         deallocx:=nextskipping(loady,[ait_comment,ait_tempalloc]);
-         loadx:=nextskipping(deallocx,[ait_comment,ait_tempalloc]);
-         if not assigned(loadx) then
-           exit;
-         if not issimpleregload(loady,regy,false) then
-           exit;
-         if not issimpleregload(loadx,regx,false) then
-           exit;
-         if not isregallocoftyp(deallocy,ra_dealloc,regy) then
-           exit;
-         if not isregallocoftyp(deallocx,ra_dealloc,regx) then
-           exit;
-         insertpos:=tai(p.previous);
-         if not assigned(insertpos) or
-            not isregallocoftyp(insertpos,ra_alloc,regx) then
-           insertpos:=storex;
-         list.remove(deallocy);
-         list.insertbefore(deallocy,insertpos);
-         list.remove(loady);
-         list.insertbefore(loady,insertpos);
-         swapxy:=taicpu.op_none(a_swap);
-         swapxy.fileinfo:=taicpu(loady).fileinfo;
-         list.insertbefore(swapxy,insertpos);
-         result:=true;
+         //regx:=NR_NO;
+         //regy:=NR_NO;
+         //if not issimpleregstore(p,regx,false) then
+         //  exit;
+         //storex:=p;
+         //deallocy:=nextskipping(storex,[ait_comment,ait_tempalloc]);
+         //loady:=nextskipping(deallocy,[ait_comment,ait_tempalloc]);
+         //deallocx:=nextskipping(loady,[ait_comment,ait_tempalloc]);
+         //loadx:=nextskipping(deallocx,[ait_comment,ait_tempalloc]);
+         //if not assigned(loadx) then
+         //  exit;
+         //if not issimpleregload(loady,regy,false) then
+         //  exit;
+         //if not issimpleregload(loadx,regx,false) then
+         //  exit;
+         //if not isregallocoftyp(deallocy,ra_dealloc,regy) then
+         //  exit;
+         //if not isregallocoftyp(deallocx,ra_dealloc,regx) then
+         //  exit;
+         //insertpos:=tai(p.previous);
+         //if not assigned(insertpos) or
+         //   not isregallocoftyp(insertpos,ra_alloc,regx) then
+         //  insertpos:=storex;
+         //list.remove(deallocy);
+         //list.insertbefore(deallocy,insertpos);
+         //list.remove(loady);
+         //list.insertbefore(loady,insertpos);
+         //swapxy:=taicpu.op_none(a_swap);
+         //swapxy.fileinfo:=taicpu(loady).fileinfo;
+         //list.insertbefore(swapxy,insertpos);
+         //result:=true;
        end;
 
 

+ 1 - 1
compiler/wasm/symcpu.pas

@@ -104,7 +104,7 @@ type
   tcpuprocvardefclass = class of tcpuprocvardef;
 
   tcpuprocdef = class(tprocdef)
-    { generated assembler code; used by JVM backend so it can afterwards
+    { generated assembler code; used by WebAssembly backend so it can afterwards
       easily write out all methods grouped per class }
     exprasmlist      : TAsmList;
     function  jvmmangledbasename(signature: boolean): TSymStr;

+ 271 - 0
compiler/wasm/tgcpu.pas

@@ -0,0 +1,271 @@
+{
+    Copyright (C) 2019 Dmitry Boyarintsev
+
+    This unit handles the temporary variables for the WebAssembly
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit tgcpu;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       globtype,
+       aasmdata,
+       cgutils,
+       symtype,tgobj;
+
+    type
+
+       { ttgjvm }
+
+       ttgwasm = class(ttgobj)
+        //protected
+        // procedure getimplicitobjtemp(list: TAsmList; def: tdef; temptype: ttemptype; out ref: treference);
+        // function getifspecialtemp(list: TAsmList; def: tdef; forcesize: asizeint; temptype: ttemptype; out ref: treference): boolean;
+        // procedure alloctemp(list: TAsmList; size: asizeint; alignment: shortint; temptype: ttemptype; def: tdef; fini: boolean; out ref: treference); override;
+        public
+         procedure setfirsttemp(l : asizeint); override;
+         //procedure getlocal(list: TAsmList; size: asizeint; alignment: shortint; def: tdef; var ref: treference); override;
+         //procedure gethltemp(list: TAsmList; def: tdef; forcesize: asizeint; temptype: ttemptype; out ref: treference); override;
+         //procedure gethltempmanaged(list: TAsmList; def: tdef; temptype: ttemptype; out ref: treference); override;
+       end;
+
+  implementation
+
+    uses
+       verbose,
+       cgbase,
+       symconst,symtable,symdef,symsym,symcpu,defutil,
+       cpubase,aasmbase,aasmcpu,
+       hlcgobj,hlcgcpu;
+
+
+    { ttgwasm }
+
+    //procedure ttgwasm.getimplicitobjtemp(list: TAsmList; def: tdef; temptype: ttemptype; out ref: treference);
+    //  var
+    //    sym: tsym;
+    //    pd: tprocdef;
+    //  begin
+    //    gettemp(list,java_jlobject.size,java_jlobject.alignment,temptype,ref);
+    //    list.concat(taicpu.op_sym(a_new,current_asmdata.RefAsmSymbol(tabstractrecorddef(def).jvm_full_typename(true),AT_METADATA)));
+    //    { the constructor doesn't return anything, so put a duplicate of the
+    //      self pointer on the evaluation stack for use as function result
+    //      after the constructor has run }
+    //    list.concat(taicpu.op_none(a_dup));
+    //    thlcgjvm(hlcg).incstack(list,2);
+    //    { call the constructor }
+    //    sym:=tsym(tabstractrecorddef(def).symtable.find('CREATE'));
+    //    if assigned(sym) and
+    //       (sym.typ=procsym) then
+    //      begin
+    //        pd:=tprocsym(sym).find_bytype_parameterless(potype_constructor);
+    //        if not assigned(pd) then
+    //          internalerror(2011032701);
+    //      end
+    //    else
+    //      internalerror(2011060301);
+    //    hlcg.a_call_name(list,pd,pd.mangledname,[],nil,false);
+    //    thlcgjvm(hlcg).decstack(list,1);
+    //    { store reference to instance }
+    //    thlcgjvm(hlcg).a_load_stack_ref(list,java_jlobject,ref,0);
+    //  end;
+
+
+    //function ttgwasm.getifspecialtemp(list: TAsmList; def: tdef; forcesize: asizeint; temptype: ttemptype; out ref: treference): boolean;
+    //  var
+    //    eledef: tdef;
+    //    ndim: longint;
+    //    sym: tsym;
+    //    pd: tprocdef;
+    //  begin
+    //    result:=false;
+    //    case def.typ of
+    //      arraydef:
+    //        begin
+    //          if not is_dynamic_array(def) then
+    //            begin
+    //              { allocate an array of the right size }
+    //              gettemp(list,java_jlobject.size,java_jlobject.alignment,temptype,ref);
+    //              ndim:=0;
+    //              eledef:=def;
+    //              repeat
+    //                if forcesize<>-1 then
+    //                  thlcgjvm(hlcg).a_load_const_stack(list,s32inttype,forcesize div tarraydef(eledef).elesize,R_INTREGISTER)
+    //                else
+    //                  thlcgjvm(hlcg).a_load_const_stack(list,s32inttype,tarraydef(eledef).elecount,R_INTREGISTER);
+    //                eledef:=tarraydef(eledef).elementdef;
+    //                inc(ndim);
+    //                forcesize:=-1;
+    //              until (eledef.typ<>arraydef) or
+    //                    is_dynamic_array(eledef);
+    //              eledef:=tarraydef(def).elementdef;
+    //              thlcgjvm(hlcg).g_newarray(list,def,ndim);
+    //              thlcgjvm(hlcg).a_load_stack_ref(list,java_jlobject,ref,0);
+    //              result:=true;
+    //            end;
+    //        end;
+    //      recorddef:
+    //        begin
+    //          getimplicitobjtemp(list,def,temptype,ref);
+    //          result:=true;
+    //        end;
+    //      setdef:
+    //        begin
+    //          if tsetdef(def).elementdef.typ=enumdef then
+    //            begin
+    //              { load enum class type }
+    //              list.concat(taicpu.op_sym(a_ldc,current_asmdata.RefAsmSymbol(tcpuenumdef(tenumdef(tsetdef(def).elementdef).getbasedef).classdef.jvm_full_typename(true),AT_METADATA)));
+    //              thlcgjvm(hlcg).incstack(current_asmdata.CurrAsmList,1);
+    //              { call tenumset.noneOf() class method }
+    //              sym:=tsym(tobjectdef(java_juenumset).symtable.find('NONEOF'));
+    //              if assigned(sym) and
+    //                 (sym.typ=procsym) then
+    //                begin
+    //                  if tprocsym(sym).procdeflist.Count<>1 then
+    //                    internalerror(2011062801);
+    //                  pd:=tprocdef(tprocsym(sym).procdeflist[0]);
+    //                  hlcg.a_call_name(list,pd,pd.mangledname,[],nil,false);
+    //                end;
+    //              { static calls method replaces parameter with set instance
+    //                -> no change in stack height }
+    //            end
+    //          else
+    //            begin
+    //              list.concat(taicpu.op_sym(a_new,current_asmdata.RefAsmSymbol(java_jubitset.jvm_full_typename(true),AT_METADATA)));
+    //              { the constructor doesn't return anything, so put a duplicate of the
+    //                self pointer on the evaluation stack for use as function result
+    //                after the constructor has run }
+    //              list.concat(taicpu.op_none(a_dup));
+    //              thlcgjvm(hlcg).incstack(list,2);
+    //              { call the constructor }
+    //              sym:=tsym(java_jubitset.symtable.find('CREATE'));
+    //              if assigned(sym) and
+    //                 (sym.typ=procsym) then
+    //                begin
+    //                  pd:=tprocsym(sym).find_bytype_parameterless(potype_constructor);
+    //                  if not assigned(pd) then
+    //                    internalerror(2011062802);
+    //                end
+    //              else
+    //                internalerror(2011062803);
+    //              hlcg.a_call_name(list,pd,pd.mangledname,[],nil,false);
+    //              { duplicate self pointer is removed }
+    //              thlcgjvm(hlcg).decstack(list,1);
+    //            end;
+    //          { store reference to instance }
+    //          gettemp(list,java_jlobject.size,java_jlobject.alignment,temptype,ref);
+    //          thlcgjvm(hlcg).a_load_stack_ref(list,java_jlobject,ref,0);
+    //          result:=true;
+    //        end;
+    //      procvardef:
+    //        begin
+    //          if not tprocvardef(def).is_addressonly then
+    //            begin
+    //              getimplicitobjtemp(list,tcpuprocvardef(def).classdef,temptype,ref);
+    //              result:=true;
+    //            end;
+    //        end;
+    //      stringdef:
+    //        begin
+    //          if is_shortstring(def) then
+    //            begin
+    //              gettemp(list,java_jlobject.size,java_jlobject.alignment,temptype,ref);
+    //              { add the maxlen parameter (s8inttype because parameters must
+    //                be sign extended) }
+    //              thlcgjvm(hlcg).a_load_const_stack(list,s8inttype,shortint(tstringdef(def).len),R_INTREGISTER);
+    //              { call the constructor }
+    //              sym:=tsym(tobjectdef(java_shortstring).symtable.find('CREATEEMPTY'));
+    //              if assigned(sym) and
+    //                 (sym.typ=procsym) then
+    //                begin
+    //                  if tprocsym(sym).procdeflist.Count<>1 then
+    //                    internalerror(2011052404);
+    //                  pd:=tprocdef(tprocsym(sym).procdeflist[0]);
+    //                  hlcg.a_call_name(list,pd,pd.mangledname,[],nil,false);
+    //                end;
+    //              { static calls method replaces parameter with string instance
+    //                -> no change in stack height }
+    //              { store reference to instance }
+    //              thlcgjvm(hlcg).a_load_stack_ref(list,java_jlobject,ref,0);
+    //              result:=true;
+    //            end;
+    //        end;
+    //      filedef:
+    //        begin
+    //          case tfiledef(def).filetyp of
+    //            ft_text:
+    //              result:=getifspecialtemp(list,search_system_type('TEXTREC').typedef,forcesize,temptype,ref);
+    //            ft_typed,
+    //            ft_untyped:
+    //              result:=getifspecialtemp(list,search_system_type('FILEREC').typedef,forcesize,temptype,ref);
+    //          end;
+    //        end;
+    //      else
+    //        ;
+    //    end;
+    //  end;
+
+
+    //procedure ttgjvm.alloctemp(list: TAsmList; size: asizeint; alignment: shortint; temptype: ttemptype; def: tdef; fini: boolean; out ref: treference);
+    //  begin
+    //    { the JVM only supports 1 slot (= 4 bytes in FPC) and 2 slot (= 8 bytes in
+    //      FPC) temps on the stack. double and int64 are 2 slots, the rest is one slot.
+    //      There are no problems with reusing the same slot for a value of a different
+    //      type. There are no alignment requirements either. }
+    //    if size<4 then
+    //      size:=4;
+    //    if not(size in [4,8]) then
+    //      internalerror(2010121401);
+    //    { don't pass on "def", since we don't care if a slot is used again for a
+    //      different type }
+    //    inherited alloctemp(list, size shr 2, 1, temptype, nil, false, ref);
+    //  end;
+
+
+    procedure ttgwasm.setfirsttemp(l: asizeint);
+      begin
+        firsttemp:=l;
+        lasttemp:=l;
+      end;
+
+
+    //procedure ttgwasm.getlocal(list: TAsmList; size: asizeint; alignment: shortint; def: tdef; var ref: treference);
+    //  begin
+    //    if not getifspecialtemp(list,def,size,tt_persistent,ref) then
+    //      inherited;
+    //  end;
+
+
+    //procedure ttgjvm.gethltemp(list: TAsmList; def: tdef; forcesize: asizeint; temptype: ttemptype; out ref: treference);
+    //  begin
+    //    if not getifspecialtemp(list,def,forcesize,temptype,ref) then
+    //      inherited;
+    //  end;
+    //
+    //procedure ttgjvm.gethltempmanaged(list: TAsmList; def: tdef; temptype: ttemptype; out ref: treference);
+    //  begin
+    //    gethltemp(list,def,def.size,temptype,ref);
+    //  end;
+
+
+begin
+  tgobjclass:=ttgwasm;
+end.